Skip to content

Commit

Permalink
feat: sponsor blocking in youtube videos
Browse files Browse the repository at this point in the history
  • Loading branch information
noelsimbolon committed Jun 17, 2023
1 parent 3383530 commit ce744e3
Show file tree
Hide file tree
Showing 2 changed files with 148 additions and 0 deletions.
1 change: 1 addition & 0 deletions input.conf
Original file line number Diff line number Diff line change
Expand Up @@ -226,3 +226,4 @@ ctrl+B script-binding make_gif_with_subtitles # make the GIF using start a
ctrl+c script-binding copy-time # copy current timestamp to clipboard in HH:MM:SS.MS format (copy-time.lua)
ctrl+S script-binding toggle-seeker # toggle keyboard input to seek to inputted timestamp (seek-to.lua)
ctrl+v script-binding paste-timestamp # automatically seek to pasted timestamp from clipboard (seek-to.lua)
alt+b script-binding sponsorblock # toggle sponsorblock on/off (sponsorblock-minimal.lua)
147 changes: 147 additions & 0 deletions scripts/sponsorblock-minimal.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
-- sponsorblock-minimal.lua
-- source: https://codeberg.org/jouni/mpv_sponsorblock_minimal
--
-- This script skips sponsored segments of YouTube videos
-- using data from https://github.com/ajayyy/SponsorBlock

local opt = require 'mp.options'
local utils = require 'mp.utils'

local ON = false
local ranges = nil

local options = {
server = "https://sponsor.ajay.app/api/skipSegments",

-- Categories to fetch and skip
categories = '"sponsor"',

-- Set this to "true" to use sha256HashPrefix instead of videoID
hash = ""
}

opt.read_options(options)

function get_ranges(youtube_id, url)
local luacurl_available, cURL = pcall(require,'cURL')

local res = nil
if not(luacurl_available) then -- if Lua-cURL is not available on this system
local sponsors = mp.command_native{
name = "subprocess",
capture_stdout = true,
playback_only = false,
args = {"curl", "-L", "-s", "-g", url}
}
res = sponsors.stdout
else -- otherwise use Lua-cURL (binding to libcurl)
local buf={}
local c = cURL.easy_init()
c:setopt_followlocation(1)
c:setopt_url(url)
c:setopt_writefunction(function(chunk) table.insert(buf,chunk); return true; end)
c:perform()
res = table.concat(buf)
end

if res then
local json = utils.parse_json(res)
if type(json) == "table" then
if options.hash == "true" then
for _, i in pairs(json) do
if i.videoID == youtube_id then
return i.segments
end
end
else
return json
end
end
end

return nil
end

function skip_ads(name,pos)
if pos then
for _, i in pairs(ranges) do
v = i.segment[2]
if i.segment[1] <= pos and v > pos then
--this message may sometimes be wrong
--it only seems to be a visual thing though
mp.osd_message(("[sponsorblock] skipping forward %ds"):format(math.floor(v-mp.get_property("time-pos"))))
--need to do the +0.01 otherwise mpv will start spamming skip sometimes
--example: https://www.youtube.com/watch?v=4ypMJzeNooo
mp.set_property("time-pos",v+0.01)
return
end
end
end
end

function file_loaded()
local video_path = mp.get_property("path", "")
local video_referer = string.match(mp.get_property("http-header-fields", ""), "Referer:([^,]+)") or ""

local urls = {
"ytdl://youtu%.be/([%w-_]+).*",
"ytdl://w?w?w?%.?youtube%.com/v/([%w-_]+).*",
"https?://youtu%.be/([%w-_]+).*",
"https?://w?w?w?%.?youtube%.com/v/([%w-_]+).*",
"/watch.*[?&]v=([%w-_]+).*",
"/embed/([%w-_]+).*",
"^ytdl://([%w-_]+)$",
"-([%w-_]+)%."
}
local youtube_id = nil
local purl = mp.get_property("metadata/by-key/PURL", "")
for i,url in ipairs(urls) do
youtube_id = youtube_id or string.match(video_path, url) or string.match(video_referer, url) or string.match(purl, url)
if youtube_id then break end
end

if not youtube_id or string.len(youtube_id) < 11 then return end
youtube_id = string.sub(youtube_id, 1, 11)

local url = ""
if options.hash == "true" then
local sha = mp.command_native{
name = "subprocess",
capture_stdout = true,
args = {"sha256sum"},
stdin_data = youtube_id
}
url = ("%s/%s?categories=[%s]"):format(options.server, string.sub(sha.stdout, 0, 4), options.categories)
else
url = ("%s?videoID=%s&categories=[%s]"):format(options.server, youtube_id, options.categories)
end

ranges = get_ranges(youtube_id, url)
if ranges then
ON = true
mp.add_key_binding("b","sponsorblock",toggle)
mp.observe_property("time-pos", "native", skip_ads)
end
end

function end_file()
if not ON then return end
mp.unobserve_property(skip_ads)
ranges = nil
ON = false
end

function toggle()
if ON then
mp.unobserve_property(skip_ads)
mp.osd_message("[sponsorblock] off")
ON = false
else
mp.observe_property("time-pos", "native", skip_ads)
mp.osd_message("[sponsorblock] on")
ON = true
end
end

mp.register_event("file-loaded", file_loaded)
mp.register_event("end-file", end_file)

0 comments on commit ce744e3

Please sign in to comment.