]> git.gir.st - subscriptionfeed.git/blob - app/youtube/templates/watch.html.j2
let all templates inherit from a base template
[subscriptionfeed.git] / app / youtube / templates / watch.html.j2
1 {% extends "base.html.j2" %}
2 {% import 'macros.imp.j2' as macros %}
3
4 {% block title %}{{ title | e }} — {{ author | e }}{% endblock %}
5
6 {% block content %}
7 {% if video_url %}
8 <div class="aspect-ratio main-video" style="--aspect-ratio:{{ aspectr }}">
9 <video controls poster="{{ poster }}">
10 <source src="{{ video_url }}">
11 {% set cc_default = False %}
12 {% for cc in subtitles %}
13 <track label="{{ cc.name }}" kind="subtitles" srclang="{{ cc.code }}" src="{{ url_for('youtube.timedtext') }}?{{ cc.query }}" {{ 'default' if cc_default and not loop.counter }}>
14 {% endfor %}
15 </video>
16
17 <script>
18 "use strict";
19 //todo: should only be done after user is made aware of video id getting sent to 3rd party (wait for k-anon)
20 //window.addEventListener("load", () => load_sponsorblock("{{ video_id }}"));
21 document.addEventListener('DOMContentLoaded', ()=>{ let check = document.querySelector("#skip_sponsors");
22 check.addEventListener("change", () => {if (check.checked) load_sponsorblock("{{ video_id }}")});});
23 function load_sponsorblock(video_id){
24 fetch(`https://sponsor.ajay.app/api/skipSegments?videoID=${video_id}`)
25 .then(response => response.json())
26 .then(data => {
27 for (const segment of data) {
28 const [start, stop] = segment.segment;
29 if (segment.category != "sponsor") continue;
30 document.querySelector('.main-video video')
31 .addEventListener("timeupdate", function() {
32 if (document.querySelector("#skip_sponsors").checked &&
33 this.currentTime >= start && this.currentTime < stop-1) {
34 this.currentTime = stop;
35 }
36 });
37 }
38 });
39 }
40 </script>
41
42 </div>
43 {% else %}{#TODO: this'll break livestreams #}
44 <img src="{{ poster }}" style="width:100%;object-fit:cover;height:calc(100% / {{ aspectr }});">
45 {% endif %}
46
47 {% if video_error %}
48 <div class="video_error">
49 {{ errdetails }} Watch on <a href="{{ invidious_url }}">Invidious</a> or <a href="https://www.youtube.com/watch?v={{ video_id }}">Youtube</a>
50 </div>
51 {% endif %}
52
53 <h1>{{ title | e }}<br>
54 <small><a href="/channel/{{ channel_id }}">{{ author | e }}</a></small></h1>
55
56 <details><summary>Description</summary>
57 <p style="white-space:pre-wrap">{{ description | e }}
58 <hr></details>
59
60 <details><summary>Metadata</summary>
61 <dl>
62 <dt>Duration
63 {% set h = length // (60*60) %}
64 {% set m = length // 60 % 60 %}
65 {% set s = length % 60 %}
66 <dd>{{ h~':' if h }}{{ '%02d' % m }}:{{ '%02d' % s }}
67 <dt>Views
68 <dd>{{ '{0:,}'.format(views | int)|replace(",","&hairsp;") }}
69 <dt>Published
70 <dd>{{ published.split('T')[0] }}
71 <dt>Rating
72 <dd>{{ rating | round(1) }}/5
73 <dt>Visibility
74 <dd>{{ 'unlisted' if unlisted else 'public' }}
75 {% if blacklisted|length == 0 %}
76 <dt>Available in
77 <dd>all regions
78 {% elif whitelisted|length == 0 %}
79 <dt>Blacklisted in
80 <dd>all regions
81 {% elif blacklisted|length > whitelisted|length %}
82 <dt>Available in
83 <dd>{{ whitelisted | join(', ') }}
84 {% else %}
85 <dt>Blacklisted in
86 <dd>{{ blacklisted | join(', ') }}
87 {% endif %}
88 </dl>
89 <hr></details>
90
91 <details><summary>More Actions</summary>
92 <ul class="more-actions">
93 <li><label><input type=checkbox id=skip_sponsors>skip sponsors</label>
94 {# TODO: make checked by default (need to inform the user about potential privacy concerns) #}
95 <noscript><br>Note: requires javascript</noscript>
96 {# TODO: don't redirect away (204 response?) #}
97 <li>{{ macros.emoji_button("pin", video_id, is_pinned, True) }}
98 <li>{{ macros.emoji_button("subscribe", channel_id, is_subscribed, True) }}
99 <li>{{ macros.emoji_link("raw", video_id, True) }}
100 <li>{{ macros.emoji_link("json", video_id, True) }}
101 <li><a href="https://invidio.us/watch?v={{ video_id }}">watch on invidious</a>
102 <li><a href="https://youtu.be/{{ video_id }}">watch on youtube</a>
103 </ul>
104 <hr></details>
105
106 <!-- not implemented warning:--><div style="background:red">{%for x in (infocards+endcards)|selectattr('content.error')%}{{x.content.error}}{%endfor%}</div>
107 <details><summary>Info- and Endcards</summary>
108 <div class="cards">
109 {% for card in all_cards %}
110 {% set c = card.content %}
111 {% if card.type == 'VIDEO' %}
112 {% call macros.card(c.video_id, c.title, c.length) %}
113 <span class=channel>{{ c.author }}&nbsp;</span>
114 {% endcall %}
115 {% elif card.type == 'CHANNEL' and c.channel_id != channel_id %}
116 {% call macros.card_generic("/channel/"~c.channel_id, c.icons[250] if 'icons' in c else '', c.title) %}
117 <span class=channel>Channel</span>
118 <span class=advanced></span>
119 {% endcall %}
120 {% elif card.type == 'PLAYLIST' %}
121 {% call macros.card_generic("/playlist?list="~c.playlist_id, "https://i.ytimg.com/vi/"~c.video_id~"/mqdefault.jpg", c.title) %}
122 <span class=channel>{{ c.author }}</span>
123 <span class=advanced>{{ c.n_videos }} videos</span>
124 {% endcall %}
125 {% elif card.type == 'WEBSITE' %}
126 {% call macros.card_generic(c.url, c.icons[250] if 'icons' in c else '', c.title) %}
127 <span class=channel>{{ c.domain }}</span>
128 {% endcall %}
129 {% endif %}
130 {% endfor %}
131 {{ macros.dummycard() }}
132 </div>
133 <hr></details>
134 {% endblock %}
Imprint / Impressum