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.

704 lines
23 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='&#9654;&#65039;') -%}
{# TODO do not hardcode certain extractors here #}
{% if element.extractor_name in ["ytdl", "youtube"] %}
{%- set opts = {
"video_uri": element.primary_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 = {
"&#x1f3e0; Home"|safe: "/",
"Latest Media": "/media",
"Short Media": "/media/short",
"Long Media": "/media/long",
"Unsorted": "/media/unsorted",
"Collections": "/collection",
"All Collections": "/collection/all",
"&#x1f4cc; 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", "&#x1f504;"|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 &#9989;"|safe, fragment) }}
{% elif element.ignored %}
{{ post_form(api_uri, "ignored", "false", "Unmark &#10062;"|safe, fragment) }}
{% else %}
{{ post_form(api_uri, "watched", "true", "&#9989;"|safe, fragment) }}
{{ post_form(api_uri, "ignored", "true", "&#10062;"|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='&#9655;') }}
{{ post_form(api_uri, "watched", "false", "&#9989;"|safe, fragment) }}
{% elif element.ignored %}
{{ as_play_link(element, symbol='&#9655;') }}
{{ post_form(api_uri, "ignored", "false", "&#10062;"|safe, fragment) }}
{% else %}
{{ post_form(api_uri, "watched", "true", "&#10003;"|safe, fragment) }}
{{ as_play_link(element, symbol='&#9655;') }}
{{ post_form(api_uri, "ignored", "true", "&#10005;"|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>&#9202;&#65039;</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>&#9202;&#65039;</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 %}
{% macro tag_list(tags) -%}
{%- for t in tags | sort(attribute="title") -%}
{%- if loop.index > 1 -%}
{{ " | " }}
{%- endif -%}
<a class="tag_item" href="{{ t.info_link }}"{% if t.notes %} title="{{ t.notes }}"{% endif %}>{{ t.title }}</a>
{%- endfor -%}
{%- endmacro %}
{% macro tag_table(tag_list) %}
<table>
<tr>
<th>Id</th>
<th>Title</th>
<th>Use for Pref.</th>
<th>Notes</th>
</tr>
{% for tag in tag_list %}
{{ tag_table_entry(tag) }}
{% endfor %}
</table>
{%- endmacro %}
{% macro tag_table_entry(tag) %}
{%- set api_uri = "/api/tag/" + tag.id|string -%}
{%- set fragment = "tag_" + tag.id|string -%}
<tr id="{{ fragment }}">
<td>
{{- tag.id -}}
</td>
<td>
<a href="{{ tag.info_link }}">
{{- tag.title -}}
</a>
</td>
<td>
{{ post_form(api_uri, "use_for_preferences", tag.use_for_preferences | tenary("false", "true"), tag.use_for_preferences | tenary("Yes", "no"), fragment) }}
</td>
<td>
{{- tag.notes or "" -}}
</td>
</tr>
{%- endmacro %}