Removed commit history
Signed-off-by: Marko Korhonen <marko.korhonen@reekynet.com>
This commit is contained in:
commit
b1335a3628
199 changed files with 36930 additions and 0 deletions
11
home/.config/mpv/input.conf
Normal file
11
home/.config/mpv/input.conf
Normal file
|
@ -0,0 +1,11 @@
|
|||
Alt+LEFT add video-pan-x -0.1
|
||||
Alt+h add video-pan-x -0.1
|
||||
|
||||
Alt+DOWN add video-pan-y +0.1
|
||||
Alt+j add video-pan-y +0.1
|
||||
|
||||
Alt+UP add video-pan-y -0.1
|
||||
Alt+k add video-pan-y -0.1
|
||||
|
||||
Alt+RIGHT add video-pan-x +0.1
|
||||
Alt+l add video-pan-x +0.1
|
124
home/.config/mpv/mpv.conf
Normal file
124
home/.config/mpv/mpv.conf
Normal file
|
@ -0,0 +1,124 @@
|
|||
#############
|
||||
# Video #
|
||||
#############
|
||||
|
||||
# Hardware decoding
|
||||
vo=gpu
|
||||
hwdec=vaapi
|
||||
hwdec-codecs=all
|
||||
|
||||
{%@@ if profile == "Mirkwood" @@%}
|
||||
gpu-context=wayland
|
||||
{%@@ elif profile == "Rivendell" @@%}
|
||||
ao=alsa
|
||||
{%@@ endif @@%}
|
||||
|
||||
# Interpolation
|
||||
#profile=gpu-hq
|
||||
#scale=ewa_lanczossharp
|
||||
#cscale=ewa_lanczossharp
|
||||
#dscale=mitchell
|
||||
#video-sync=display-resample
|
||||
#interpolation=yes
|
||||
#tscale=box
|
||||
#tscale-window=sphinx
|
||||
#tscale-radius=1.0
|
||||
#tscale-clamp=0.0
|
||||
|
||||
#############
|
||||
# Audio #
|
||||
#############
|
||||
pulse-buffer=50 # using a large buffer causes seeking issues
|
||||
audio-pitch-correction=yes # automatically insert scaletempo when playing with higher speed
|
||||
|
||||
#############
|
||||
# Plugins/misc #
|
||||
#############
|
||||
# Mpris plugin
|
||||
script=/usr/lib/mpv/mpris.so
|
||||
|
||||
# Acestream plugin
|
||||
script=/usr/lib/mpv/mpv-acestream.lua
|
||||
|
||||
# Start ipc server
|
||||
input-ipc-server=/tmp/mpvsocket
|
||||
|
||||
# set youtube-dl max res to 1080
|
||||
ytdl-format=bestvideo[height<=1080]+bestaudio/best[height<=1080]
|
||||
|
||||
#############
|
||||
# Languages #
|
||||
#############
|
||||
slang=eng,en,enUS,en-US,fi,fiFI,fi-FI # automatically select these subtitles (decreasing priority)
|
||||
alang=eng,en,enUS,en-US,fi,fiFI,fi-FI # automatically select these audio tracks (decreasing priority)
|
||||
ytdl-raw-options=sub-lang="en,eng,enUS,en-US,fi,fiFI,fi-FI"
|
||||
|
||||
#############
|
||||
# Subtitles #
|
||||
#############
|
||||
no-sub # subtitles off on startup
|
||||
demuxer-mkv-subtitle-preroll # try to correctly show embedded subs when seeking
|
||||
sub-auto=fuzzy # external subs don't have to match the file name exactly to autoload
|
||||
sub-file-paths=ass:srt:sub:subs:subtitles # search for external subs in the listed subdirectories
|
||||
embeddedfonts=yes # use embedded fonts for SSA/ASS subs
|
||||
sub-ass-force-style=Kerning=yes # allows you to override style parameters of ASS scripts
|
||||
|
||||
# the following options only apply to subtitles without own styling (i.e. not ASS but e.g. SRT)
|
||||
sub-font="Overpass"
|
||||
sub-font-size=45
|
||||
sub-color="#FFFFFFFF"
|
||||
sub-border-color="#FF262626"
|
||||
sub-border-size=3.2
|
||||
sub-shadow-offset=1
|
||||
sub-shadow-color="#33000000"
|
||||
sub-spacing=0.5
|
||||
|
||||
#############
|
||||
# OSD / OSC #
|
||||
#############
|
||||
osd-font="Overpass"
|
||||
osd-font-size=30
|
||||
osd-color="#ffffffff" # ARGB format
|
||||
osd-border-color="#ff151515" # ARGB format
|
||||
osd-bar-align-y=0 # progress bar y alignment (-1 top, 0 centered, 1 bottom)
|
||||
osd-border-size=2 # size for osd text and progress bar
|
||||
osd-shadow-offset=1 # pixel width for osd text and progress bar
|
||||
osd-bar-w=60 # width of " " "
|
||||
osd-shadow-color="#11000000"
|
||||
osd-fractions
|
||||
|
||||
###################################
|
||||
# Protocol Specific Configuration #
|
||||
###################################
|
||||
|
||||
|
||||
[protocol.https]
|
||||
cache=yes
|
||||
user-agent='Mozilla/5.0 (X11; Linux x86_64; rv:55.0) Gecko/20100101 Firefox/55.0'
|
||||
|
||||
[protocol.http]
|
||||
cache=yes
|
||||
user-agent='Mozilla/5.0 (X11; Linux x86_64; rv:55.0) Gecko/20100101 Firefox/55.0'
|
||||
|
||||
[extension.gif]
|
||||
cache=no
|
||||
no-pause
|
||||
loop-file=yes
|
||||
|
||||
[extension.gifv]
|
||||
cache=no
|
||||
no-pause
|
||||
loop-file=yes
|
||||
|
||||
# Profile for 4k videos
|
||||
[4k]
|
||||
ytdl-format="bestvideo[height<=2160]+bestaudio/best[height<=2160]"
|
||||
|
||||
[best]
|
||||
ytdl-format="bestvideo+bestaudio"
|
||||
|
||||
# Use vulkan and hwdec
|
||||
[vulkan]
|
||||
gpu-api=vulkan
|
||||
gpu-context=waylandvk
|
||||
hwdec=vaapi-copy
|
1
home/.config/mpv/script-opts/osc.conf
Normal file
1
home/.config/mpv/script-opts/osc.conf
Normal file
|
@ -0,0 +1 @@
|
|||
hidetimeout=2000
|
30
home/.config/mpv/scripts/autosub.lua
Normal file
30
home/.config/mpv/scripts/autosub.lua
Normal file
|
@ -0,0 +1,30 @@
|
|||
-- default keybinding: b
|
||||
-- add the following to your input.conf to change the default keybinding:
|
||||
-- keyname script_binding auto_load_subs
|
||||
local utils = require 'mp.utils'
|
||||
|
||||
function display_error()
|
||||
mp.msg.warn("Subtitle download failed: ")
|
||||
mp.osd_message("Subtitle download failed")
|
||||
end
|
||||
|
||||
function load_sub_fn()
|
||||
path = mp.get_property("path")
|
||||
srt_path = string.gsub(path, "%.%w+$", ".srt")
|
||||
t = { args = { "subliminal", "download", "-s", "-f", "-l", "en", path } }
|
||||
|
||||
mp.osd_message("Searching subtitle")
|
||||
res = utils.subprocess(t)
|
||||
if res.error == nil then
|
||||
if mp.commandv("sub_add", srt_path) then
|
||||
mp.msg.warn("Subtitle download succeeded")
|
||||
mp.osd_message("Subtitle '" .. srt_path .. "' download succeeded")
|
||||
else
|
||||
display_error()
|
||||
end
|
||||
else
|
||||
display_error()
|
||||
end
|
||||
end
|
||||
|
||||
mp.add_key_binding("b", "auto_load_subs", load_sub_fn)
|
367
home/.config/mpv/scripts/mines.lua
Normal file
367
home/.config/mpv/scripts/mines.lua
Normal file
|
@ -0,0 +1,367 @@
|
|||
local assdraw = require 'mp.assdraw'
|
||||
|
||||
local W = 0
|
||||
local H = 0
|
||||
-- 2D array of size W*H that's addressed via gField[x][y]. Each entry is a
|
||||
-- table, with the following fields:
|
||||
-- is_mine: true or false
|
||||
-- area_mines: mine count in the 3x3 surrounding area
|
||||
-- is_covered: true or false, for visibility
|
||||
-- flag: flag put by user, one of FLAG_*
|
||||
local gField = nil
|
||||
|
||||
local FLAG_NONE = "" -- not flagged
|
||||
local FLAG_MINE = "⚑" -- "⚐" -- flagged as containing mine
|
||||
local FLAG_MAYBE_MINE = "!" -- flagged as maybe containing mine
|
||||
local FLAG_MAYBE_SAFE = "?" -- flagged as maybe empty
|
||||
|
||||
local STATUS_PLAYING = "playing"
|
||||
local STATUS_WON = "won"
|
||||
local STATUS_LOST = "lost"
|
||||
|
||||
local gStatus = nil
|
||||
|
||||
local gMines = 0
|
||||
|
||||
local gX = 0
|
||||
local gY = 0
|
||||
|
||||
local gNeedRefresh = false
|
||||
local gHidden = true
|
||||
local gTransparent = false
|
||||
|
||||
local PRESETS = {
|
||||
-- taken from kmines
|
||||
{ name = "easy", w = 9, h = 9, mines = 10 },
|
||||
{ name = "medium", w = 16, h = 16, mines = 40 },
|
||||
{ name = "hard", w = 30, h = 16, mines = 99 },
|
||||
}
|
||||
local gCurrentPreset = 2
|
||||
|
||||
function init_field()
|
||||
local preset = PRESETS[gCurrentPreset]
|
||||
gStatus = STATUS_PLAYING
|
||||
gField = {}
|
||||
W = preset.w
|
||||
H = preset.h
|
||||
gMines = math.min(preset.mines, W * H - 1)
|
||||
gX = 1
|
||||
gY = 1
|
||||
|
||||
for x = 1, W do
|
||||
gField[x] = {}
|
||||
for y = 1, H do
|
||||
gField[x][y] = {
|
||||
is_mine = false,
|
||||
area_mines = 0,
|
||||
is_covered = true,
|
||||
flag = FLAG_NONE,
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
-- place mines using the dumbfuck algorithm
|
||||
local place_mines = gMines
|
||||
while place_mines > 0 do
|
||||
local x = math.random(1, W)
|
||||
local y = math.random(1, H)
|
||||
if not gField[x][y].is_mine then
|
||||
gField[x][y].is_mine = true
|
||||
place_mines = place_mines - 1
|
||||
end
|
||||
end
|
||||
|
||||
-- pick a random start position (also using dumbfuck algorithm)
|
||||
for i = 1, 1000000 do
|
||||
local x = math.random(1, W)
|
||||
local y = math.random(1, H)
|
||||
if not gField[x][y].is_mine then
|
||||
gX = x
|
||||
gY = y
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
-- compute proximities after mines have been placed
|
||||
for y = 1, H do
|
||||
for x = 1, W do
|
||||
local tile = gField[x][y]
|
||||
for a_x = -1, 1 do
|
||||
for a_y = -1, 1 do
|
||||
local t_x = x + a_x
|
||||
local t_y = y + a_y
|
||||
if t_x >= 1 and t_x <= W and t_y >= 1 and t_y <= H and
|
||||
gField[t_x][t_y].is_mine
|
||||
then
|
||||
tile.area_mines = tile.area_mines + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
uncover()
|
||||
|
||||
check_status()
|
||||
|
||||
gNeedRefresh = true
|
||||
end
|
||||
|
||||
function uncover_at(x, y)
|
||||
if x < 1 or x > W or y < 1 or y > H then
|
||||
return
|
||||
end
|
||||
|
||||
local tile = gField[x][y]
|
||||
|
||||
if not tile.is_covered then
|
||||
return
|
||||
end
|
||||
|
||||
tile.is_covered = false
|
||||
|
||||
if tile.is_mine then
|
||||
return -- lost anyway
|
||||
end
|
||||
|
||||
-- uncover mines as far as it goes
|
||||
-- apparently, the standard thing to do is recursively uncovering all
|
||||
-- tiles which have 0 neightbours - tiles with 1 or more neighbours are
|
||||
-- uncovered, but not recursively
|
||||
if tile.area_mines == 0 then
|
||||
for a_x = -1, 1 do
|
||||
for a_y = -1, 1 do
|
||||
uncover_at(x + a_x, y + a_y)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
gNeedRefresh = true
|
||||
end
|
||||
|
||||
function check_status()
|
||||
if gStatus ~= STATUS_PLAYING then
|
||||
return
|
||||
end
|
||||
|
||||
local won = true
|
||||
local lost = false
|
||||
|
||||
for y = 1, H do
|
||||
for x = 1, W do
|
||||
local tile = gField[x][y]
|
||||
won = won and (tile.is_mine == tile.is_covered)
|
||||
lost = lost or (tile.is_mine and not tile.is_covered)
|
||||
end
|
||||
end
|
||||
|
||||
if lost then
|
||||
gStatus = STATUS_LOST
|
||||
gNeedRefresh = true
|
||||
elseif won then
|
||||
gStatus = STATUS_WON
|
||||
gNeedRefresh = true
|
||||
end
|
||||
end
|
||||
|
||||
function uncover()
|
||||
if gStatus ~= STATUS_PLAYING and not gField[gX][gY].is_covered then
|
||||
init_field()
|
||||
render()
|
||||
return
|
||||
end
|
||||
uncover_at(gX, gY)
|
||||
check_status()
|
||||
render()
|
||||
end
|
||||
|
||||
function flag()
|
||||
local tile = gField[gX][gY]
|
||||
local cycle = {FLAG_NONE, FLAG_MINE, FLAG_MAYBE_MINE, FLAG_MAYBE_SAFE}
|
||||
for i = 1, #cycle do
|
||||
if tile.flag == cycle[i] then
|
||||
tile.flag = cycle[(i - 1 + 1) % #cycle + 1]
|
||||
break
|
||||
end
|
||||
end
|
||||
if not tile.is_covered then
|
||||
tile.flag = FLAG_NONE
|
||||
end
|
||||
force_render()
|
||||
end
|
||||
|
||||
function move(x, y)
|
||||
gX = math.min(math.max(gX + x, 1), W)
|
||||
gY = math.min(math.max(gY + y, 1), H)
|
||||
|
||||
force_render()
|
||||
end
|
||||
|
||||
function force_render()
|
||||
gNeedRefresh = true
|
||||
render()
|
||||
end
|
||||
|
||||
function render()
|
||||
if not gNeedRefresh then
|
||||
return
|
||||
end
|
||||
|
||||
if gHidden then
|
||||
mp.set_osd_ass(1280, 720, "")
|
||||
return
|
||||
end
|
||||
|
||||
local canvas_w = 1280
|
||||
local canvas_h = 720
|
||||
local dw, dh, da = mp.get_osd_size()
|
||||
if dw ~= nil and dw > 0 and dh > 0 then
|
||||
canvas_w = dw / dh * canvas_h
|
||||
end
|
||||
|
||||
local tile_wh = 32
|
||||
|
||||
local o_x = canvas_w / 2 - tile_wh * W / 2
|
||||
local o_y = canvas_h / 2 - tile_wh * (H + 2) / 2 + tile_wh
|
||||
|
||||
local ass = assdraw.ass_new()
|
||||
|
||||
local transp = nil
|
||||
if gTransparent then
|
||||
transp = "{\\1a&HA0&\\3a&HA0&}"
|
||||
end
|
||||
|
||||
-- some shitty background
|
||||
ass:new_event()
|
||||
ass:append("{\\1c&Ha3a3a3&\\1a&H30&}")
|
||||
if transp then
|
||||
ass:append(transp)
|
||||
end
|
||||
ass:pos(o_x - tile_wh, o_y - tile_wh)
|
||||
ass:draw_start()
|
||||
ass:rect_cw(0, 0, (W + 2) * tile_wh, (H + 2) * tile_wh)
|
||||
-- grid
|
||||
local function grid_line(x0, y0, x1, y1)
|
||||
ass:new_event()
|
||||
ass:append("{\\bord0.5}")
|
||||
if transp then
|
||||
ass:append(transp)
|
||||
end
|
||||
ass:pos(x0, y0)
|
||||
ass:draw_start()
|
||||
ass:coord(0, 0)
|
||||
ass:line_to(x1 - x0, y1 - y0)
|
||||
end
|
||||
for x = 0, W do
|
||||
local p_x = x * tile_wh + o_x
|
||||
grid_line(p_x, o_y, p_x, o_y + tile_wh * H)
|
||||
end
|
||||
for y = 0, H do
|
||||
local p_y = y * tile_wh + o_y
|
||||
grid_line(o_x, p_y, o_x + tile_wh * W, p_y)
|
||||
end
|
||||
|
||||
local function draw_sym(x, y, sym, c)
|
||||
ass:new_event()
|
||||
ass:pos(x, y)
|
||||
ass:append("{\\an5\\fs25\\bord0\\1c&H" .. c .. "&\\b1}" .. sym)
|
||||
end
|
||||
|
||||
for x = 1, W do
|
||||
for y = 1, H do
|
||||
local tile = gField[x][y]
|
||||
local p_x = (x - 1) * tile_wh + tile_wh / 2 + o_x
|
||||
local p_y = (y - 1) * tile_wh + tile_wh / 2 + o_y
|
||||
local wh = tile_wh - 4
|
||||
local sym = nil
|
||||
if tile.is_covered then
|
||||
ass:new_event()
|
||||
if transp then
|
||||
ass:append(transp)
|
||||
end
|
||||
ass:pos(p_x, p_y)
|
||||
ass:draw_start()
|
||||
ass:round_rect_cw(-wh / 2, -wh / 2, wh / 2, wh / 2, 5)
|
||||
ass:draw_stop()
|
||||
elseif tile.is_mine then
|
||||
draw_sym(p_x, p_y, "💣", "0000FF")
|
||||
elseif tile.area_mines > 0 then
|
||||
draw_sym(p_x, p_y, tile.area_mines, "000000")
|
||||
end
|
||||
if tile.flag ~= FLAG_NONE then
|
||||
draw_sym(p_x, p_y, tile.flag, "FF0000")
|
||||
end
|
||||
if x == gX and y == gY then
|
||||
local wh = tile_wh - 12
|
||||
ass:new_event()
|
||||
ass:append("{\\1a&HFF&}")
|
||||
ass:pos(p_x, p_y)
|
||||
ass:draw_start()
|
||||
ass:rect_cw(-wh / 2, -wh / 2, wh / 2, wh / 2)
|
||||
ass:draw_stop()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local banner = nil
|
||||
if gStatus == STATUS_WON then
|
||||
banner = "You may have won, but actually you just wasted time."
|
||||
elseif gStatus == STATUS_LOST then
|
||||
banner = "You lost (and wasted time)."
|
||||
end
|
||||
if banner then
|
||||
ass:new_event()
|
||||
ass:pos(o_x + tile_wh * W / 2, o_y - tile_wh - 10)
|
||||
ass:append("{\\fs40\\b1\\an2}" .. banner)
|
||||
end
|
||||
|
||||
mp.set_osd_ass(canvas_w, canvas_h, ass.text)
|
||||
end
|
||||
|
||||
mp.observe_property("osd-width", "native", force_render)
|
||||
mp.observe_property("osd-height", "native", force_render)
|
||||
|
||||
init_field()
|
||||
force_render()
|
||||
|
||||
function toggle_transp()
|
||||
gTransparent = not gTransparent
|
||||
force_render()
|
||||
end
|
||||
|
||||
function cycle_preset()
|
||||
gCurrentPreset = (gCurrentPreset + 1 - 1) % #PRESETS + 1
|
||||
init_field()
|
||||
render()
|
||||
end
|
||||
|
||||
function toggle_show()
|
||||
if gHidden then
|
||||
gHidden = false
|
||||
|
||||
local REP = {repeatable = true}
|
||||
mp.add_forced_key_binding("left", "mines-left", function() move(-1, 0) end, REP)
|
||||
mp.add_forced_key_binding("right", "mines-right", function() move(1, 0) end, REP)
|
||||
mp.add_forced_key_binding("up", "mines-up", function() move(0, -1) end, REP)
|
||||
mp.add_forced_key_binding("down", "mines-down", function() move(0, 1) end, REP)
|
||||
mp.add_forced_key_binding("space", "mines-uncover", uncover)
|
||||
mp.add_forced_key_binding("b", "mines-flag", flag)
|
||||
mp.add_forced_key_binding("t", "mines-transp", toggle_transp)
|
||||
mp.add_forced_key_binding("w", "mines-preset", cycle_preset)
|
||||
else
|
||||
gHidden = true
|
||||
|
||||
mp.remove_key_binding("mines-left")
|
||||
mp.remove_key_binding("mines-right")
|
||||
mp.remove_key_binding("mines-up")
|
||||
mp.remove_key_binding("mines-down")
|
||||
mp.remove_key_binding("mines-uncover")
|
||||
mp.remove_key_binding("mines-flag")
|
||||
mp.remove_key_binding("mines-transp")
|
||||
mp.remove_key_binding("mines-preset")
|
||||
end
|
||||
|
||||
force_render()
|
||||
end
|
||||
|
||||
mp.add_forced_key_binding("ctrl+x", "mines-show", toggle_show)
|
43
home/.config/mpv/scripts/redshift_toggle.lua
Normal file
43
home/.config/mpv/scripts/redshift_toggle.lua
Normal file
|
@ -0,0 +1,43 @@
|
|||
-- Toggle redshift when viewing videos with mpv
|
||||
|
||||
if os.execute("pgrep -x redshift >/dev/null") ~= 0
|
||||
then
|
||||
return
|
||||
end
|
||||
|
||||
-- Consider that redshift is enabled when starting
|
||||
rs_enabled = true
|
||||
|
||||
function rs_toggle()
|
||||
os.execute("pkill -x -USR1 redshift")
|
||||
end
|
||||
|
||||
function rs_disable()
|
||||
if rs_enabled
|
||||
then
|
||||
rs_toggle()
|
||||
rs_enabled = false
|
||||
mp.msg.log("info", "Disabling redshift")
|
||||
end
|
||||
end
|
||||
|
||||
function rs_enable()
|
||||
if not rs_enabled
|
||||
then
|
||||
rs_toggle()
|
||||
rs_enabled = true
|
||||
mp.msg.log("info", "Reenabling redshift")
|
||||
end
|
||||
end
|
||||
|
||||
function rs_handler()
|
||||
if mp.get_property("video") ~= "no"
|
||||
then
|
||||
rs_disable()
|
||||
else
|
||||
rs_enable()
|
||||
end
|
||||
end
|
||||
|
||||
mp.register_event("file-loaded", rs_handler)
|
||||
mp.register_event("shutdown", rs_enable)
|
145
home/.config/mpv/scripts/slicing.lua
Normal file
145
home/.config/mpv/scripts/slicing.lua
Normal file
|
@ -0,0 +1,145 @@
|
|||
local msg = require "mp.msg"
|
||||
local utils = require "mp.utils"
|
||||
local options = require "mp.options"
|
||||
|
||||
local cut_pos = nil
|
||||
local copy_audio = true
|
||||
local o = {
|
||||
target_dir = "~",
|
||||
vcodec = "rawvideo",
|
||||
acodec = "pcm_s16le",
|
||||
prevf = "",
|
||||
vf = "format=yuv444p16$hqvf,scale=in_color_matrix=$matrix,format=bgr24",
|
||||
hqvf = "",
|
||||
postvf = "",
|
||||
opts = "",
|
||||
ext = "avi",
|
||||
command_template = [[
|
||||
ffmpeg -v warning -y -stats
|
||||
-ss $shift -i "$in" -t $duration
|
||||
-c:v $vcodec -c:a $acodec $audio
|
||||
-vf $prevf$vf$postvf $opts "$out.$ext"
|
||||
]],
|
||||
}
|
||||
options.read_options(o)
|
||||
|
||||
function timestamp(duration)
|
||||
local hours = duration / 3600
|
||||
local minutes = duration % 3600 / 60
|
||||
local seconds = duration % 60
|
||||
return string.format("%02d:%02d:%02.03f", hours, minutes, seconds)
|
||||
end
|
||||
|
||||
function osd(str)
|
||||
return mp.osd_message(str, 3)
|
||||
end
|
||||
|
||||
function get_homedir()
|
||||
-- It would be better to do platform detection instead of fallback but
|
||||
-- it's not that easy in Lua.
|
||||
return os.getenv("HOME") or os.getenv("USERPROFILE") or ""
|
||||
end
|
||||
|
||||
function log(str)
|
||||
local logpath = utils.join_path(
|
||||
o.target_dir:gsub("~", get_homedir()),
|
||||
"mpv_slicing.log")
|
||||
f = io.open(logpath, "a")
|
||||
f:write(string.format("# %s\n%s\n",
|
||||
os.date("%Y-%m-%d %H:%M:%S"),
|
||||
str))
|
||||
f:close()
|
||||
end
|
||||
|
||||
function escape(str)
|
||||
-- FIXME(Kagami): This escaping is NOT enough, see e.g.
|
||||
-- https://stackoverflow.com/a/31413730
|
||||
-- Consider using `utils.subprocess` instead.
|
||||
return str:gsub("\\", "\\\\"):gsub('"', '\\"')
|
||||
end
|
||||
|
||||
function trim(str)
|
||||
return str:gsub("^%s+", ""):gsub("%s+$", "")
|
||||
end
|
||||
|
||||
function get_csp()
|
||||
local csp = mp.get_property("colormatrix")
|
||||
if csp == "bt.601" then return "bt601"
|
||||
elseif csp == "bt.709" then return "bt709"
|
||||
elseif csp == "smpte-240m" then return "smpte240m"
|
||||
else
|
||||
local err = "Unknown colorspace: " .. csp
|
||||
osd(err)
|
||||
error(err)
|
||||
end
|
||||
end
|
||||
|
||||
function get_outname(shift, endpos)
|
||||
local name = mp.get_property("filename")
|
||||
local dotidx = name:reverse():find(".", 1, true)
|
||||
if dotidx then name = name:sub(1, -dotidx-1) end
|
||||
name = name:gsub(" ", "_")
|
||||
name = name:gsub(":", "-")
|
||||
name = name .. string.format(".%s-%s", timestamp(shift), timestamp(endpos))
|
||||
return name
|
||||
end
|
||||
|
||||
function cut(shift, endpos)
|
||||
local cmd = trim(o.command_template:gsub("%s+", " "))
|
||||
local inpath = escape(utils.join_path(
|
||||
utils.getcwd(),
|
||||
mp.get_property("stream-path")))
|
||||
local outpath = escape(utils.join_path(
|
||||
o.target_dir:gsub("~", get_homedir()),
|
||||
get_outname(shift, endpos)))
|
||||
|
||||
cmd = cmd:gsub("$shift", shift)
|
||||
cmd = cmd:gsub("$duration", endpos - shift)
|
||||
cmd = cmd:gsub("$vcodec", o.vcodec)
|
||||
cmd = cmd:gsub("$acodec", o.acodec)
|
||||
cmd = cmd:gsub("$audio", copy_audio and "" or "-an")
|
||||
cmd = cmd:gsub("$prevf", o.prevf)
|
||||
cmd = cmd:gsub("$vf", o.vf)
|
||||
cmd = cmd:gsub("$hqvf", o.hqvf)
|
||||
cmd = cmd:gsub("$postvf", o.postvf)
|
||||
cmd = cmd:gsub("$matrix", get_csp())
|
||||
cmd = cmd:gsub("$opts", o.opts)
|
||||
-- Beware that input/out filename may contain replacing patterns.
|
||||
cmd = cmd:gsub("$ext", o.ext)
|
||||
cmd = cmd:gsub("$out", outpath)
|
||||
cmd = cmd:gsub("$in", inpath, 1)
|
||||
|
||||
msg.info(cmd)
|
||||
log(cmd)
|
||||
os.execute(cmd)
|
||||
end
|
||||
|
||||
function toggle_mark()
|
||||
local pos = mp.get_property_number("time-pos")
|
||||
if cut_pos then
|
||||
local shift, endpos = cut_pos, pos
|
||||
if shift > endpos then
|
||||
shift, endpos = endpos, shift
|
||||
end
|
||||
if shift == endpos then
|
||||
osd("Cut fragment is empty")
|
||||
else
|
||||
cut_pos = nil
|
||||
osd(string.format("Cut fragment: %s - %s",
|
||||
timestamp(shift),
|
||||
timestamp(endpos)))
|
||||
cut(shift, endpos)
|
||||
end
|
||||
else
|
||||
cut_pos = pos
|
||||
osd(string.format("Marked %s as start position", timestamp(pos)))
|
||||
end
|
||||
end
|
||||
|
||||
function toggle_audio()
|
||||
copy_audio = not copy_audio
|
||||
osd("Audio capturing is " .. (copy_audio and "enabled" or "disabled"))
|
||||
end
|
||||
|
||||
mp.add_key_binding("c", "slicing_mark", toggle_mark)
|
||||
mp.add_key_binding("a", "slicing_audio", toggle_audio)
|
Loading…
Add table
Add a link
Reference in a new issue