diff options
-rw-r--r-- | README.md | 1 | ||||
-rw-r--r-- | server.py | 1 | ||||
-rw-r--r-- | settings.py | 7 | ||||
-rw-r--r-- | youtube/__init__.py | 4 | ||||
-rw-r--r-- | youtube/static/js/hotkeys.js | 3 | ||||
-rw-r--r-- | youtube/static/js/sponsorblock.js | 40 | ||||
-rw-r--r-- | youtube/templates/watch.html | 16 | ||||
-rw-r--r-- | youtube/watch.py | 4 |
8 files changed, 68 insertions, 8 deletions
@@ -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 @@ -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, } diff --git a/settings.py b/settings.py index 159a896..e1cec13 100644 --- a/settings.py +++ b/settings.py @@ -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/__init__.py b/youtube/__init__.py index 61039d3..6d79e44 100644 --- a/youtube/__init__.py +++ b/youtube/__init__.py @@ -8,6 +8,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/hotkeys.js b/youtube/static/js/hotkeys.js index 5688ef3..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 = JSON.parse(Q(".video-info input[name=video_info_list]").value).id 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 new file mode 100644 index 0000000..dab4372 --- /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<b[h];d++){if(e=b.charCodeAt(d),e>>8)return;j[d>>2]|=e<<(3-d)%4*8}for(j[j[h]]=k/g|0,j[j[h]]=k,e=0;e<j[h];){var q=j.slice(e,e+=16),r=l;for(l=l.slice(0,8),d=0;64>d;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 hash = sha256(data.video_id).substr(0,4); + const video_obj = Q("video"); + let url = `/https://sponsor.ajay.app/api/skipSegments/${hash}`; + fetch(url) + .then(response => response.json()) + .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() + .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/watch.html b/youtube/templates/watch.html index 3542d94..b6faf21 100644 --- a/youtube/templates/watch.html +++ b/youtube/templates/watch.html @@ -482,6 +482,12 @@ Reload without invidious (for usage of new identity button).</a> <p>Used Invidious as fallback.</p> {% endif %} <p class="allowed-countries">Allowed countries: {{ allowed_countries|join(', ') }}</p> + + {% if settings.use_sponsorblock_js %} + <ul class="more-actions"> + <li><label><input type=checkbox id=skip_sponsors checked>skip sponsors</label> <span id=skip_n></span> + </ul> + {% endif %} </div> </details> </div> @@ -677,12 +683,10 @@ Reload without invidious (for usage of new identity button).</a> {% endif %} {% endif %} + <script> data = {{ js_data|tojson }} </script> <script src="/youtube.com/static/js/common.js"></script> <script src="/youtube.com/static/js/transcript-table.js"></script> - {% if settings.use_video_hotkeys %} - <script src="/youtube.com/static/js/hotkeys.js"></script> - {% endif %} - {% if settings.use_comments_js %} - <script src="/youtube.com/static/js/comments.js"></script> - {% endif %} + {% if settings.use_video_hotkeys %} <script src="/youtube.com/static/js/hotkeys.js"></script> {% endif %} + {% if settings.use_comments_js %} <script src="/youtube.com/static/js/comments.js"></script> {% endif %} + {% if settings.use_sponsorblock_js %} <script src="/youtube.com/static/js/sponsorblock.js"></script> {% endif %} {% endblock main %} diff --git a/youtube/watch.py b/youtube/watch.py index b1d4665..8ef9448 100644 --- a/youtube/watch.py +++ b/youtube/watch.py @@ -493,6 +493,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'], + } ) |