From f7f2b9fa06fd2218179636c712e43f0c4d65bd9e Mon Sep 17 00:00:00 2001 From: zrose584 <57181548+zrose584@users.noreply.github.com> Date: Sat, 17 Oct 2020 19:51:41 +0200 Subject: add sponsorblock.js --- settings.py | 9 ++++++++- youtube/static/js/common.js | 4 ++++ youtube/static/js/hotkeys.js | 2 +- youtube/static/js/sponsorblock.js | 40 +++++++++++++++++++++++++++++++++++++++ youtube/templates/base.html | 4 +++- youtube/templates/watch.html | 15 +++++++++------ 6 files changed, 65 insertions(+), 9 deletions(-) create mode 100644 youtube/static/js/sponsorblock.js diff --git a/settings.py b/settings.py index dfab369..7417cc6 100644 --- a/settings.py +++ b/settings.py @@ -134,7 +134,7 @@ For security reasons, enabling this is not recommended.''', 'default': True, 'comment': '', }), - + ('use_comments_js', { 'label': 'Enable comments.js', 'type': bool, @@ -142,6 +142,13 @@ For security reasons, enabling this is not recommended.''', 'comment': '', }), + ('use_sponsorblock_js', { + 'label': 'Enable sponsorblock.js', + 'type': bool, + 'default': False, + 'comment': '', + }), + ('theme', { 'type': int, 'default': 0, diff --git a/youtube/static/js/common.js b/youtube/static/js/common.js index 2db4390..42fa41f 100644 --- a/youtube/static/js/common.js +++ b/youtube/static/js/common.js @@ -108,6 +108,10 @@ function copyTextToClipboard(text) { document.body.removeChild(textArea); } +function getVideoID() { + return JSON.parse(Q(".video-info input[name=video_info_list]").value).id +} + window.addEventListener('DOMContentLoaded', function() { cur_track_idx = getDefaultTranscriptTrackIdx(); diff --git a/youtube/static/js/hotkeys.js b/youtube/static/js/hotkeys.js index 5688ef3..1f41510 100644 --- a/youtube/static/js/hotkeys.js +++ b/youtube/static/js/hotkeys.js @@ -37,7 +37,7 @@ function onKeyDown(e) { else tt.mode = "showing"; } else if (c == "t") { - let video_id = JSON.parse(Q(".video-info input[name=video_info_list]").value).id + let video_id = getVideoID(); let ts = Math.floor(Q("video").currentTime); copyTextToClipboard(`https://youtu.be/${video_id}?t=${ts}`); } diff --git a/youtube/static/js/sponsorblock.js b/youtube/static/js/sponsorblock.js new file mode 100644 index 0000000..66dcf16 --- /dev/null +++ b/youtube/static/js/sponsorblock.js @@ -0,0 +1,40 @@ +"use strict"; + +// from: https://git.gir.st/subscriptionfeed.git/blob/59a590d:/app/youtube/templates/watch.html.j2#l28 + +var sha256=function a(b){function c(a,b){return a>>>b|a<<32-b}for(var d,e,f=Math.pow,g=f(2,32),h="length",i="",j=[],k=8*b[h],l=a.h=a.h||[],m=a.k=a.k||[],n=m[h],o={},p=2;64>n;p++)if(!o[p]){for(d=0;313>d;d+=p)o[d]=p;l[n]=f(p,.5)*g|0,m[n++]=f(p,1/3)*g|0}for(b+="\x80";b[h]%64-56;)b+="\x00";for(d=0;d>8)return;j[d>>2]|=e<<(3-d)%4*8}for(j[j[h]]=k/g|0,j[j[h]]=k,e=0;ed;d++){var s=q[d-15],t=q[d-2],u=l[0],v=l[4],w=l[7]+(c(v,6)^c(v,11)^c(v,25))+(v&l[5]^~v&l[6])+m[d]+(q[d]=16>d?q[d]:q[d-16]+(c(s,7)^c(s,18)^s>>>3)+q[d-7]+(c(t,17)^c(t,19)^t>>>10)|0),x=(c(u,2)^c(u,13)^c(u,22))+(u&l[1]^u&l[2]^l[1]&l[2]);l=[w+x|0].concat(l),l[4]=l[4]+w|0}for(d=0;8>d;d++)l[d]=l[d]+r[d]|0}for(d=0;8>d;d++)for(e=3;e+1;e--){var y=l[d]>>8*e&255;i+=(16>y?0:"")+y.toString(16)}return i}; /*https://geraintluff.github.io/sha256/sha256.min.js (public domain)*/ + +window.addEventListener("load", load_sponsorblock); +document.addEventListener('DOMContentLoaded', ()=>{ + const check = document.querySelector("#skip_sponsors"); + check.addEventListener("change", () => {if (check.checked) load_sponsorblock()}); +}); +function load_sponsorblock(){ + const info_elem = Q('#skip_n'); + if (info_elem.innerText.length) return; // already fetched + const video_id = getVideoID(); + const hash = sha256(video_id).substr(0,4); + const video_obj = Q("video"); + fetch(`https://sponsor.ajay.app/api/skipSegments/${hash}`) + .then(response => response.json()) + .then(data => { + for (const video of data) { + if (video.videoID != video_id) continue; + info_elem.innerText = `(${video.segments.length} segments)`; + const cat_n = video.segments.map(e=>e.category).sort() + .reduce((acc,e) => (acc[e]=(acc[e]||0)+1, acc), {}); + info_elem.title = Object.entries(cat_n).map(e=>e.join(': ')).join(', '); + for (const segment of video.segments) { + const [start, stop] = segment.segment; + if (segment.category != "sponsor") continue; + video_obj.addEventListener("timeupdate", function() { + if (Q("#skip_sponsors").checked && + this.currentTime >= start && + this.currentTime < stop-1) { + this.currentTime = stop; + } + }); + } + } + }); +} \ No newline at end of file diff --git a/youtube/templates/base.html b/youtube/templates/base.html index f325f86..df7bb99 100644 --- a/youtube/templates/base.html +++ b/youtube/templates/base.html @@ -4,7 +4,9 @@ {{ page_title }} + {{ "img-src https://*.googleusercontent.com https://*.ggpht.com https://*.ytimg.com;" if not settings.proxy_images else "" }} + {{ "" if not settings.use_sponsorblock_js else "connect-src 'self' https://sponsor.ajay.app;"|safe }}"> + diff --git a/youtube/templates/watch.html b/youtube/templates/watch.html index 86644ea..d89cc05 100644 --- a/youtube/templates/watch.html +++ b/youtube/templates/watch.html @@ -494,6 +494,12 @@ Reload without invidious (for usage of new identity button).

Used Invidious as fallback.

{% endif %}

Allowed countries: {{ allowed_countries|join(', ') }}

+ + {% if settings.use_sponsorblock_js %} + + {% endif %} @@ -691,10 +697,7 @@ Reload without invidious (for usage of new identity button). - {% if settings.use_video_hotkeys %} - - {% endif %} - {% if settings.use_comments_js %} - - {% endif %} + {% if settings.use_video_hotkeys %} {% endif %} + {% if settings.use_comments_js %} {% endif %} + {% if settings.use_sponsorblock_js %} {% endif %} {% endblock main %} -- cgit v1.2.3 From a8916b9308a4e2b7c1441a4d8d3c6d0b19c38fd2 Mon Sep 17 00:00:00 2001 From: zrose584 <57181548+zrose584@users.noreply.github.com> Date: Sun, 18 Oct 2020 17:58:16 +0200 Subject: proxy 'sponsor.ajay.app' --- server.py | 7 ++++--- youtube/__init__.py | 4 ++++ youtube/static/js/common.js | 4 ---- youtube/static/js/hotkeys.js | 3 +-- youtube/static/js/sponsorblock.js | 8 ++++---- youtube/templates/base.html | 5 +++-- youtube/templates/watch.html | 1 + youtube/watch.py | 4 ++++ 8 files changed, 21 insertions(+), 15 deletions(-) diff --git a/server.py b/server.py index acce420..319a140 100644 --- a/server.py +++ b/server.py @@ -66,7 +66,7 @@ def proxy_site(env, start_response, video=False): # such as 8192 lest that causes the socket library to limit the # TCP window size # Might need fine-tuning, since this gives us 4*65536 - # The tradeoff is that larger values (such as 6 seconds) only + # The tradeoff is that larger values (such as 6 seconds) only # allows video to buffer in those increments, meaning user must wait # until the entire chunk is downloaded before video starts playing content_part = response.read(32*8192) @@ -85,6 +85,7 @@ site_handlers = { 'ytimg.com': proxy_site, 'yt3.ggpht.com': proxy_site, 'lh3.googleusercontent.com': proxy_site, + 'sponsor.ajay.app': proxy_site, 'googlevideo.com': proxy_video, } @@ -95,9 +96,9 @@ def split_url(url): match = re.match(r'(?:https?://)?([\w-]+(?:\.[\w-]+)+?)(/.*|$)', url) if match is None: raise ValueError('Invalid or unsupported url: ' + url) - + return match.group(1), match.group(2) - + def error_code(code, start_response): diff --git a/youtube/__init__.py b/youtube/__init__.py index 3c271f1..92e1878 100644 --- a/youtube/__init__.py +++ b/youtube/__init__.py @@ -7,6 +7,10 @@ from sys import exc_info yt_app = flask.Flask(__name__) yt_app.config['TEMPLATES_AUTO_RELOAD'] = True yt_app.url_map.strict_slashes = False +# yt_app.jinja_env.trim_blocks = True +# yt_app.jinja_env.lstrip_blocks = True + + yt_app.add_url_rule('/settings', 'settings_page', settings.settings_page, methods=['POST', 'GET']) diff --git a/youtube/static/js/common.js b/youtube/static/js/common.js index 42fa41f..2db4390 100644 --- a/youtube/static/js/common.js +++ b/youtube/static/js/common.js @@ -108,10 +108,6 @@ function copyTextToClipboard(text) { document.body.removeChild(textArea); } -function getVideoID() { - return JSON.parse(Q(".video-info input[name=video_info_list]").value).id -} - window.addEventListener('DOMContentLoaded', function() { cur_track_idx = getDefaultTranscriptTrackIdx(); diff --git a/youtube/static/js/hotkeys.js b/youtube/static/js/hotkeys.js index 1f41510..e199f3b 100644 --- a/youtube/static/js/hotkeys.js +++ b/youtube/static/js/hotkeys.js @@ -37,9 +37,8 @@ function onKeyDown(e) { else tt.mode = "showing"; } else if (c == "t") { - let video_id = getVideoID(); let ts = Math.floor(Q("video").currentTime); - copyTextToClipboard(`https://youtu.be/${video_id}?t=${ts}`); + copyTextToClipboard(`https://youtu.be/${data.video_id}?t=${ts}`); } } diff --git a/youtube/static/js/sponsorblock.js b/youtube/static/js/sponsorblock.js index 66dcf16..692de9b 100644 --- a/youtube/static/js/sponsorblock.js +++ b/youtube/static/js/sponsorblock.js @@ -12,14 +12,14 @@ document.addEventListener('DOMContentLoaded', ()=>{ function load_sponsorblock(){ const info_elem = Q('#skip_n'); if (info_elem.innerText.length) return; // already fetched - const video_id = getVideoID(); - const hash = sha256(video_id).substr(0,4); + const hash = sha256(data.video_id).substr(0,4); const video_obj = Q("video"); - fetch(`https://sponsor.ajay.app/api/skipSegments/${hash}`) + let url = `/https://sponsor.ajay.app/api/skipSegments/${hash}`; + fetch(url) .then(response => response.json()) .then(data => { for (const video of data) { - if (video.videoID != video_id) continue; + if (video.videoID != data.video_id) continue; info_elem.innerText = `(${video.segments.length} segments)`; const cat_n = video.segments.map(e=>e.category).sort() .reduce((acc,e) => (acc[e]=(acc[e]||0)+1, acc), {}); diff --git a/youtube/templates/base.html b/youtube/templates/base.html index df7bb99..ef69960 100644 --- a/youtube/templates/base.html +++ b/youtube/templates/base.html @@ -4,8 +4,9 @@ {{ page_title }} + {% if not settings.proxy_images %} + img-src https://*.googleusercontent.com https://*.ggpht.com https://*.ytimg.com; + {% endif %} diff --git a/youtube/templates/watch.html b/youtube/templates/watch.html index d89cc05..319c314 100644 --- a/youtube/templates/watch.html +++ b/youtube/templates/watch.html @@ -695,6 +695,7 @@ Reload without invidious (for usage of new identity button). {% endif %} {% endif %} + {% if settings.use_video_hotkeys %} {% endif %} diff --git a/youtube/watch.py b/youtube/watch.py index 1a9e6c4..1fa952c 100644 --- a/youtube/watch.py +++ b/youtube/watch.py @@ -489,6 +489,10 @@ def get_watch_page(video_id=None): invidious_reload_button = info['invidious_reload_button'], video_url = util.URL_ORIGIN + '/watch?v=' + video_id, time_start = time_start, + + js_data = { + 'video_id': video_info['id'], + } ) -- cgit v1.2.3 From d86f521326a8341f3a7a5dc445b44a235cb29268 Mon Sep 17 00:00:00 2001 From: zrose584 <57181548+zrose584@users.noreply.github.com> Date: Sun, 18 Oct 2020 21:13:06 +0200 Subject: give credit to 'ajayyy/SponsorBlock' --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 2428ec6..17d92bd 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,7 @@ The Youtube API is not used, so no keys or anything are needed. It uses the same 1. Shown by default, with click to hide 2. Hidden by default, with click to show 3. Never shown +* Optionally skip sponsored segments using [SponsorBlock](https://github.com/ajayyy/SponsorBlock)'s API ## Planned features - [ ] Putting videos from subscriptions or local playlists into the related videos -- cgit v1.2.3 From 832524e421349e279d8ec06c89fef7f16dc46ae8 Mon Sep 17 00:00:00 2001 From: zrose584 <57181548+zrose584@users.noreply.github.com> Date: Wed, 21 Oct 2020 10:29:49 +0200 Subject: fix html --- youtube/templates/base.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/youtube/templates/base.html b/youtube/templates/base.html index ef69960..4fc48cf 100644 --- a/youtube/templates/base.html +++ b/youtube/templates/base.html @@ -6,7 +6,7 @@ -- cgit v1.2.3 From 3b5df36b0310b751fc25f8c0b7167c659c8259de Mon Sep 17 00:00:00 2001 From: zrose584 <57181548+zrose584@users.noreply.github.com> Date: Wed, 21 Oct 2020 10:29:57 +0200 Subject: fix sponserblock:js --- youtube/static/js/sponsorblock.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/youtube/static/js/sponsorblock.js b/youtube/static/js/sponsorblock.js index 692de9b..dab4372 100644 --- a/youtube/static/js/sponsorblock.js +++ b/youtube/static/js/sponsorblock.js @@ -17,8 +17,8 @@ function load_sponsorblock(){ let url = `/https://sponsor.ajay.app/api/skipSegments/${hash}`; fetch(url) .then(response => response.json()) - .then(data => { - for (const video of data) { + .then(r => { + for (const video of r) { if (video.videoID != data.video_id) continue; info_elem.innerText = `(${video.segments.length} segments)`; const cat_n = video.segments.map(e=>e.category).sort() -- cgit v1.2.3