diff --git a/.config/mpv/mpv.conf b/.config/mpv/mpv.conf new file mode 100644 index 0000000..fa1c522 --- /dev/null +++ b/.config/mpv/mpv.conf @@ -0,0 +1,3 @@ +volume=50 +sub-auto=fuzzy +hwdec=vaapi diff --git a/.config/mpv/scripts/autosub.lua b/.config/mpv/scripts/autosub.lua new file mode 100644 index 0000000..c800b7b --- /dev/null +++ b/.config/mpv/scripts/autosub.lua @@ -0,0 +1,260 @@ +--============================================================================= +-->> SUBLIMINAL PATH: +--============================================================================= +-- This script uses Subliminal to download subtitles, +-- so make sure to specify your system's Subliminal location below: +local subliminal = '/home/juan/.local/bin//subliminal' +--============================================================================= +-->> SUBTITLE LANGUAGE: +--============================================================================= +-- Specify languages in this order: +-- { 'language name', 'ISO-639-1', 'ISO-639-2' } ! +-- (See: https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) +local languages = { +-- If subtitles are found for the first language, +-- other languages will NOT be downloaded, +-- so put your preferred language first: + { 'English', 'en', 'eng' }, + { 'Chinese', 'zh', 'chi' }, + { 'Japanese', 'ja', 'jpn' }, +-- { 'Dutch', 'nl', 'dut' }, +-- { 'Spanish', 'es', 'spa' }, +-- { 'French', 'fr', 'fre' }, +-- { 'German', 'de', 'ger' }, +-- { 'Italian', 'it', 'ita' }, +-- { 'Portuguese', 'pt', 'por' }, +-- { 'Polish', 'pl', 'pol' }, +-- { 'Russian', 'ru', 'rus' }, +-- { 'Arabic', 'ar', 'ara' }, +} +--============================================================================= +-->> PROVIDER LOGINS: +--============================================================================= +-- These are completely optional and not required +-- for the functioning of the script! +-- If you use any of these services, simply uncomment it +-- and replace 'USERNAME' and 'PASSWORD' with your own: +local logins = { +-- { '--addic7ed', 'USERNAME', 'PASSWORD' }, +-- { '--legendastv', 'USERNAME', 'PASSWORD' }, +-- { '--opensubtitles', 'USERNAME', 'PASSWORD' }, +-- { '--subscenter', 'USERNAME', 'PASSWORD' }, +} +--============================================================================= +-->> ADDITIONAL OPTIONS: +--============================================================================= +local bools = { + auto = true, -- Automatically download subtitles, no hotkeys required + debug = false, -- Use `--debug` in subliminal command for debug output + force = true, -- Force download; will overwrite existing subtitle files + utf8 = true, -- Save all subtitle files as UTF-8 +} +local excludes = { + -- Movies with a path containing any of these strings/paths + -- will be excluded from auto-downloading subtitles. + -- Full paths are also allowed, e.g.: + -- '/home/david/Videos', + 'no-subs-dl', +} +local includes = { + -- If anything is defined here, only the movies with a path + -- containing any of these strings/paths will auto-download subtitles. + -- Full paths are also allowed, e.g.: + -- '/home/david/Videos', +} +--============================================================================= +local utils = require 'mp.utils' + + +-- Download function: download the best subtitles in most preferred language +function download_subs(language) + language = language or languages[1] + if #language == 0 then + log('No Language found\n') + return false + end + + log('Searching ' .. language[1] .. ' subtitles ...', 30) + + -- Build the `subliminal` command, starting with the executable: + local table = { args = { subliminal } } + local a = table.args + + for _, login in ipairs(logins) do + a[#a + 1] = login[1] + a[#a + 1] = login[2] + a[#a + 1] = login[3] + end + if bools.debug then + -- To see `--debug` output start MPV from the terminal! + a[#a + 1] = '--debug' + end + + a[#a + 1] = 'download' + if bools.force then + a[#a + 1] = '-f' + end + if bools.utf8 then + a[#a + 1] = '-e' + a[#a + 1] = 'utf-8' + end + + a[#a + 1] = '-l' + a[#a + 1] = language[2] + a[#a + 1] = '-d' + a[#a + 1] = directory + a[#a + 1] = filename --> Subliminal command ends with the movie filename. + + local result = utils.subprocess(table) + + if string.find(result.stdout, 'Downloaded 1 subtitle') then + -- When multiple external files are present, + -- always activate the most recently downloaded: + mp.set_property('slang', language[2]) + -- Subtitles are downloaded successfully, so rescan to activate them: + mp.commandv('rescan_external_files') + log(language[1] .. ' subtitles ready!') + return true + else + log('No ' .. language[1] .. ' subtitles found\n') + return false + end +end + +-- Manually download second language subs by pressing 'n': +function download_subs2() + download_subs(languages[2]) +end + +-- Control function: only download if necessary +function control_downloads() + -- Make MPV accept external subtitle files with language specifier: + mp.set_property('sub-auto', 'fuzzy') + -- Set subtitle language preference: + mp.set_property('slang', languages[1][2]) + mp.msg.warn('Reactivate external subtitle files:') + mp.commandv('rescan_external_files') + directory, filename = utils.split_path(mp.get_property('path')) + + if not autosub_allowed() then + return + end + + sub_tracks = {} + for _, track in ipairs(mp.get_property_native('track-list')) do + if track['type'] == 'sub' then + sub_tracks[#sub_tracks + 1] = track + end + end + if bools.debug then -- Log subtitle properties to terminal: + for _, track in ipairs(sub_tracks) do + mp.msg.warn('Subtitle track', track['id'], ':\n{') + for k, v in pairs(track) do + if type(v) == 'string' then v = '"' .. v .. '"' end + mp.msg.warn(' "' .. k .. '":', v) + end + mp.msg.warn('}\n') + end + end + + for _, language in ipairs(languages) do + if should_download_subs_in(language) then + if download_subs(language) then return end -- Download successful! + else return end -- No need to download! + end + log('No subtitles were found') +end + +-- Check if subtitles should be auto-downloaded: +function autosub_allowed() + local duration = tonumber(mp.get_property('duration')) + local active_format = mp.get_property('file-format') + + if not bools.auto then + mp.msg.warn('Automatic downloading disabled!') + return false + -- elseif duration < 900 then + -- mp.msg.warn('Video is less than 15 minutes\n' .. + -- '=> NOT auto-downloading subtitles') + -- return false + elseif directory:find('^http') then + mp.msg.warn('Automatic subtitle downloading is disabled for web streaming') + return false + elseif active_format:find('^cue') then + mp.msg.warn('Automatic subtitle downloading is disabled for cue files') + return false + else + local not_allowed = {'aiff', 'ape', 'flac', 'mp3', 'ogg', 'wav', 'wv', 'tta'} + + for _, file_format in pairs(not_allowed) do + if file_format == active_format then + mp.msg.warn('Automatic subtitle downloading is disabled for audio files') + return false + end + end + + for _, exclude in pairs(excludes) do + local escaped_exclude = exclude:gsub('%W','%%%0') + local excluded = directory:find(escaped_exclude) + + if excluded then + mp.msg.warn('This path is excluded from auto-downloading subs') + return false + end + end + + for i, include in ipairs(includes) do + local escaped_include = include:gsub('%W','%%%0') + local included = directory:find(escaped_include) + + if included then break + elseif i == #includes then + mp.msg.warn('This path is not included for auto-downloading subs') + return false + end + end + end + + return true +end + +-- Check if subtitles should be downloaded in this language: +function should_download_subs_in(language) + for i, track in ipairs(sub_tracks) do + local subtitles = track['external'] and + 'subtitle file' or 'embedded subtitles' + + if not track['lang'] and (track['external'] or not track['title']) + and i == #sub_tracks then + local status = track['selected'] and ' active' or ' present' + log('Unknown ' .. subtitles .. status) + mp.msg.warn('=> NOT downloading new subtitles') + return false -- Don't download if 'lang' key is absent + elseif track['lang'] == language[3] or track['lang'] == language[2] or + (track['title'] and track['title']:lower():find(language[3])) then + if not track['selected'] then + mp.set_property('sid', track['id']) + log('Enabled ' .. language[1] .. ' ' .. subtitles .. '!') + else + log(language[1] .. ' ' .. subtitles .. ' active') + end + mp.msg.warn('=> NOT downloading new subtitles') + return false -- The right subtitles are already present + end + end + mp.msg.warn('No ' .. language[1] .. ' subtitles were detected\n' .. + '=> Proceeding to download:') + return true +end + +-- Log function: log to both terminal and MPV OSD (On-Screen Display) +function log(string, secs) + secs = secs or 2.5 -- secs defaults to 2.5 when secs parameter is absent + mp.msg.warn(string) -- This logs to the terminal + mp.osd_message(string, secs) -- This logs to MPV screen +end + + +mp.add_key_binding('b', 'download_subs', download_subs) +mp.add_key_binding('n', 'download_subs2', download_subs2) +mp.register_event('file-loaded', control_downloads) diff --git a/.config/mpv/scripts/sponsorblock.lua b/.config/mpv/scripts/sponsorblock.lua new file mode 100644 index 0000000..55fb8ed --- /dev/null +++ b/.config/mpv/scripts/sponsorblock.lua @@ -0,0 +1,564 @@ +-- sponsorblock.lua +-- +-- This script skips sponsored segments of YouTube videos +-- using data from https://github.com/ajayyy/SponsorBlock + +local ON_WINDOWS = package.config:sub(1,1) ~= "/" + +local options = { + server_address = "https://sponsor.ajay.app", + + python_path = ON_WINDOWS and "python" or "python3", + + -- Categories to fetch + categories = "sponsor,intro,outro,interaction,selfpromo", + + -- Categories to skip automatically + skip_categories = "sponsor, selfpromo, interaction", + + -- If true, sponsored segments will only be skipped once + skip_once = true, + + -- Note that sponsored segments may ocasionally be inaccurate if this is turned off + -- see https://blog.ajay.app/voting-and-pseudo-randomness-or-sponsorblock-or-youtube-sponsorship-segment-blocker + local_database = true, + + -- Update database on first run, does nothing if local_database is false + auto_update = true, + + -- How long to wait between local database updates + -- Format: "X[d,h,m]", leave blank to update on every mpv run + auto_update_interval = "6h", + + -- User ID used to submit sponsored segments, leave blank for random + user_id = "", + + -- Name to display on the stats page https://sponsor.ajay.app/stats/ leave blank to keep current name + display_name = "", + + -- Tell the server when a skip happens + report_views = true, + + -- Auto upvote skipped sponsors + auto_upvote = false, + + -- Use sponsor times from server if they're more up to date than our local database + server_fallback = true, + + -- Create chapters at sponsor boundaries for OSC display and manual skipping + make_chapters = true, + + -- Minimum duration for sponsors (in seconds), segments under that threshold will be ignored + min_duration = 1, + + -- Fade audio for smoother transitions + audio_fade = false, + + -- Audio fade step, applied once every 100ms until cap is reached + audio_fade_step = 10, + + -- Audio fade cap + audio_fade_cap = 0, + + -- Fast forward through sponsors instead of skipping + fast_forward = false, + + -- Playback speed modifier when fast forwarding, applied once every second until cap is reached + fast_forward_increase = .2, + + -- Playback speed cap + fast_forward_cap = 2, + + -- Length of the sha256 prefix (3-32) when querying server, 0 to disable + sha256_length = 4, + + -- Pattern for video id in local files, ignored if blank + -- Recommended value for base youtube-dl is "-([%w-_]+)%.[mw][kpe][v4b]m?$" + local_pattern = "", + + -- Legacy option, use skip_categories instead + skip = true +} + +mp.options = require "mp.options" +mp.options.read_options(options, "sponsorblock") + +local legacy = mp.command_native_async == nil +if legacy then + options.local_database = false +end + +local utils = require "mp.utils" +scripts_dir = mp.find_config_file("scripts") + +local sponsorblock = utils.join_path(scripts_dir, "sponsorblock_shared/sponsorblock.py") +local uid_path = utils.join_path(scripts_dir, "sponsorblock_shared/sponsorblock.txt") +local database_file = options.local_database and utils.join_path(scripts_dir, "sponsorblock_shared/sponsorblock.db") or "" +local youtube_id = nil +local ranges = {} +local init = false +local segment = {a = 0, b = 0, progress = 0, first = true} +local retrying = false +local last_skip = {uuid = "", dir = nil} +local speed_timer = nil +local fade_timer = nil +local fade_dir = nil +local volume_before = mp.get_property_number("volume") +local categories = {} +local all_categories = {"sponsor", "intro", "outro", "interaction", "selfpromo", "music_offtopic"} +local chapter_cache = {} + +for category in string.gmatch(options.skip_categories, "([^,]+)") do + categories[category] = true +end + +function file_exists(name) + local f = io.open(name,"r") + if f ~= nil then io.close(f) return true else return false end +end + +function t_count(t) + local count = 0 + for _ in pairs(t) do count = count + 1 end + return count +end + +function time_sort(a, b) + if a.time == b.time then + return string.match(a.title, "segment end") + end + return a.time < b.time +end + +function parse_update_interval() + local s = options.auto_update_interval + if s == "" then return 0 end -- Interval Disabled + + local num, mod = s:match "^(%d+)([hdm])$" + + if num == nil or mod == nil then + mp.osd_message("[sponsorblock] auto_update_interval " .. s .. " is invalid", 5) + return nil + end + + local time_table = { + m = 60, + h = 60 * 60, + d = 60 * 60 * 24, + } + + return num * time_table[mod] +end + +function clean_chapters() + local chapters = mp.get_property_native("chapter-list") + local new_chapters = {} + for _, chapter in pairs(chapters) do + if chapter.title ~= "Preview segment start" and chapter.title ~= "Preview segment end" then + table.insert(new_chapters, chapter) + end + end + mp.set_property_native("chapter-list", new_chapters) +end + +function create_chapter(chapter_title, chapter_time) + local chapters = mp.get_property_native("chapter-list") + local duration = mp.get_property_native("duration") + table.insert(chapters, {title=chapter_title, time=(duration == nil or duration > chapter_time) and chapter_time or duration - .001}) + table.sort(chapters, time_sort) + mp.set_property_native("chapter-list", chapters) +end + +function process(uuid, t, new_ranges) + start_time = tonumber(string.match(t, "[^,]+")) + end_time = tonumber(string.sub(string.match(t, ",[^,]+"), 2)) + for o_uuid, o_t in pairs(ranges) do + if (start_time >= o_t.start_time and start_time <= o_t.end_time) or (o_t.start_time >= start_time and o_t.start_time <= end_time) then + new_ranges[o_uuid] = o_t + return + end + end + category = string.match(t, "[^,]+$") + if categories[category] and end_time - start_time >= options.min_duration then + new_ranges[uuid] = { + start_time = start_time, + end_time = end_time, + category = category, + skipped = false + } + end + if options.make_chapters and not chapter_cache[uuid] then + chapter_cache[uuid] = true + local category_title = (category:gsub("^%l", string.upper):gsub("_", " ")) + create_chapter(category_title .. " segment start (" .. string.sub(uuid, 1, 6) .. ")", start_time) + create_chapter(category_title .. " segment end (" .. string.sub(uuid, 1, 6) .. ")", end_time) + end +end + +function getranges(_, exists, db, more) + if type(exists) == "table" and exists["status"] == "1" then + if options.server_fallback then + mp.add_timeout(0, function() getranges(true, true, "") end) + else + return mp.osd_message("[sponsorblock] database update failed, gave up") + end + end + if db ~= "" and db ~= database_file then db = database_file end + if exists ~= true and not file_exists(db) then + if not retrying then + mp.osd_message("[sponsorblock] database update failed, retrying...") + retrying = true + end + return update() + end + if retrying then + mp.osd_message("[sponsorblock] database update succeeded") + retrying = false + end + local sponsors + local args = { + options.python_path, + sponsorblock, + "ranges", + db, + options.server_address, + youtube_id, + options.categories, + tostring(options.sha256_length) + } + if not legacy then + sponsors = mp.command_native({name = "subprocess", capture_stdout = true, playback_only = false, args = args}) + else + sponsors = utils.subprocess({args = args}) + end + mp.msg.debug("Got: " .. string.gsub(sponsors.stdout, "[\n\r]", "")) + if not string.match(sponsors.stdout, "^%s*(.*%S)") then return end + if string.match(sponsors.stdout, "error") then return getranges(true, true) end + local new_ranges = {} + local r_count = 0 + if more then r_count = -1 end + for t in string.gmatch(sponsors.stdout, "[^:%s]+") do + uuid = string.match(t, "([^,]+),[^,]+$") + if ranges[uuid] then + new_ranges[uuid] = ranges[uuid] + else + process(uuid, t, new_ranges) + end + r_count = r_count + 1 + end + local c_count = t_count(ranges) + if c_count == 0 or r_count >= c_count then + ranges = new_ranges + end +end + +function fast_forward() + if options.fast_forward and options.fast_forward == true then + speed_timer = nil + mp.set_property("speed", 1) + end + local last_speed = mp.get_property_number("speed") + local new_speed = math.min(last_speed + options.fast_forward_increase, options.fast_forward_cap) + if new_speed <= last_speed then return end + mp.set_property("speed", new_speed) +end + +function fade_audio(step) + local last_volume = mp.get_property_number("volume") + local new_volume = math.max(options.audio_fade_cap, math.min(last_volume + step, volume_before)) + if new_volume == last_volume then + if step >= 0 then fade_dir = nil end + if fade_timer ~= nil then fade_timer:kill() end + fade_timer = nil + return + end + mp.set_property("volume", new_volume) +end + +function skip_ads(name, pos) + if pos == nil then return end + local sponsor_ahead = false + for uuid, t in pairs(ranges) do + if (options.fast_forward == uuid or not options.skip_once or not t.skipped) and t.start_time <= pos and t.end_time > pos then + if options.fast_forward == uuid then return end + if options.fast_forward == false then + mp.osd_message("[sponsorblock] " .. t.category .. " skipped") + mp.set_property("time-pos", t.end_time) + else + mp.osd_message("[sponsorblock] skipping " .. t.category) + end + t.skipped = true + last_skip = {uuid = uuid, dir = nil} + if options.report_views or options.auto_upvote then + local args = { + options.python_path, + sponsorblock, + "stats", + database_file, + options.server_address, + youtube_id, + uuid, + options.report_views and "1" or "", + uid_path, + options.user_id, + options.auto_upvote and "1" or "" + } + if not legacy then + mp.command_native_async({name = "subprocess", playback_only = false, args = args}, function () end) + else + utils.subprocess_detached({args = args}) + end + end + if options.fast_forward ~= false then + options.fast_forward = uuid + if speed_timer ~= nil then speed_timer:kill() end + speed_timer = mp.add_periodic_timer(1, fast_forward) + end + return + elseif (not options.skip_once or not t.skipped) and t.start_time <= pos + 1 and t.end_time > pos + 1 then + sponsor_ahead = true + end + end + if options.audio_fade then + if sponsor_ahead then + if fade_dir ~= false then + if fade_dir == nil then volume_before = mp.get_property_number("volume") end + if fade_timer ~= nil then fade_timer:kill() end + fade_dir = false + fade_timer = mp.add_periodic_timer(.1, function() fade_audio(-options.audio_fade_step) end) + end + elseif fade_dir == false then + fade_dir = true + if fade_timer ~= nil then fade_timer:kill() end + fade_timer = mp.add_periodic_timer(.1, function() fade_audio(options.audio_fade_step) end) + end + end + if options.fast_forward and options.fast_forward ~= true then + options.fast_forward = true + speed_timer:kill() + speed_timer = nil + mp.set_property("speed", 1) + end +end + +function vote(dir) + if last_skip.uuid == "" then return mp.osd_message("[sponsorblock] no sponsors skipped, can't submit vote") end + local updown = dir == "1" and "up" or "down" + if last_skip.dir == dir then return mp.osd_message("[sponsorblock] " .. updown .. "vote already submitted") end + last_skip.dir = dir + local args = { + options.python_path, + sponsorblock, + "stats", + database_file, + options.server_address, + youtube_id, + last_skip.uuid, + "", + uid_path, + options.user_id, + dir + } + if not legacy then + mp.command_native_async({name = "subprocess", playback_only = false, args = args}, function () end) + else + utils.subprocess({args = args}) + end + mp.osd_message("[sponsorblock] " .. updown .. "vote submitted") +end + +function update() + mp.command_native_async({name = "subprocess", playback_only = false, args = { + options.python_path, + sponsorblock, + "update", + database_file, + options.server_address + }}, getranges) +end + +function file_loaded() + local initialized = init + ranges = {} + segment = {a = 0, b = 0, progress = 0, first = true} + last_skip = {uuid = "", dir = nil} + chapter_cache = {} + local video_path = mp.get_property("path", "") + mp.msg.debug("Path: " .. video_path) + local video_referer = string.match(mp.get_property("http-header-fields", ""), "Referer:([^,]+)") or "" + mp.msg.debug("Referer: " .. video_referer) + + local urls = { + "https?://youtu%.be/([%w-_]+).*", + "https?://w?w?w?%.?youtube%.com/v/([%w-_]+).*", + "/watch.*[?&]v=([%w-_]+).*", + "/embed/([%w-_]+).*" + } + youtube_id = nil + for i,url in ipairs(urls) do + youtube_id = youtube_id or string.match(video_path, url) or string.match(video_referer, url) + end + youtube_id = youtube_id or string.match(video_path, options.local_pattern) + + if not youtube_id or string.len(youtube_id) < 11 or (local_pattern and string.len(youtube_id) ~= 11) then return end + youtube_id = string.sub(youtube_id, 1, 11) + mp.msg.debug("Found YouTube ID: " .. youtube_id) + init = true + if not options.local_database then + getranges(true, true) + else + local exists = file_exists(database_file) + if exists and options.server_fallback then + getranges(true, true) + mp.add_timeout(0, function() getranges(true, true, "", true) end) + elseif exists then + getranges(true, true) + elseif options.server_fallback then + mp.add_timeout(0, function() getranges(true, true, "") end) + end + end + if initialized then return end + if options.skip then + mp.observe_property("time-pos", "native", skip_ads) + end + if options.display_name ~= "" then + local args = { + options.python_path, + sponsorblock, + "username", + database_file, + options.server_address, + youtube_id, + "", + "", + uid_path, + options.user_id, + options.display_name + } + if not legacy then + mp.command_native_async({name = "subprocess", playback_only = false, args = args}, function () end) + else + utils.subprocess_detached({args = args}) + end + end + if not options.local_database or (not options.auto_update and file_exists(database_file)) then return end + + if file_exists(database_file) then + local db_info = utils.file_info(database_file) + local cur_time = os.time(os.date("*t")) + local upd_interval = parse_update_interval() + if upd_interval == nil or os.difftime(cur_time, db_info.mtime) < upd_interval then return end + end + + update() +end + +function set_segment() + if not youtube_id then return end + local pos = mp.get_property_number("time-pos") + if pos == nil then return end + if segment.progress > 1 then + segment.progress = segment.progress - 2 + end + if segment.progress == 1 then + segment.progress = 0 + segment.b = pos + mp.osd_message("[sponsorblock] segment boundary B set, press again for boundary A", 3) + else + segment.progress = 1 + segment.a = pos + mp.osd_message("[sponsorblock] segment boundary A set, press again for boundary B", 3) + end + if options.make_chapters and not segment.first then + local start_time = math.min(segment.a, segment.b) + local end_time = math.max(segment.a, segment.b) + if end_time - start_time ~= 0 and end_time ~= 0 then + clean_chapters() + create_chapter("Preview segment start", start_time) + create_chapter("Preview segment end", end_time) + end + end + segment.first = false +end + +function select_category(selected) + for category in string.gmatch(options.categories, "([^,]+)") do + mp.remove_key_binding("select_category_"..category) + mp.remove_key_binding("kp_select_category_"..category) + end + submit_segment(selected) +end + +function submit_segment(category) + if not youtube_id then return end + local start_time = math.min(segment.a, segment.b) + local end_time = math.max(segment.a, segment.b) + if end_time - start_time == 0 or end_time == 0 then + mp.osd_message("[sponsorblock] empty segment, not submitting") + elseif segment.progress <= 1 then + segment.progress = segment.progress + 2 + local category_list = "" + for category_id, category in pairs(all_categories) do + local category_title = (category:gsub("^%l", string.upper):gsub("_", " ")) + category_list = category_list .. category_id .. ": " .. category_title .. "\n" + mp.add_forced_key_binding(tostring(category_id), "select_category_"..category, function() select_category(category) end) + mp.add_forced_key_binding("KP"..tostring(category_id), "kp_select_category_"..category, function() select_category(category) end) + end + mp.osd_message(string.format("[sponsorblock] press a number to select category for segment: %.2d:%.2d:%.2d to %.2d:%.2d:%.2d\n\n" .. category_list .. "\nyou can press Shift+G again for default (Sponsor) or hide this message with g", math.floor(start_time/(60*60)), math.floor(start_time/60%60), math.floor(start_time%60), math.floor(end_time/(60*60)), math.floor(end_time/60%60), math.floor(end_time%60)), 30) + else + mp.osd_message("[sponsorblock] submitting segment...", 30) + local submit + local args = { + options.python_path, + sponsorblock, + "submit", + database_file, + options.server_address, + youtube_id, + tostring(start_time), + tostring(end_time), + uid_path, + options.user_id, + category or "sponsor" + } + if not legacy then + submit = mp.command_native({name = "subprocess", capture_stdout = true, playback_only = false, args = args}) + else + submit = utils.subprocess({args = args}) + end + if string.match(submit.stdout, "success") then + segment = {a = 0, b = 0, progress = 0, first = true} + mp.osd_message("[sponsorblock] segment submitted") + if options.make_chapters then + clean_chapters() + create_chapter("Submitted segment start", start_time) + create_chapter("Submitted segment end", end_time) + end + elseif string.match(submit.stdout, "error") then + mp.osd_message("[sponsorblock] segment submission failed, server may be down. try again", 5) + elseif string.match(submit.stdout, "502") then + mp.osd_message("[sponsorblock] segment submission failed, server is down. try again", 5) + elseif string.match(submit.stdout, "400") then + mp.osd_message("[sponsorblock] segment submission failed, impossible inputs", 5) + segment = {a = 0, b = 0, progress = 0, first = true} + elseif string.match(submit.stdout, "429") then + mp.osd_message("[sponsorblock] segment submission failed, rate limited. try again", 5) + elseif string.match(submit.stdout, "409") then + mp.osd_message("[sponsorblock] segment already submitted", 3) + segment = {a = 0, b = 0, progress = 0, first = true} + else + mp.osd_message("[sponsorblock] segment submission failed", 5) + end + end +end + +mp.register_event("file-loaded", file_loaded) +mp.add_key_binding("g", "set_segment", set_segment) +mp.add_key_binding("G", "submit_segment", submit_segment) +mp.add_key_binding("h", "upvote_segment", function() return vote("1") end) +mp.add_key_binding("H", "downvote_segment", function() return vote("0") end) +-- Bindings below are for backwards compatibility and could be removed at any time +mp.add_key_binding(nil, "sponsorblock_set_segment", set_segment) +mp.add_key_binding(nil, "sponsorblock_submit_segment", submit_segment) +mp.add_key_binding(nil, "sponsorblock_upvote", function() return vote("1") end) +mp.add_key_binding(nil, "sponsorblock_downvote", function() return vote("0") end) diff --git a/.config/sway/config##hostname.T14s b/.config/sway/config##hostname.T14s index 329c4f3..7a3d9c2 100644 --- a/.config/sway/config##hostname.T14s +++ b/.config/sway/config##hostname.T14s @@ -54,7 +54,6 @@ bindsym XF86AudioMute exec amixer sset Master toggle | sed -En '/\[on\]/ s/.*\[( bindsym XF86MonBrightnessUp exec light -A 5 && light -G | cut -d'.' -f1 > $SWAYSOCK.wob bindsym XF86MonBrightnessDown exec light -U 5 && light -G | cut -d'.' -f1 > $SWAYSOCK.wob -bindsym XF86AudioPlay exec 'playerctl play' bindsym XF86AudioPause exec 'playerctl pause' binsdym XF86AudioStop exec 'playerctl stop' bindsym XF86AudioNext exec 'playerctl next'