mpv: Move into multimedia module
This commit is contained in:
parent
5a1c779a0d
commit
4c33a6da56
13 changed files with 7 additions and 1 deletions
50
multimedia/.config/mpv/input.conf
Normal file
50
multimedia/.config/mpv/input.conf
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
q quit
|
||||
|
||||
l seek 5
|
||||
L seek 60
|
||||
h seek -5
|
||||
H seek -60
|
||||
|
||||
p cycle pause # play/pause
|
||||
|
||||
J playlist-next
|
||||
K playlist-prev
|
||||
k add volume 5
|
||||
j add volume -5
|
||||
|
||||
+ add volume 2
|
||||
- add volume -2
|
||||
|
||||
a add speed 0.1
|
||||
A add speed -0.1
|
||||
|
||||
d add audio-delay 0.100 # for unsynched audio video
|
||||
D add audio-delay -0.100
|
||||
|
||||
u add sub-delay -0.1 # subtract 100 ms delay from subs
|
||||
U add sub-delay +0.1 # add
|
||||
|
||||
s cycle sub # choose subtitles
|
||||
S cycle sub down # choose subtitles (reverse)
|
||||
|
||||
f cycle fullscreen # toggle fullscreen
|
||||
|
||||
F5 async screenshot # take a screenshot
|
||||
Shift+F5 async screenshot video # screenshot without subtitles
|
||||
|
||||
i script-message playlistmanager show playlist toggle # toggle advanced playlist
|
||||
I script-message playlistmanager show filename
|
||||
R cycle-values video-aspect "16:9" "4:3" "3.25:1" "no" "-1" # cycle aspect ratios
|
||||
|
||||
# uosc definitions and menu
|
||||
o script-binding uosc/peek-timeline
|
||||
m script-binding uosc/menu
|
||||
|
||||
# script-binding uosc/open-file #! Open file
|
||||
# script-binding uosc/load-subtitles #! Load subtitles
|
||||
# script-binding uosc/subtitles #! Select subtitles
|
||||
# script-binding uosc/audio #! Select audio
|
||||
# async screenshot #! Utils > Screenshot
|
||||
# script-binding uosc/playlist #! Utils > Playlist
|
||||
# script-binding uosc/chapters #! Utils > Chapters
|
||||
# script-binding uosc/open-config-directory #! Utils > Open config directory
|
||||
156
multimedia/.config/mpv/mpv.conf
Normal file
156
multimedia/.config/mpv/mpv.conf
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
## mostly cobbled together from:
|
||||
## https://github.com/Tsubajashi/mpv-settings/blob/master/mpv.conf
|
||||
## https://github.com/haasn/gentoo-conf/blob/d3fd304fd7d8d816de6e280daf626b1b49a69893/home/nand/.mpv/config
|
||||
## with much gratitude
|
||||
|
||||
#### player settings
|
||||
|
||||
# do not open in fullscreen, do not create border
|
||||
fullscreen=no
|
||||
# if playing the last file in e.g. a playlist, simply pause after finishing
|
||||
keep-open=yes
|
||||
# allow remote operation through ipc, see https://mpv.io/manual/stable/#json-ipc
|
||||
input-ipc-server=/tmp/mpv-socket
|
||||
|
||||
# display a little seek bar in term
|
||||
term-osd-bar=yes
|
||||
# colorful term output
|
||||
msg-color=yes
|
||||
# add module names to term output
|
||||
msg-module=yes
|
||||
|
||||
### screenshots
|
||||
|
||||
screenshot-directory="${XDG_PICTURES_DIR:-~/media/pictures}/screenshots"
|
||||
# filename_HH-MM-SS
|
||||
screenshot-template="screen_%F_%wH-%wM-%wS"
|
||||
screenshot-format=png
|
||||
# default compression rate (0 is no compression)
|
||||
screenshot-png-compression=7
|
||||
screenshot-tag-colorspace=yes
|
||||
|
||||
### OSD
|
||||
|
||||
# 2 options necessary for uosc, see https://github.com/darsain/uosc
|
||||
osc=no
|
||||
osd-bar=no
|
||||
|
||||
osd-font='Iosevka Mono'
|
||||
osd-font-size=16
|
||||
|
||||
### Subtitles
|
||||
|
||||
## options and compatibility
|
||||
# vsfilter backward compatibility
|
||||
sub-ass-vsfilter-blur-compat=yes
|
||||
sub-ass-scale-with-window=no
|
||||
# custom ass style params
|
||||
sub-ass-force-style=Kerning=yes
|
||||
# fuzzy-search available subs in folder
|
||||
sub-auto=fuzzy
|
||||
# search for external subs in these relative subdirectories
|
||||
sub-file-paths-append=ass:srt:sub:subs:subtitles
|
||||
# make sure when seeking through mkv we try to display subs
|
||||
demuxer-mkv-subtitle-preroll=yes
|
||||
# use fonts embedded in the container if available
|
||||
embeddedfonts=yes
|
||||
# don't meddle with subtitle timing by default
|
||||
sub-fix-timing=no
|
||||
# do not blend subtitles, so that we can display them beyond the video borders
|
||||
blend-subtitles=no
|
||||
|
||||
## look and style
|
||||
sub-ass-override=scale
|
||||
sub-scale=0.5
|
||||
sub-font="Liberation Sans"
|
||||
sub-font-size=70
|
||||
# put them a bit above seekbar -- not necessary imo
|
||||
# sub-margin-y=50
|
||||
sub-color="#FFFFFFFF"
|
||||
sub-border-color="#FF151515"
|
||||
sub-border-size=6
|
||||
sub-shadow-offset=1
|
||||
sub-shadow-color="#33000000"
|
||||
sub-spacing=0.5
|
||||
|
||||
### Audio
|
||||
|
||||
volume=80
|
||||
volume-max=150
|
||||
# find audio files even if slightly mismatched
|
||||
audio-file-auto=fuzzy
|
||||
# playing at different speed will pitch-correct
|
||||
audio-pitch-correction=yes
|
||||
|
||||
### Video
|
||||
|
||||
hwdec=auto
|
||||
profile=opengl-hq
|
||||
opengl-early-flush=auto
|
||||
opengl-pbo=no
|
||||
# ever so slightly up saturation
|
||||
saturation=12
|
||||
# interpolation options, will take some more cpu
|
||||
interpolation=yes
|
||||
video-sync=display-resample
|
||||
|
||||
### Cache
|
||||
|
||||
# use cache if it seems like a networked connection
|
||||
cache=auto
|
||||
|
||||
### youtube-dl setup
|
||||
|
||||
ytdl=yes
|
||||
# never go beyond 1080p if it is avoidable
|
||||
ytdl-format=(bestvideo[vcodec=vp9.2][height<=1080]/bestvideo[vcodec=vp9][fps>30][height<=1080]/bestvideo[vcodec=vp9][height<=1080]/bestvideo[fps>30][height<=1080]/bestvideo[height>720])+(bestaudio[acodec=opus]/bestaudio)/best
|
||||
|
||||
### Languages
|
||||
|
||||
# prefer english subtitles, use german if you have to
|
||||
slang=en,eng,de,deu,ger
|
||||
# prefer original language, use dub if necessary
|
||||
alang=ja,jp,jpn,en,eng,de,deu,ger
|
||||
|
||||
### Protocol configuration
|
||||
|
||||
[network]
|
||||
# don't wait for buffering to be complete to show the window
|
||||
force-window=immediate
|
||||
cache=yes
|
||||
# create a huge cache to buffer most of videos
|
||||
demuxer-max-bytes=3000MiB
|
||||
demuxer-readahead-secs=500
|
||||
|
||||
[protocol.http]
|
||||
profile=network
|
||||
|
||||
[protocol.https]
|
||||
profile=network
|
||||
|
||||
[protocol.ytdl]
|
||||
profile=network
|
||||
|
||||
[extension.gif]
|
||||
interpolation=no
|
||||
loop-file=yes
|
||||
|
||||
# for those yt playlists that are created in reverse order
|
||||
[reverse]
|
||||
ytdl-raw-options=playlist-reverse=
|
||||
|
||||
[lowquality]
|
||||
scale=bilinear
|
||||
cscale=ewa_lanczossharp
|
||||
interpolation=no
|
||||
video-sync=audio
|
||||
|
||||
[highquality]
|
||||
scale=ewa_lanczossharp
|
||||
cscale=ewa_lanczossharp
|
||||
video-sync=display-resample
|
||||
interpolation=yes
|
||||
tscale=oversample
|
||||
|
||||
# default to hq
|
||||
profile=highquality
|
||||
23
multimedia/.config/mpv/script-opts/playlistmanager.conf
Normal file
23
multimedia/.config/mpv/script-opts/playlistmanager.conf
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
|
||||
#navigation keybindings force override only while playlist is visible
|
||||
#if "no" then you can display the playlist by any of the navigation keys
|
||||
dynamic_binds=yes
|
||||
|
||||
#dynamic keybind keys, they should not be re-bound in input.conf
|
||||
#to bind multiple keys separate them by a space
|
||||
key_moveup=UP
|
||||
key_movedown=DOWN
|
||||
key_selectfile=RIGHT LEFT
|
||||
key_unselectfile=
|
||||
key_playfile=ENTER
|
||||
key_removefile=BS
|
||||
key_closeplaylist=ESC
|
||||
|
||||
#Use ~ for home directory. Leave as empty to use mpv/playlists
|
||||
playlist_savepath=~/.local/share/mpv/playlists
|
||||
|
||||
#2 shows playlist, 1 shows current file(filename strip applied), 0 shows nothing
|
||||
show_playlist_on_fileload=1
|
||||
|
||||
#call youtube-dl to resolve the titles of urls in the playlist
|
||||
resolve_titles=yes
|
||||
2
multimedia/.config/mpv/script-opts/uosc.conf
Normal file
2
multimedia/.config/mpv/script-opts/uosc.conf
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
timeline_size_max=20
|
||||
timeline_size_min=1
|
||||
2
multimedia/.config/mpv/script-opts/ytdl_hook.conf
Normal file
2
multimedia/.config/mpv/script-opts/ytdl_hook.conf
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
# use fork instead
|
||||
ytdl_path=yt-dlp
|
||||
220
multimedia/.config/mpv/scripts/autoload.lua
Normal file
220
multimedia/.config/mpv/scripts/autoload.lua
Normal file
|
|
@ -0,0 +1,220 @@
|
|||
-- This script automatically loads playlist entries before and after the
|
||||
-- the currently played file. It does so by scanning the directory a file is
|
||||
-- located in when starting playback. It sorts the directory entries
|
||||
-- alphabetically, and adds entries before and after the current file to
|
||||
-- the internal playlist. (It stops if it would add an already existing
|
||||
-- playlist entry at the same position - this makes it "stable".)
|
||||
-- Add at most 5000 * 2 files when starting a file (before + after).
|
||||
|
||||
--[[
|
||||
To configure this script use file autoload.conf in directory script-opts (the "script-opts"
|
||||
directory must be in the mpv configuration directory, typically ~/.config/mpv/).
|
||||
|
||||
Example configuration would be:
|
||||
|
||||
disabled=no
|
||||
images=no
|
||||
videos=yes
|
||||
audio=yes
|
||||
|
||||
--]]
|
||||
|
||||
MAXENTRIES = 5000
|
||||
|
||||
local msg = require 'mp.msg'
|
||||
local options = require 'mp.options'
|
||||
local utils = require 'mp.utils'
|
||||
|
||||
o = {
|
||||
disabled = false,
|
||||
images = true,
|
||||
videos = true,
|
||||
audio = true
|
||||
}
|
||||
options.read_options(o)
|
||||
|
||||
function Set (t)
|
||||
local set = {}
|
||||
for _, v in pairs(t) do set[v] = true end
|
||||
return set
|
||||
end
|
||||
|
||||
function SetUnion (a,b)
|
||||
local res = {}
|
||||
for k in pairs(a) do res[k] = true end
|
||||
for k in pairs(b) do res[k] = true end
|
||||
return res
|
||||
end
|
||||
|
||||
EXTENSIONS_VIDEO = Set {
|
||||
'mkv', 'avi', 'mp4', 'ogv', 'webm', 'rmvb', 'flv', 'wmv', 'mpeg', 'mpg', 'm4v', '3gp'
|
||||
}
|
||||
|
||||
EXTENSIONS_AUDIO = Set {
|
||||
'mp3', 'wav', 'ogm', 'flac', 'm4a', 'wma', 'ogg', 'opus'
|
||||
}
|
||||
|
||||
EXTENSIONS_IMAGES = Set {
|
||||
'jpg', 'jpeg', 'png', 'tif', 'tiff', 'gif', 'webp', 'svg', 'bmp'
|
||||
}
|
||||
|
||||
EXTENSIONS = Set {}
|
||||
if o.videos then EXTENSIONS = SetUnion(EXTENSIONS, EXTENSIONS_VIDEO) end
|
||||
if o.audio then EXTENSIONS = SetUnion(EXTENSIONS, EXTENSIONS_AUDIO) end
|
||||
if o.images then EXTENSIONS = SetUnion(EXTENSIONS, EXTENSIONS_IMAGES) end
|
||||
|
||||
function add_files_at(index, files)
|
||||
index = index - 1
|
||||
local oldcount = mp.get_property_number("playlist-count", 1)
|
||||
for i = 1, #files do
|
||||
mp.commandv("loadfile", files[i], "append")
|
||||
mp.commandv("playlist-move", oldcount + i - 1, index + i - 1)
|
||||
end
|
||||
end
|
||||
|
||||
function get_extension(path)
|
||||
match = string.match(path, "%.([^%.]+)$" )
|
||||
if match == nil then
|
||||
return "nomatch"
|
||||
else
|
||||
return match
|
||||
end
|
||||
end
|
||||
|
||||
table.filter = function(t, iter)
|
||||
for i = #t, 1, -1 do
|
||||
if not iter(t[i]) then
|
||||
table.remove(t, i)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- splitbynum and alnumcomp from alphanum.lua (C) Andre Bogus
|
||||
-- Released under the MIT License
|
||||
-- http://www.davekoelle.com/files/alphanum.lua
|
||||
|
||||
-- split a string into a table of number and string values
|
||||
function splitbynum(s)
|
||||
local result = {}
|
||||
for x, y in (s or ""):gmatch("(%d*)(%D*)") do
|
||||
if x ~= "" then table.insert(result, tonumber(x)) end
|
||||
if y ~= "" then table.insert(result, y) end
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
function clean_key(k)
|
||||
k = (' '..k..' '):gsub("%s+", " "):sub(2, -2):lower()
|
||||
return splitbynum(k)
|
||||
end
|
||||
|
||||
-- compare two strings
|
||||
function alnumcomp(x, y)
|
||||
local xt, yt = clean_key(x), clean_key(y)
|
||||
for i = 1, math.min(#xt, #yt) do
|
||||
local xe, ye = xt[i], yt[i]
|
||||
if type(xe) == "string" then ye = tostring(ye)
|
||||
elseif type(ye) == "string" then xe = tostring(xe) end
|
||||
if xe ~= ye then return xe < ye end
|
||||
end
|
||||
return #xt < #yt
|
||||
end
|
||||
|
||||
local autoloaded = nil
|
||||
|
||||
function find_and_add_entries()
|
||||
local path = mp.get_property("path", "")
|
||||
local dir, filename = utils.split_path(path)
|
||||
msg.trace(("dir: %s, filename: %s"):format(dir, filename))
|
||||
if o.disabled then
|
||||
msg.verbose("stopping: autoload disabled")
|
||||
return
|
||||
elseif #dir == 0 then
|
||||
msg.verbose("stopping: not a local path")
|
||||
return
|
||||
end
|
||||
|
||||
local pl_count = mp.get_property_number("playlist-count", 1)
|
||||
-- check if this is a manually made playlist
|
||||
if (pl_count > 1 and autoloaded == nil) or
|
||||
(pl_count == 1 and EXTENSIONS[string.lower(get_extension(filename))] == nil) then
|
||||
msg.verbose("stopping: manually made playlist")
|
||||
return
|
||||
else
|
||||
autoloaded = true
|
||||
end
|
||||
|
||||
local pl = mp.get_property_native("playlist", {})
|
||||
local pl_current = mp.get_property_number("playlist-pos-1", 1)
|
||||
msg.trace(("playlist-pos-1: %s, playlist: %s"):format(pl_current,
|
||||
utils.to_string(pl)))
|
||||
|
||||
local files = utils.readdir(dir, "files")
|
||||
if files == nil then
|
||||
msg.verbose("no other files in directory")
|
||||
return
|
||||
end
|
||||
table.filter(files, function (v, k)
|
||||
if string.match(v, "^%.") then
|
||||
return false
|
||||
end
|
||||
local ext = get_extension(v)
|
||||
if ext == nil then
|
||||
return false
|
||||
end
|
||||
return EXTENSIONS[string.lower(ext)]
|
||||
end)
|
||||
table.sort(files, alnumcomp)
|
||||
|
||||
if dir == "." then
|
||||
dir = ""
|
||||
end
|
||||
|
||||
-- Find the current pl entry (dir+"/"+filename) in the sorted dir list
|
||||
local current
|
||||
for i = 1, #files do
|
||||
if files[i] == filename then
|
||||
current = i
|
||||
break
|
||||
end
|
||||
end
|
||||
if current == nil then
|
||||
return
|
||||
end
|
||||
msg.trace("current file position in files: "..current)
|
||||
|
||||
local append = {[-1] = {}, [1] = {}}
|
||||
for direction = -1, 1, 2 do -- 2 iterations, with direction = -1 and +1
|
||||
for i = 1, MAXENTRIES do
|
||||
local file = files[current + i * direction]
|
||||
local pl_e = pl[pl_current + i * direction]
|
||||
if file == nil or file[1] == "." then
|
||||
break
|
||||
end
|
||||
|
||||
local filepath = dir .. file
|
||||
if pl_e then
|
||||
-- If there's a playlist entry, and it's the same file, stop.
|
||||
msg.trace(pl_e.filename.." == "..filepath.." ?")
|
||||
if pl_e.filename == filepath then
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if direction == -1 then
|
||||
if pl_current == 1 then -- never add additional entries in the middle
|
||||
msg.info("Prepending " .. file)
|
||||
table.insert(append[-1], 1, filepath)
|
||||
end
|
||||
else
|
||||
msg.info("Adding " .. file)
|
||||
table.insert(append[1], filepath)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
add_files_at(pl_current + 1, append[1])
|
||||
add_files_at(pl_current, append[-1])
|
||||
end
|
||||
|
||||
mp.register_event("start-file", find_and_add_entries)
|
||||
25
multimedia/.config/mpv/scripts/battery.lua
Normal file
25
multimedia/.config/mpv/scripts/battery.lua
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
-- If the laptop is on battery, the profile 'lq' will be loaded; otherwise 'hq' is used
|
||||
--
|
||||
local lqprofile = "lowquality"
|
||||
local hqprofile = "highquality"
|
||||
|
||||
local function powerstate()
|
||||
local f = io.open("/sys/class/power_supply/AC/online")
|
||||
if f == nil then return end
|
||||
local t = f:read("*n")
|
||||
f:close()
|
||||
return t
|
||||
end
|
||||
|
||||
local function adjust()
|
||||
local state = powerstate()
|
||||
-- this actually overrides automatically applied profiles
|
||||
-- like 'protocol.http'
|
||||
if state == 0 then
|
||||
mp.msg.info("Running on battery, setting low-quality options.")
|
||||
mp.set_property("profile", lqprofile)
|
||||
else
|
||||
mp.msg.info("Not running on battery, setting high-quality options.")
|
||||
end
|
||||
end
|
||||
mp.add_hook("on_load", 1, adjust)
|
||||
32
multimedia/.config/mpv/scripts/gallery-dl.lua
Normal file
32
multimedia/.config/mpv/scripts/gallery-dl.lua
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
-- gallery-dl_hook.lua
|
||||
--
|
||||
-- load online image galleries as playlists using gallery-dl
|
||||
-- https://github.com/mikf/gallery-dl
|
||||
--
|
||||
-- to use, prepend the gallery url with: gallery-dl://
|
||||
-- e.g.
|
||||
-- `mpv gallery-dl://https://imgur.com/....`
|
||||
|
||||
local utils = require 'mp.utils'
|
||||
local msg = require 'mp.msg'
|
||||
|
||||
local function exec(args)
|
||||
local ret = utils.subprocess({args = args})
|
||||
return ret.status, ret.stdout, ret
|
||||
end
|
||||
|
||||
mp.add_hook("on_load", 15, function()
|
||||
local url = mp.get_property("stream-open-filename", "")
|
||||
if (url:find("gdl://") ~= 1) then
|
||||
msg.debug("not a gdl:// url: " .. url)
|
||||
return
|
||||
end
|
||||
local url = string.gsub(url,"gdl://","")
|
||||
|
||||
local es, urls, result = exec({"gallery-dl", "-g", url})
|
||||
if (es < 0) or (urls == nil) or (urls == "") then
|
||||
msg.error("failed to get album list.")
|
||||
end
|
||||
|
||||
mp.commandv("loadlist", "memory://" .. urls)
|
||||
end)
|
||||
1011
multimedia/.config/mpv/scripts/playlistmanager.lua
Normal file
1011
multimedia/.config/mpv/scripts/playlistmanager.lua
Normal file
File diff suppressed because it is too large
Load diff
94
multimedia/.config/mpv/scripts/sponsorblock_minimal.lua
Normal file
94
multimedia/.config/mpv/scripts/sponsorblock_minimal.lua
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
-- sponsorblock_minimal.lua
|
||||
--
|
||||
-- This script skips sponsored segments of YouTube videos
|
||||
-- using data from https://github.com/ajayyy/SponsorBlock
|
||||
--
|
||||
-- original from https://codeberg.org/jouni/mpv_sponsorblock_minimal
|
||||
-- adapted for local playback skipping and some refactoring by me
|
||||
local options = {
|
||||
API = "https://sponsor.ajay.app/api/skipSegments",
|
||||
|
||||
-- Categories to fetch and skip
|
||||
categories = '"sponsor","intro","outro","interaction","selfpromo"'
|
||||
}
|
||||
|
||||
local function getranges()
|
||||
local args = {
|
||||
"curl", "-s", "-d", "videoID=" .. Youtube_id, "-d",
|
||||
"categories=[" .. options.categories .. "]", "-G", options.API
|
||||
}
|
||||
local sponsors = mp.command_native({
|
||||
name = "subprocess",
|
||||
capture_stdout = true,
|
||||
playback_only = false,
|
||||
args = args
|
||||
})
|
||||
|
||||
if string.match(sponsors.stdout, "%[(.-)%]") then
|
||||
Ranges = {}
|
||||
for i in string.gmatch(string.sub(sponsors.stdout, 2, -2), "%[(.-)%]") do
|
||||
local k, v = string.match(i, "(%d+.?%d*),(%d+.?%d*)")
|
||||
Ranges[k] = v
|
||||
end
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
local function skip_ads(name, pos)
|
||||
if pos ~= nil then
|
||||
for k, v in pairs(Ranges) do
|
||||
if tonumber(k) <= pos and tonumber(v) > pos then
|
||||
-- this message may sometimes be wrong
|
||||
-- it only seems to be a visual thing though
|
||||
mp.osd_message("[sponsorblock] skipping forward " ..
|
||||
math.floor(
|
||||
tonumber(v) - mp.get_property("time-pos")) ..
|
||||
"s")
|
||||
-- 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", tonumber(v) + 0.01)
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
local function file_loaded()
|
||||
local video_path = mp.get_property("path")
|
||||
local youtube_id1 = string.match(video_path,
|
||||
"https?://youtu%.be/([%w-_]+).*")
|
||||
local youtube_id2 = string.match(video_path,
|
||||
"https?://w?w?w?%.?youtube%.com/v/([%w-_]+).*")
|
||||
local youtube_id3 = string.match(video_path, "/watch.*[?&]v=([%w-_]+).*")
|
||||
local youtube_id4 = string.match(video_path, "/embed/([%w-_]+).*")
|
||||
local localytfile = string.match(video_path,
|
||||
"-([%a%d%-_]+)%.[mw][kpe][v4b][m]?$")
|
||||
Youtube_id = youtube_id1 or youtube_id2 or youtube_id3 or youtube_id4 or
|
||||
localytfile
|
||||
if not Youtube_id or string.len(Youtube_id) < 11 then return end
|
||||
Youtube_id = string.sub(Youtube_id, 1, 11)
|
||||
|
||||
getranges()
|
||||
if Ranges then
|
||||
ON = true
|
||||
mp.add_key_binding("b", "sponsorblock", toggle)
|
||||
mp.observe_property("time-pos", "native", skip_ads)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
local function toggle()
|
||||
if ON then
|
||||
mp.unobserve_property(skip_ads)
|
||||
mp.osd_message("[sponsorblock] off")
|
||||
ON = false
|
||||
return
|
||||
end
|
||||
mp.observe_property("time-pos", "native", skip_ads)
|
||||
mp.osd_message("[sponsorblock] on")
|
||||
ON = true
|
||||
return
|
||||
end
|
||||
|
||||
mp.register_event("file-loaded", file_loaded)
|
||||
3655
multimedia/.config/mpv/scripts/uosc.lua
Normal file
3655
multimedia/.config/mpv/scripts/uosc.lua
Normal file
File diff suppressed because it is too large
Load diff
103
multimedia/.local/bin/umpv
Executable file
103
multimedia/.local/bin/umpv
Executable file
|
|
@ -0,0 +1,103 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
"""
|
||||
This script emulates "unique application" functionality on Linux. When starting
|
||||
playback with this script, it will try to reuse an already running instance of
|
||||
mpv (but only if that was started with umpv). Other mpv instances (not started
|
||||
by umpv) are ignored, and the script doesn't know about them.
|
||||
|
||||
This only takes filenames as arguments. Custom options can't be used; the script
|
||||
interprets them as filenames. If mpv is already running, the files passed to
|
||||
umpv are appended to mpv's internal playlist. If a file does not exist or is
|
||||
otherwise not playable, mpv will skip the playlist entry when attempting to
|
||||
play it (from the GUI perspective, it's silently ignored).
|
||||
|
||||
If mpv isn't running yet, this script will start mpv and let it control the
|
||||
current terminal. It will not write output to stdout/stderr, because this
|
||||
will typically just fill ~/.xsession-errors with garbage.
|
||||
|
||||
mpv will terminate if there are no more files to play, and running the umpv
|
||||
script after that will start a new mpv instance.
|
||||
|
||||
Note: you can supply custom mpv path and options with the MPV environment
|
||||
variable. The environment variable will be split on whitespace, and the
|
||||
first item is used as path to mpv binary and the rest is passed as options
|
||||
_if_ the script starts mpv. If mpv is not started by the script (i.e. mpv
|
||||
is already running), this will be ignored.
|
||||
"""
|
||||
|
||||
import sys
|
||||
import os
|
||||
import socket
|
||||
import errno
|
||||
import subprocess
|
||||
import string
|
||||
|
||||
files = sys.argv[1:]
|
||||
|
||||
# this is the same method mpv uses to decide this
|
||||
def is_url(filename):
|
||||
parts = filename.split("://", 1)
|
||||
if len(parts) < 2:
|
||||
return False
|
||||
# protocol prefix has no special characters => it's an URL
|
||||
allowed_symbols = string.ascii_letters + string.digits + "_"
|
||||
prefix = parts[0]
|
||||
return all(map(lambda c: c in allowed_symbols, prefix))
|
||||
|
||||
|
||||
# make them absolute; also makes them safe against interpretation as options
|
||||
def make_abs(filename):
|
||||
if not is_url(filename):
|
||||
return os.path.abspath(filename)
|
||||
return filename
|
||||
|
||||
|
||||
files = [make_abs(f) for f in files]
|
||||
|
||||
SOCK = os.path.join(str(os.getenv("HOME")), ".umpv_socket")
|
||||
|
||||
sock = None
|
||||
try:
|
||||
sock = socket.socket(socket.AF_UNIX)
|
||||
sock.connect(SOCK)
|
||||
except socket.error as e:
|
||||
if e.errno == errno.ECONNREFUSED:
|
||||
sock = None
|
||||
pass # abandoned socket
|
||||
elif e.errno == errno.ENOENT:
|
||||
sock = None
|
||||
pass # doesn't exist
|
||||
else:
|
||||
raise e
|
||||
|
||||
if sock:
|
||||
# Unhandled race condition: what if mpv is terminating right now?
|
||||
for f in files:
|
||||
# escape: \ \n "
|
||||
f = f.replace("\\", "\\\\").replace('"', '\\"').replace("\n", "\\n")
|
||||
f = '"' + f + '"'
|
||||
sock.send(("raw loadfile " + f + " append\n").encode("utf-8"))
|
||||
else:
|
||||
# Let mpv recreate socket if it doesn't already exist.
|
||||
|
||||
opts = (os.getenv("MPV") or "mpv").split()
|
||||
opts.extend(
|
||||
[
|
||||
"--no-terminal",
|
||||
"--force-window",
|
||||
"--input-ipc-server=" + SOCK,
|
||||
# position on lower left screen corner
|
||||
# contains funky fix for slight resizings depending on video
|
||||
# move it 10px more left than it wants; 5px more up
|
||||
"--geometry=15%+-10-+5",
|
||||
"--on-all-workspaces",
|
||||
"--force-window=immediate",
|
||||
"--x11-name=float",
|
||||
"--wayland-app-id=float",
|
||||
"--",
|
||||
]
|
||||
)
|
||||
opts.extend(files)
|
||||
|
||||
subprocess.check_call(opts)
|
||||
62
multimedia/README.md
Normal file
62
multimedia/README.md
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
# Multimedia module
|
||||
|
||||
[mpv](https://mpv.io) -- free, open-source, cross-platform media player
|
||||
beets -- organize your music library
|
||||
mopidy -- serve your music library
|
||||
ncmpcpp -- actually play your music (and twist your tongue pronouncing it)
|
||||
|
||||
The largest modifications so far are definitely to mpv (described below),
|
||||
with beets and mopidy being somewhat configured to my tastes as well.
|
||||
|
||||
mpv is set up to hopefully strike a balance between high quality playback, streaming with a reasonable speed and saving battery power.
|
||||
It is set up to play both local files and streams from the web (especially youtube with playlisting and ad skipping), via a qutebrowser mapping if the corresponding module is installed.
|
||||
|
||||
* mpv by default does not come with a gui, this configuration uses [uosc](https://github.com/darsain/uosc) to enable a comfortable gui
|
||||
* available subtitles are loaded and shown in a consistently high quality, as much as possible
|
||||
* easy screenshot grabbing is possible, saving to a default folder (`~/pictures/screenshots`, can be changed at top of `mpv.conf`)
|
||||
* audio is not meddled with too much, but should provide good default sound quality for pulseaudio
|
||||
* playback position is *not* saved for every file by default, but can be used when quitting with shift-q (default mpv behavior)
|
||||
* streaming video is optimized for a 1080p display, it will avoid qualities higher than that if possible
|
||||
* default video is adjusted for playback during the day, in a normally lit room
|
||||
* simple context menu (opened with `menu` key on keyboard) to load files, subtitles, chapters, and more
|
||||
* newly defined keybindings, look in `input.conf` for their definitions
|
||||
* when a battery is being discharged, mpv starts in a slightly lower quality but battery saving playback profile
|
||||
|
||||
## vim-like navigation
|
||||
|
||||
Scrolling through videos can be done with h and l (or H and L for larger steps),
|
||||
scrolling through a playlist is accomplished with J and K,
|
||||
and volume is controlled with j and k.
|
||||
|
||||
`a` controls playback speed, `s` cycles subtitles, `d` controls audio delay, `u` controls subtitle delay,
|
||||
`f` remains fullscreen, `p` toggles pauses, `i` shows the playlist, `o` peeks at the timeline, `F5` takes a screenshot.
|
||||
|
||||
Additionally, pressing the `menu` button (between right `ctrl` and `alt`) will open a little context menu,
|
||||
from which you can load other files, subtitles, chapters, switch audio tracks and take screenshots.
|
||||
|
||||
Most of this is (thanks to the hard work of the original script writers) easily customizable,
|
||||
mostly from `input.conf` directly.
|
||||
|
||||
## playlist management
|
||||
|
||||
Uses the wonderful [playlistmanager](https://github.com/jonniek/mpv-playlistmanager) script to enable easy management of mpv playlists.
|
||||
Enables manually or automatically sorting playlists, shuffling them, and saving them to files.
|
||||
|
||||
Additionally, it automatically populates streaming content with the video title instead of the url within the playlist.
|
||||
|
||||
## battery saving
|
||||
|
||||
When mpv ist started on a pc which it assumes to be running on battery power, it will automatically switch to a (slightly) lower quality mode,
|
||||
foregoing some of the upscaling niceties integrated into the default high quality mode for (somewhat) better battery preservation.
|
||||
|
||||
This script uses the output of `/sys/class/power_supply/AC/online`, and thus depends on this file being readable to get its information.
|
||||
|
||||
It degrades gracefully, and simply keeps running in higher quality if the file is not readable.
|
||||
|
||||
## sponsorblock
|
||||
|
||||
The [minimal mpv-sponsorblock](https://codeberg.org/jouni/mpv_sponsorblock_minimal) script is included to enable automatically skipping many sponsorship segments integrated within youtube videos.
|
||||
|
||||
This works mostly fully automated, it checks the database and finds affected segments, which it then automatically skips over.
|
||||
|
||||
To toggle sponsorblock on or off just hit `b`, it will confirm the choice via osd.
|
||||
Loading…
Add table
Add a link
Reference in a new issue