You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
660 lines
22 KiB
HTML
660 lines
22 KiB
HTML
{% macro shared_style() %}
|
|
<script src="/static/scripts/jquery.min.js"></script>
|
|
<script src="/static/scripts/select.js"></script>
|
|
<link href="/static/stylesheets/reset.css" rel="stylesheet" />
|
|
<style>
|
|
body {
|
|
font-family: sans-serif;
|
|
font-size: 1rem;
|
|
background-color: #222222;
|
|
color: whitesmoke;
|
|
margin: .8rem;
|
|
margin-top: 0;
|
|
line-height: 1.24;
|
|
}
|
|
table tr th, table tr td {
|
|
margin: 0;
|
|
padding: .2em;
|
|
border: solid white 1px;
|
|
}
|
|
table tr:nth-child(even) {
|
|
background-color: #333333;
|
|
}
|
|
a:any-link {
|
|
text-decoration: none;
|
|
color: lightcyan;
|
|
}
|
|
h1, h2 {
|
|
margin: 1rem 0 .5rem;
|
|
}
|
|
ul {
|
|
margin: .5rem 0;
|
|
}
|
|
form.form-single-button {
|
|
display: inline-block;
|
|
}
|
|
button,
|
|
.button {
|
|
font-size: .92em;
|
|
margin: .2rem;
|
|
padding: .16rem .2rem;
|
|
background-color: rgb(153, 50, 204);
|
|
color: whitesmoke;
|
|
border-radius: .3rem;
|
|
border: none;
|
|
cursor: pointer;
|
|
word-break: keep-all;
|
|
white-space: nowrap;
|
|
}
|
|
button:disabled {
|
|
background-color: rgb(98, 67, 113);
|
|
color: gray;
|
|
cursor: default;
|
|
}
|
|
.button-list {
|
|
display: flex;
|
|
flex-direction: row;
|
|
justify-content: center;
|
|
align-items: center;
|
|
align-content: center;
|
|
}
|
|
@media screen and (max-width: 700px) {
|
|
.button-list {
|
|
flex-direction: column;
|
|
}
|
|
}
|
|
/* navigation */
|
|
.navigation {
|
|
position: sticky;
|
|
z-index: 1000;
|
|
top: 0;
|
|
|
|
display: flex;
|
|
flex-direction: row;
|
|
flex-wrap: wrap;
|
|
align-items: center;
|
|
align-content: center;
|
|
justify-content: center;
|
|
gap: .8rem;
|
|
--height: 2.4em;
|
|
width: max-content;
|
|
height: var(--height);
|
|
border-radius: 0 0 var(--height) var(--height);
|
|
margin: 0 auto;
|
|
padding: 1.2em 1.6em;
|
|
|
|
background-color: #333333;
|
|
box-shadow: 0 0 .2rem .4rem #444444;
|
|
|
|
font-size: 1.2rem;
|
|
}
|
|
/* sidebar box */
|
|
.sidebar-box {
|
|
display: flex;
|
|
position: sticky;
|
|
float: right;
|
|
margin: .5rem;
|
|
top: 1rem;
|
|
right: 1rem;
|
|
flex-direction: column;
|
|
gap: .4rem;
|
|
}
|
|
.sidebar-button {
|
|
font-size: 1.6rem;
|
|
min-width: 1.7rem;
|
|
writing-mode: vertical-rl;
|
|
text-align: center;
|
|
}
|
|
/* select view */
|
|
#select_view {
|
|
display: flex;
|
|
position: fixed;
|
|
right: 4rem;
|
|
bottom: 0;
|
|
padding: 1rem;
|
|
background-color: #333333;
|
|
border-radius: 1rem 1rem 0 0;
|
|
box-shadow: 0 0 .2rem .4rem #444444;
|
|
align-items: center;
|
|
gap: .4rem;
|
|
opacity: 0%;
|
|
visibility: hidden;
|
|
transition: opacity .1s linear, visibility .1s linear;
|
|
z-index: 200;
|
|
}
|
|
#select_view[to_display='true'] {
|
|
opacity: 100%;
|
|
visibility: visible;
|
|
}
|
|
#select_view > .text > * {
|
|
display: inline;
|
|
}
|
|
/* thumbnail view */
|
|
.thumbnail_img {
|
|
width: 100%;
|
|
aspect-ratio: 16 / 9;
|
|
}
|
|
.thumbnail_list {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fill, calc(240px * 1.2));
|
|
gap: 1rem;
|
|
justify-content: center;
|
|
}
|
|
.thumbnail_list::after {
|
|
content: "";
|
|
flex: auto;
|
|
}
|
|
.thumbnail_entry {
|
|
display: flex;
|
|
/*width: 240px;*/
|
|
flex-direction: column;
|
|
flex-wrap: nowrap;
|
|
align-items: stretch;
|
|
gap: .1rem;
|
|
}
|
|
.thumbnail_view {
|
|
display: block;
|
|
position: relative;
|
|
z-index: 0;
|
|
}
|
|
.thumbnail_view > * {
|
|
z-index: 30;
|
|
}
|
|
.thumbnail_view > .thumbnail_img {
|
|
display: block;
|
|
z-index: 10;
|
|
}
|
|
.thumbnail_view > .overlay {
|
|
display: block;
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
background-color:rgba(0, 0, 0, 0.7);
|
|
opacity: 0%;
|
|
transition: opacity .2s linear;
|
|
z-index: 20;
|
|
}
|
|
.thumbnail_view > .overlay.watched,
|
|
.thumbnail_view > .overlay.ignored,
|
|
.thumbnail_view > .overlay.not_considered {
|
|
opacity: 66%;
|
|
}
|
|
.thumbnail_view > .overlay.watched {
|
|
background-color: rgba(20, 117, 0, 0.7);
|
|
}
|
|
.thumbnail_view > .overlay.ignored {
|
|
background-color: rgba(117, 0, 0, 0.7);
|
|
}
|
|
.thumbnail_view > .overlay.not_considered {
|
|
background-color: rgba(34, 34, 34, 0.7);
|
|
}
|
|
.thumbnail_view > .button_list {
|
|
display: inline-flex;
|
|
flex-wrap: nowrap;
|
|
align-items: center;
|
|
align-content: center;
|
|
justify-content: center;
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
gap: 1rem;
|
|
opacity: 0%;
|
|
visibility: hidden;
|
|
transition: opacity .2s linear, visibility .2s linear;
|
|
}
|
|
.thumbnail_view:hover > .button_list,
|
|
.thumbnail_view:hover > .checkbox,
|
|
.thumbnail_view:hover > .overlay,
|
|
.thumbnail_view:active > .button_list,
|
|
.thumbnail_view:active > .checkbox,
|
|
.thumbnail_view:active > .overlay {
|
|
opacity: 100%;
|
|
visibility: visible;
|
|
}
|
|
.thumbnail_view > .button_list button,
|
|
.thumbnail_view > .button_list .button {
|
|
display: inline-block;
|
|
color: white;
|
|
font-size: 1.8em;
|
|
width: 2.4rem;
|
|
height: 2.4rem;
|
|
text-align: center;
|
|
vertical-align: middle;
|
|
margin: 0;
|
|
padding: .2rem;
|
|
border-radius: 100%;
|
|
background-color: rgba(0, 0, 0, 0.6);
|
|
}
|
|
.thumbnail_view > .button_list .play_button {
|
|
font-size: 2em;
|
|
width: 2.8rem;
|
|
height: 2.8rem;
|
|
}
|
|
.thumbnail_view > .additional_info,
|
|
.thumbnail_view > .checkbox,
|
|
.thumbnail_view > .episode_info,
|
|
.thumbnail_view > .length,
|
|
.thumbnail_view > .release_date {
|
|
display: block;
|
|
font-size: .8em;
|
|
position: absolute;
|
|
margin: .2rem;
|
|
z-index: 40;
|
|
}
|
|
.thumbnail_view > .episode_info,
|
|
.thumbnail_view > .length,
|
|
.thumbnail_view > .release_date {
|
|
padding: .2rem;
|
|
border-radius: .2rem;
|
|
--box-color: rgba(0, 0, 0, 0.7);
|
|
background-color: var(--box-color);
|
|
box-shadow: 0 0 .4rem .16rem var(--box-color);
|
|
}
|
|
.thumbnail_view > .episode_info {
|
|
top: 0;
|
|
left: 0;
|
|
}
|
|
.thumbnail_view > .episode_info[href] {
|
|
--box-color: rgba(153, 50, 204, .8);
|
|
}
|
|
.thumbnail_view > .additional_info,
|
|
.thumbnail_view > .checkbox {
|
|
top: 0;
|
|
right: 0;
|
|
}
|
|
.thumbnail_view > .checkbox {
|
|
opacity: 0%;
|
|
visibility: hidden;
|
|
transform: scale(1.4) translate(-20%, 20%);
|
|
transition: opacity .2s linear, visibility .2s linear;
|
|
}
|
|
.thumbnail_view:hover > .checkbox,
|
|
.thumbnail_view:active > .checkbox,
|
|
.thumbnail_view > .checkbox:checked {
|
|
opacity: 100%;
|
|
visibility: visible;
|
|
}
|
|
.thumbnail_view > .release_date {
|
|
left: 0;
|
|
bottom: 0;
|
|
}
|
|
.thumbnail_view > .length {
|
|
bottom: 0;
|
|
right: 0;
|
|
}
|
|
.thumbnail_view > .length.started {
|
|
--box-color: rgba(20, 117, 0, 0.6);
|
|
}
|
|
.thumbnail_title {
|
|
padding: .1rem;
|
|
white-space: normal;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
width: 100%;
|
|
max-height: calc(2em + (.24em * 2));
|
|
font-size: .9rem;
|
|
font-weight: 300;
|
|
}
|
|
/* Collection Table Listing */
|
|
.collection_table_list .thumbnail_img {
|
|
max-width: 140px;
|
|
}
|
|
/* media element */
|
|
.element_view {
|
|
display: flex;
|
|
flex-wrap: wrap-reverse;
|
|
justify-content: space-between;
|
|
align-items: flex-end;
|
|
}
|
|
.element_view > .thumbnail_img {
|
|
display: block;
|
|
margin: .4rem;
|
|
order: 90;
|
|
width: 420px;
|
|
max-width: 100%;
|
|
}
|
|
.element_view > .element_info {
|
|
display: block;
|
|
}
|
|
.element_view > .element_info > .description {
|
|
display: block;
|
|
font-size: .8rem;
|
|
max-width: 100%;
|
|
max-height: 16rem;
|
|
overflow-x: scroll;
|
|
overflow-y: scroll;
|
|
white-space: pre-wrap;
|
|
unicode-bidi: embed;
|
|
}
|
|
</style>
|
|
{% endmacro %}
|
|
|
|
{% macro hidden_redirect_back(fragment="") %}
|
|
<input type="hidden" name="redirect" value="{{ this_url() }}{{ ('#' + fragment) if fragment else '' }}"/>
|
|
{% endmacro %}
|
|
|
|
{% macro no_input_post_form(uri, text, fragment="") -%}
|
|
<form class="form-single-button" method="POST" action="{{ uri }}">
|
|
{{ hidden_redirect_back(fragment=fragment) }}
|
|
<button>{{ text }}</button>
|
|
</form>
|
|
{%- endmacro %}
|
|
|
|
{% macro post_form(uri, key, val, text, fragment="") %}
|
|
<form class="form-single-button" method="POST" action="{{ uri }}">
|
|
{{ hidden_redirect_back(fragment=fragment) }}
|
|
{% if caller is defined %}
|
|
{{ caller() }}
|
|
{% endif %}
|
|
<button name="{{ key }}" value="{{ val }}">{{ text }}</button>
|
|
</form>
|
|
{% endmacro %}
|
|
|
|
{% macro as_play_link(element, symbol='▶️') -%}
|
|
{# TODO do not hardcode certain extractors here #}
|
|
{% if element.extractor_name in ["ytdl", "youtube"] %}
|
|
{%- set opts = {
|
|
"video_uri": element.uri,
|
|
"start": element.progress,
|
|
} -%}
|
|
<a class="button play_button" href="entertainment-decider:///player/play?{{ opts | encode_options }}">{{ symbol | safe }}</a>
|
|
{% endif %}
|
|
{%- endmacro -%}
|
|
|
|
{% macro _navigation() %}
|
|
{% set links = {
|
|
"🏠 Home"|safe: "/",
|
|
"Latest Media": "/media",
|
|
"Short Media": "/media/short",
|
|
"Long Media": "/media/long",
|
|
"Unsorted": "/media/unsorted",
|
|
"Collections": "/collection",
|
|
"All Collections": "/collection/all",
|
|
"📌 Collections"|safe: "/collection/pinned",
|
|
"Collections To Watch": "/collection/to_watch",
|
|
"Statistics": "/stats",
|
|
"Tags": "/tag",
|
|
"Add Media": "/media/extract",
|
|
"Add Collection": "/collection/extract",
|
|
} %}
|
|
<div class="navigation">
|
|
{% for name, uri in links.items() %}
|
|
<a class="button" href="{{ uri }}">{{ name }}</a>
|
|
{% endfor %}
|
|
{{ no_input_post_form("/api/refresh/collections", "🔄"|safe) }}
|
|
</div>
|
|
{%- endmacro %}
|
|
|
|
{% macro _sidebar() %}
|
|
<div class="sidebar-box">
|
|
<a class="sidebar-button button" href="/recommendations/adaptive">Adaptive</a>
|
|
<a class="sidebar-button button" href="/recommendations/short_filler">Small Fillers</a>
|
|
<a class="sidebar-button button" href="/recommendations/series_episode">Series Episode</a>
|
|
<a class="sidebar-button button" href="/recommendations/movie_like">Movie Like</a>
|
|
</div>
|
|
{%- endmacro %}
|
|
|
|
{% macro _select_view() %}
|
|
<div id="select_view" to_display="false">
|
|
<div class="text">
|
|
<div class="counter">X</div> videos selected
|
|
</div>
|
|
<button id="select_button_watch" onclick="select_watch();">watched</button>
|
|
<button id="select_button_ignore" onclick="select_ignore();">ignored</button>
|
|
<button id="select_button_dependent" onclick="select_dependent();">make dependent</button>
|
|
<button id="select_button_" onclick="select_clear();">clear selection</button>
|
|
</div>
|
|
{%- endmacro %}
|
|
|
|
{% macro body_header() %}
|
|
{{ _navigation() }}
|
|
{{ _sidebar() }}
|
|
{{ _select_view() }}
|
|
{%- endmacro %}
|
|
|
|
{% macro media_element_buttons(element, show_fragment=True) %}
|
|
{% set api_uri = "/api/media/" + element.id|string %}
|
|
{% set fragment = ("media_element_" + element.id|string) if show_fragment else None %}
|
|
{{ as_play_link(element) }}
|
|
{% if element.watched %}
|
|
{{ post_form(api_uri, "watched", "false", "Unmark ✅"|safe, fragment) }}
|
|
{% elif element.ignored %}
|
|
{{ post_form(api_uri, "ignored", "false", "Unmark ❎"|safe, fragment) }}
|
|
{% else %}
|
|
{{ post_form(api_uri, "watched", "true", "✅"|safe, fragment) }}
|
|
{{ post_form(api_uri, "ignored", "true", "❎"|safe, fragment) }}
|
|
{% endif %}
|
|
{% endmacro %}
|
|
|
|
{% macro media_thumbnail_buttons(
|
|
element,
|
|
show_fragment=True,
|
|
show_rating=False
|
|
) %}
|
|
{% set api_uri = "/api/media/" + element.id|string %}
|
|
{% set fragment = ("media_element_" + element.id|string) if show_fragment else None %}
|
|
{% if element.watched %}
|
|
{{ as_play_link(element, symbol='▷') }}
|
|
{{ post_form(api_uri, "watched", "false", "✅"|safe, fragment) }}
|
|
{% elif element.ignored %}
|
|
{{ as_play_link(element, symbol='▷') }}
|
|
{{ post_form(api_uri, "ignored", "false", "❎"|safe, fragment) }}
|
|
{% else %}
|
|
{{ post_form(api_uri, "watched", "true", "✓"|safe, fragment) }}
|
|
{{ as_play_link(element, symbol='▷') }}
|
|
{{ post_form(api_uri, "ignored", "true", "✕"|safe, fragment) }}
|
|
{% endif %}
|
|
{% if show_rating %}
|
|
{{ post_form("/cookies/rating/positive", "media_id", element.id|string, "+", fragment) }}
|
|
{{ post_form("/cookies/rating/negative", "media_id", element.id|string, "-", fragment) }}
|
|
{% endif %}
|
|
{% endmacro %}
|
|
|
|
{% macro link_position_marker(link, prefix=false) -%}
|
|
{{- prefix and (link.season != 0 or link.episode != 0) | tenary(", ", "") -}}
|
|
{%- if link.season != 0 -%}
|
|
Season {{ link.season }}
|
|
{{- (link.episode != 0) | tenary(", ", "") -}}
|
|
{%- endif -%}
|
|
{%- if link.episode != 0 -%}
|
|
Episode {{ link.episode }}
|
|
{%- endif -%}
|
|
{%- endmacro %}
|
|
|
|
{% macro media_thumbnail_view(
|
|
element=None,
|
|
link=None,
|
|
check_considered=True,
|
|
is_considered=True,
|
|
link_collection=True,
|
|
show_rating=False,
|
|
title=None,
|
|
) %}
|
|
{% set element = link.element if link else element %}
|
|
<div class="thumbnail_entry" id="media_element_{{ element.id }}" title="{{ element.title }}">
|
|
<div class="thumbnail_view">
|
|
<img
|
|
class="thumbnail_img"
|
|
src="{{ element.info_link }}/thumbnail"
|
|
alt="Thumbnail for {{ element.title }}"
|
|
loading="lazy"
|
|
/>
|
|
{% if link == None %}
|
|
{% set link = element.detected_playlists | list | first_and_only %}
|
|
{% endif %}
|
|
{% if link and (link.season or link.episode) %}
|
|
<a
|
|
class="episode_info"
|
|
{% if link_collection -%}
|
|
href="{{ link.collection.info_link }}"
|
|
{%- endif -%}
|
|
>
|
|
{%- if link.season != 0 -%}
|
|
s{{ "%02d" % link.season }}
|
|
{%- endif -%}
|
|
{%- if link.episode != 0 -%}
|
|
e{{ "%02d" % link.episode }}
|
|
{%- endif -%}
|
|
</a>
|
|
{% endif %}
|
|
<div class="overlay
|
|
{%- if element.watched %} watched
|
|
{%- elif element.ignored %} ignored
|
|
{%- elif (
|
|
not check_considered and not is_considered
|
|
) or (
|
|
check_considered and not element.can_considered
|
|
) %} not_considered
|
|
{%- endif -%}
|
|
"></div>
|
|
<div class="button_list">
|
|
{{ media_thumbnail_buttons(element, show_rating=show_rating) }}
|
|
</div>
|
|
{% if caller is defined %}
|
|
<div class="additional_info">
|
|
{{ caller() }}
|
|
</div>
|
|
{% else %}
|
|
<input class="checkbox" type="checkbox" name="element_id" value="{{ element.id }}" onchange="select_onChange();" />
|
|
{% endif %}
|
|
<span class="release_date" title="{{ element.release_date.strftime('%d.%m.%Y') }}">
|
|
{{ element.release_date | time_since }}
|
|
</span>
|
|
<span class="length
|
|
{%- if element.started %} started
|
|
{%- endif -%}
|
|
">
|
|
{%- if element.started -%}
|
|
{{ element.left_length | timedelta }} ({{ element.length | timedelta }})
|
|
{%- else -%}
|
|
{{- element.length | timedelta -}}
|
|
{%- endif -%}
|
|
</span>
|
|
</div>
|
|
<a class="thumbnail_title" href="{{ element.info_link }}">
|
|
{{ title or element.title }}
|
|
</a>
|
|
</div>
|
|
{%- endmacro %}
|
|
|
|
{% macro media_thumbnail_list(
|
|
elements=None,
|
|
links=None,
|
|
check_considered=True,
|
|
link_collection=True,
|
|
show_rating=False,
|
|
titles=None,
|
|
) %}
|
|
{%- set l = elements or links -%}
|
|
{%- set considered = (links|map(attribute="element") if links else elements)|map(attribute="id")|are_considered -%}
|
|
<div class="thumbnail_list">
|
|
{% for o in l %}
|
|
{% set elem = o.element if links else o %}
|
|
{{ media_thumbnail_view(
|
|
element=o if not links else None,
|
|
link=o if links else None,
|
|
check_considered=False,
|
|
is_considered=considered[elem.id] if check_considered else True,
|
|
link_collection=link_collection,
|
|
show_rating=show_rating,
|
|
title=titles[loop.index0] if titles else None,
|
|
) }}
|
|
{% endfor %}
|
|
</div>
|
|
{%- endmacro %}
|
|
|
|
{% macro media_entry_content(element, show_fragment=True) %}
|
|
{{ media_element_buttons(element, show_fragment=show_fragment) }}
|
|
{{ element.release_date.strftime("%d.%m.%Y") }}
|
|
{{ element.length | timedelta }}
|
|
<a href="{{ element.info_link }}">{{ element.title }}</a>
|
|
{%- endmacro %}
|
|
|
|
{% macro link_entry_content(link, show_fragment=True) %}
|
|
{{ media_entry_content(link.element, show_fragment=show_fragment) -}}
|
|
{{- link_position_marker(link, prefix=true) -}}
|
|
{%- endmacro %}
|
|
|
|
{% macro collection_entry_content(collection) %}
|
|
<a href="{{ collection.info_link }}">{{ collection.title }}</a>
|
|
{%- endmacro %}
|
|
|
|
{% macro media_entry(element, show_fragment=True) %}
|
|
<li id="media_element_{{ element.id }}">
|
|
{{ media_entry_content(element, show_fragment=show_fragment) }}
|
|
</li>
|
|
{%- endmacro %}
|
|
|
|
{% macro link_entry(link, show_fragment=True) %}
|
|
<li id="media_element_{{ link.element.id }}">
|
|
{{ link_entry_content(link, show_fragment=show_fragment) }}
|
|
</li>
|
|
{%- endmacro %}
|
|
|
|
{% macro collection_entry(collection) %}
|
|
<li id="media_collection_{{ collection.id }}">
|
|
{{ collection_entry_content(collection, show_fragment=show_fragment) }}
|
|
</li>
|
|
{%- endmacro %}
|
|
|
|
{% macro media_table(media_list) %}
|
|
<table>
|
|
<tr>
|
|
<th>Date</th>
|
|
<th>⏲️</th>
|
|
<th></th>
|
|
<th>Title</th>
|
|
</tr>
|
|
{% for media in media_list %}
|
|
<tr>
|
|
<td>
|
|
{{- media.release_date.strftime("%d.%m.%Y") -}}
|
|
</td>
|
|
<td>
|
|
{{- media.left_length | timedelta -}}
|
|
</td>
|
|
<td class="button-list">
|
|
{{- media_element_buttons(media) -}}
|
|
</td>
|
|
<td><a href="{{ media.info_link }}">{{ media.title }}</a></td>
|
|
</tr>
|
|
{% endfor %}
|
|
</table>
|
|
{%- endmacro %}
|
|
|
|
{% macro link_differ_table(link_list) %}
|
|
<table>
|
|
<tr>
|
|
<th>Date</th>
|
|
<th>⏲️</th>
|
|
<th></th>
|
|
<th>Title</th>
|
|
<th>From Collection</th>
|
|
</tr>
|
|
{% for link in link_list %}
|
|
<tr>
|
|
<td>
|
|
{{- link.element.release_date.strftime("%d.%m.%Y") -}}
|
|
</td>
|
|
<td>
|
|
{{- link.element.left_length | timedelta -}}
|
|
</td>
|
|
<td class="button-list">
|
|
{{- media_element_buttons(link.element) -}}
|
|
</td>
|
|
<td>
|
|
<a href="{{ link.element.info_link }}">{{ link.element.title }}</a>
|
|
</td>
|
|
<td>
|
|
<a href="{{ link.collection.info_link }}">{{ link.collection.id }}</a>
|
|
{{- link_position_marker(link, prefix=true) -}}
|
|
</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</table>
|
|
{%- endmacro %}
|