├── LICENSE ├── README.md ├── autosubs_via_subliminal.lua ├── pause-indicator.jpg ├── pause-indicator.lua ├── show_chapters.jpeg ├── show_chapters.lua ├── show_podcast_description.lua ├── speed.conf ├── speed.lua ├── speed_osd3.lua └── total_playtime.lua /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 oltodosel 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Stand With Ukraine](https://raw.githubusercontent.com/vshymanskyy/StandWithUkraine/main/banner-direct-single.svg)](https://stand-with-ukraine.pp.ua) 2 | 3 | # speed.lua 4 | Changing speed based on regex of filename/path. 5 | * (see `speed.conf` for config example) 6 | * Use [rubberband](https://github.com/jgreco/mpv-scripts/blob/master/rubberband_helper.lua) for higher speeds. 7 | 8 | # total_playtime.lua 9 | * Shows total playtime of current playlist with `F12`. 10 | * Sorts playlist by duration with `KP4`. 11 | * * Repeated keypress reverses the order. 12 | * Sorts playlist by duration and jumps to the first entry with `shift+KP4`. 13 | * * Repeated keypress reverses the order. 14 | * On `Windows` it might flash cmd window for each iteration. [Reason](https://stackoverflow.com/questions/6362841/use-lua-os-execute-in-windows-to-launch-a-program-with-out-a-flash-of-cmd/6365296#6365296) 15 | * On `Windows` change the script according to [this](https://github.com/oltodosel/mpv-scripts/issues/1#issuecomment-894465495) 16 | * For `Mac` - https://github.com/oltodosel/mpv-scripts/issues/15#event-14435343114 17 | 18 | # show_chapters.lua 19 | Shows chapters and their time at the bottom left corner. 20 | * at a hotkey 21 | * at given paths 22 | * [example](https://github.com/oltodosel/mpv-scripts/raw/master/show_chapters.jpeg) 23 | 24 | # speed_osd3.lua 25 | Recalculates `osd-msg3` timecodes with speed != 1 26 | * Example at 1.5x : 00:24:43 -> 00:16:29 27 | 28 | # pause-indicator.lua 29 | Displays an indicator in the middle of the screen while mpv is paused. 30 | [Preview](https://github.com/oltodosel/mpv-scripts/raw/master/pause-indicator.jpg) 31 | 32 | # show_podcast_description.lua 33 | Displays content from `mp.get_property('metadata/lyrics')` 34 | -------------------------------------------------------------------------------- /autosubs_via_subliminal.lua: -------------------------------------------------------------------------------- 1 | -- original script: 2 | -- https://gist.github.com/selsta/ce3fb37e775dbd15c698 3 | -- 4 | -- subliminal: 5 | -- https://github.com/Diaoul/subliminal 6 | ------------------------------------------------------ 7 | -- Seeks subtitles with subliminal at different servers separately and downloads all available. 8 | -- 9 | -- keybinding: shift+v - for current file 10 | -- keybinding: shift+b - for all files in playlist 11 | -- 12 | -- language code(s) for one or more languages to seek 13 | sub_langs = {'de', 'he'} 14 | 15 | -- sites where to search 16 | sites = {'addic7ed', 'legendastv', 'opensubtitles', 'podnapisi', 'shooter', 'subscenter', 'thesubdb', 'tvsubtitles'} 17 | 18 | 19 | local utils = require 'mp.utils' 20 | 21 | function display_error() 22 | mp.msg.warn("Subtitle download failed") 23 | mp.osd_message("Subtitle download failed") 24 | end 25 | 26 | function auto_load_subs_all() 27 | all_files = 1 28 | mp.register_event("start-file", load_sub_fn) 29 | load_sub_fn() 30 | end 31 | 32 | function load_sub_fn() 33 | if all_files == 1 then 34 | os.execute('sleep .3') 35 | mp.set_property("pause", 'yes') 36 | end 37 | 38 | path = mp.get_property("path") 39 | 40 | for k1, language in pairs(sub_langs) do 41 | for k2, site_name in pairs(sites) do 42 | path2 = string.gsub(path, "%.%w+$", '.' .. language .. "." .. site_name .. ".srt") 43 | 44 | srt_path = string.gsub(path2, "%.%w+$", ".srt") 45 | t = { args = { "subliminal", "download", "--provider", site_name, "-s", "-l", language, path2 } } 46 | 47 | mp.osd_message("Searching subtitles...") 48 | res = utils.subprocess(t) 49 | if res.error == nil then 50 | if mp.commandv("sub_add", srt_path) then 51 | mp.msg.warn("Subtitle download succeeded.") 52 | mp.osd_message("Subtitle '" .. srt_path .. "' download succeeded") 53 | else 54 | display_error() 55 | end 56 | else 57 | display_error() 58 | end 59 | end 60 | end 61 | 62 | if all_files == 1 then 63 | mp.command("playlist_next force") 64 | end 65 | end 66 | 67 | mp.add_key_binding("V", "auto_load_subs", load_sub_fn) 68 | mp.add_key_binding("B", "auto_load_subs_all", auto_load_subs_all) 69 | -------------------------------------------------------------------------------- /pause-indicator.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oltodosel/mpv-scripts/7566810a0002a99f992b84f1326fcf9d32424e7d/pause-indicator.jpg -------------------------------------------------------------------------------- /pause-indicator.lua: -------------------------------------------------------------------------------- 1 | 2 | local ov = mp.create_osd_overlay('ass-events') 3 | ov.data = [[{\an5\p1\alpha&H79\1c&Hffffff&\3a&Hff\pos(760,440)}]] .. 4 | [[m-125 -75 l 2 2 l -125 75]] 5 | 6 | mp.observe_property('pause', 'bool', function(_, paused) 7 | mp.add_timeout(0.1, function() 8 | if paused then ov:update() 9 | else ov:remove() end 10 | end) 11 | end) -------------------------------------------------------------------------------- /show_chapters.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oltodosel/mpv-scripts/7566810a0002a99f992b84f1326fcf9d32424e7d/show_chapters.jpeg -------------------------------------------------------------------------------- /show_chapters.lua: -------------------------------------------------------------------------------- 1 | -- show chapters and their time at the bottom left corner 2 | -- the timings get proportionally adjusted at different speeds 3 | 4 | ---------------------------------------- 5 | CHAPTERS_TO_SHOW = 10 6 | HOTKEY = 'Meta+c' 7 | 8 | FONT_SCALE = 80 -- in % from osd-font-size 9 | FONT_SCALE_inactive_chapters = 75 10 | FONT_ALPHA_inactive_chapters = 60 11 | 12 | AUTOSTART_IN_PATHS = { 13 | "^edl://", 14 | "/med/p/podcasts", 15 | "/abooks/" 16 | } 17 | ---------------------------------------- 18 | 19 | local assdraw = require('mp.assdraw') 20 | 21 | function disp_time(time) 22 | local hours = math.floor(time/3600) 23 | local minutes = math.floor((time % 3600)/60) 24 | local seconds = math.floor(time % 60) 25 | 26 | return string.format("%02d:%02d:%02d", hours, minutes, seconds) 27 | end 28 | 29 | function time_2_seconds(time) 30 | h,m,s = time:match('(.*):(.*):(.*)$') 31 | 32 | return h*3600 + m*60 + s 33 | end 34 | 35 | function show_chapters() 36 | if observation_active == false then 37 | observation_active = true 38 | mp.observe_property("chapter", "number", show_chapters) 39 | mp.observe_property("speed", "number", show_chapters) 40 | end 41 | 42 | local osd_w, osd_h, aspect = mp.get_osd_size() 43 | local ass = assdraw:ass_new() 44 | ass:new_event() 45 | ass:an(1) 46 | 47 | -- font scale 48 | ass:append('{\\fscx' .. tostring(FONT_SCALE) .. '}') 49 | ass:append('{\\fscy' .. tostring(FONT_SCALE) .. '}') 50 | 51 | local ch_index = mp.get_property_number("chapter") 52 | local ch_total = mp.get_property_osd("chapter-list/count") 53 | 54 | if ch_index and ch_index >= 0 then 55 | ass:append("(" .. tostring(ch_index + 1) .. "/" .. tostring(ch_total) .. ")") 56 | 57 | shift = 1 58 | if ch_index == 0 then 59 | start_from = 0 60 | else 61 | shift = ch_total - CHAPTERS_TO_SHOW - ch_index - 1 62 | start_from = -1 63 | end 64 | 65 | if shift < 0 then 66 | start_from = shift 67 | end 68 | 69 | for i_ch = start_from, CHAPTERS_TO_SHOW + start_from do 70 | if tonumber(ch_total) == ch_index + i_ch then 71 | break 72 | end 73 | 74 | -- from overshooting backwards 75 | if ch_index + i_ch < 0 then 76 | goto continue 77 | end 78 | 79 | title = mp.get_property_osd("chapter-list/" .. tostring(ch_index + i_ch) .. "/title") 80 | time = mp.get_property_osd("chapter-list/" .. tostring(ch_index + i_ch) .. "/time") 81 | 82 | ass:append("\\N") 83 | 84 | if i_ch == 0 then 85 | ass:append("{\\alpha&H" .. '00' .. "}") 86 | ass:append('{\\fscx' .. tostring(FONT_SCALE) .. '}') 87 | ass:append('{\\fscy' .. tostring(FONT_SCALE) .. '}') 88 | else 89 | ass:append("{\\alpha&H" .. tostring(FONT_ALPHA_inactive_chapters) .. "}") 90 | ass:append('{\\fscx' .. tostring(FONT_SCALE_inactive_chapters) .. '}') 91 | ass:append('{\\fscy' .. tostring(FONT_SCALE_inactive_chapters) .. '}') 92 | end 93 | 94 | -- removing paths 95 | if string.sub(title, 1, 1) == '/' then 96 | title = title:match('.+/(.*)$') 97 | end 98 | 99 | speed = mp.get_property_number("speed") 100 | if speed ~= 1.0 then 101 | time = disp_time(time_2_seconds(time) / speed) 102 | end 103 | 104 | ass:append('[' .. time .. "] " .. title) 105 | 106 | ::continue:: 107 | end 108 | end 109 | 110 | mp.set_osd_ass(osd_w, osd_h, ass.text) 111 | end 112 | 113 | function started() 114 | local pth = mp.get_property("path") 115 | 116 | if pth == nil then 117 | return 118 | end 119 | 120 | for i, i_path in pairs(AUTOSTART_IN_PATHS) do 121 | if pth:find(i_path) then 122 | running = true 123 | show_chapters() 124 | return 125 | end 126 | end 127 | end 128 | 129 | function show_hide() 130 | if running == true then 131 | running = false 132 | observation_active = false 133 | mp.set_osd_ass(0, 0, "{}") 134 | mp.unobserve_property(show_chapters) 135 | else 136 | running = true 137 | show_chapters() 138 | end 139 | end 140 | 141 | observation_active = false 142 | 143 | mp.register_event("file-loaded", started) 144 | mp.add_forced_key_binding(HOTKEY, 'show_hide', show_hide, {repeatable=true}) 145 | 146 | -------------------------------------------------------------------------------- /show_podcast_description.lua: -------------------------------------------------------------------------------- 1 | -- shows content from mp.get_property('metadata/lyrics') 2 | 3 | ---------------------------------------- 4 | SPD_HOTKEY = 'Alt+c' 5 | 6 | -- in % from osd-font-size 7 | SPD_FONT_SCALE = 80 8 | 9 | -- top padding 10 | SPD_Y_POS_PX = 500 11 | 12 | -- for not truncating =0 13 | SPD_TEXT_MAX_SYMBOLS = 600 14 | 15 | SPD_AUTOSTART_IN_PATHS_REGEX = { 16 | "/home/lom/podcasts", 17 | "/mnt/1/Music/", 18 | "/abooks/" 19 | } 20 | ---------------------------------------- 21 | 22 | local assdraw_lyrics = require('mp.assdraw') 23 | 24 | function show_lyrics() 25 | local osd_w, osd_h, aspect = mp.get_osd_size() 26 | local ass = assdraw_lyrics:ass_new() 27 | ass:new_event() 28 | ass:an(4) 29 | 30 | -- font scale 31 | ass:append('{\\fscx' .. tostring(SPD_FONT_SCALE) .. '}') 32 | ass:append('{\\fscy' .. tostring(SPD_FONT_SCALE) .. '}') 33 | 34 | lyrics = mp.get_property('metadata/lyrics') 35 | 36 | if lyrics ~= nil then 37 | -- for assdraw's newlines 38 | lyrics = lyrics:gsub('\n', '\\N') 39 | 40 | if SPD_TEXT_MAX_SYMBOLS > 0 then 41 | lyrics = string.sub(lyrics, 0, SPD_TEXT_MAX_SYMBOLS) 42 | end 43 | 44 | ass:append('{\\pos(10,' .. SPD_Y_POS_PX .. ')}') 45 | ass:append(lyrics) 46 | end 47 | 48 | mp.set_osd_ass(osd_w, osd_h, ass.text) 49 | end 50 | 51 | function SPD_started() 52 | local pth = mp.get_property("path") 53 | 54 | if pth == nil then 55 | return 56 | end 57 | 58 | for i, i_path in pairs(SPD_AUTOSTART_IN_PATHS_REGEX) do 59 | if pth:find(i_path) then 60 | running_lyrics = true 61 | show_lyrics() 62 | return 63 | end 64 | end 65 | end 66 | 67 | function SPD_show_hide() 68 | if running_lyrics == true then 69 | running_lyrics = false 70 | mp.set_osd_ass(0, 0, "{}") 71 | mp.osd_message('Hiding lyricss', 5) 72 | else 73 | running_lyrics = true 74 | show_lyrics() 75 | mp.osd_message('Showing lyricss', 5) 76 | end 77 | end 78 | 79 | mp.register_event("file-loaded", SPD_started) 80 | mp.add_forced_key_binding(SPD_HOTKEY, 'SPD_show_hide', SPD_show_hide) 81 | -------------------------------------------------------------------------------- /speed.conf: -------------------------------------------------------------------------------- 1 | # speed path_or_name_in_lua's_regex_ignore_case 2 | # speed is float or int, \t for previously set speed value 3 | # first match && brake 4 | 5 | # lua's inability to work with utf8 properly: 6 | # [äöüß] : [\xc3][\xa4\xb6\xbc\x9f]* 7 | # [Hebrew] : [\xd7][\x90-\xaa]* 8 | # [Russian] : [\xd0-\xd1][\xb0-\x8f]* 9 | 10 | ############################################## 11 | 12 | 1.0 asmr 13 | 14 | 1.1 /med/video/youtube/.*[\xd7][\x90-\xaa]* 15 | 1.2 /med/video/youtube/.*[\xc3][\xa4\xb6\xbc\x9f]* 16 | 1.8 /med/video/youtube/.*[\xd0-\xd1][\xb0-\x8f]* 17 | 1.5 /med/video/youtube/ 18 | 19 | 1.1 /med/2see/.*[\xd7][\x90-\xaa]* 20 | 1.2 /med/2see/.*[\xc3][\xa4\xb6\xbc\x9f]* 21 | 1.8 /med/2see/.*[\xd0-\xd1][\xb0-\x8f]* 22 | 1.5 /med/2see/ 23 | 24 | 1.4 /med/p/TV/1_doc/en/ 25 | 1.2 /med/p/TV/1_doc/de/ 26 | 1.2 /med/p/TV/POKER/ 27 | 28 | 29 | 1.1 In trockenen Büchern 30 | Sternstunde Philosophie 31 | Soziopod 32 | Instant Philosophie 33 | Vorgedacht 34 | 35 | 1.2 36 | Stimmen der Kulturwissenschaften 37 | omega tau 38 | %[CRE%] 39 | Wissenschaft 40 | Raumzeit 41 | Request for Comments 42 | Sternengeschichten 43 | Resonator 44 | Zeitsprung 45 | Hoaxilla 46 | Kritisches Denken 47 | Das philosophische Radio 48 | WRINT 49 | 50 | Partially Examined Life 51 | Very Bad Wizards 52 | Drunken Philosophy 53 | Examining Ethics 54 | 55 | 1.3 56 | Two Psychologists Four Beers 57 | GeekWeek 58 | Die Frage 59 | Scathing Atheist 60 | Skepticrat 61 | 62 | 1.5 60 Minutes 63 | Ending The Sexual Dark Age 64 | By the Bi 65 | 66 | 1.6 Best of the Left 67 | 68 | 1.2 /med/podcasts/.*[\xc3][\xa4\xb6\xbc\x9f]* 69 | 1.6 /med/podcasts/.*[\xd0-\xd1][\xb0-\x8f]* 70 | 1.4 /med/podcasts/ 71 | 72 | 1.3 Last.Week.Tonight 73 | -------------------------------------------------------------------------------- /speed.lua: -------------------------------------------------------------------------------- 1 | speed_regexs_fn = '~/.config/mpv/scripts/speed.conf' 2 | 3 | function string.interpr_hex(str) 4 | return (str:gsub('\\x..', function (c) 5 | return string.char(c:gsub('\\x', '0x')):sub(1, 1) 6 | end)) 7 | end 8 | 9 | function trim(s) 10 | return s:gsub("^%s+", ""):gsub("%s+$", "") 11 | end 12 | 13 | function started() 14 | pth = mp.get_property("path"):lower() 15 | 16 | for _, speed_rgx in pairs(speed_regexs) do 17 | if pth:find(speed_rgx[2]) then 18 | mp.set_property("speed", speed_rgx[1]) 19 | break 20 | end 21 | end 22 | end 23 | 24 | speed_regexs_fn = speed_regexs_fn:gsub('~', os.getenv('HOME')) 25 | speed_regexs = {} 26 | 27 | for line in io.lines(speed_regexs_fn) do 28 | rgx = line:match("^\t(.+)") 29 | 30 | if speed and rgx then 31 | rgx = trim(rgx):interpr_hex():lower() 32 | if rgx:len() > 0 then 33 | table.insert(speed_regexs, {speed, rgx}) 34 | end 35 | else 36 | speed_tmp, rgx = line:match("^([%d%.]+)(.*)") 37 | 38 | if speed_tmp and rgx then 39 | speed = speed_tmp 40 | rgx = trim(rgx):interpr_hex():lower() 41 | if rgx:len() > 0 then 42 | table.insert(speed_regexs, {speed, rgx}) 43 | end 44 | end 45 | end 46 | end 47 | 48 | mp.register_event("file-loaded", started) 49 | -------------------------------------------------------------------------------- /speed_osd3.lua: -------------------------------------------------------------------------------- 1 | -- recalculates osd-msg3 timecodes with playback-speed != 1 2 | 3 | -- show current speed at given paths at top right corner 4 | SHOW_SPEED_IN_PATHS = { 5 | "^edl://", 6 | "/med/p/podcasts", 7 | "/abooks/" 8 | } 9 | ---------------------------------------- 10 | 11 | local assdraw = require('mp.assdraw') 12 | 13 | function disp_time(time) 14 | local hours = math.floor(time/3600) 15 | local minutes = math.floor((time % 3600)/60) 16 | local seconds = math.floor(time % 60) 17 | 18 | return string.format("%02d:%02d:%02d", hours, minutes, seconds) 19 | end 20 | 21 | past_value = -1 22 | function osd3(name, value) 23 | if value ~= nil and math.floor(value) ~= math.floor(past_value) then 24 | local speed = mp.get_property_number("speed") 25 | local dur = mp.get_property_number("duration") 26 | local pp = mp.get_property_number("percent-pos") 27 | 28 | if speed ~= nil and dur ~= nil and pp ~= nil then 29 | past_value = value 30 | mp.set_property("osd-msg3", 31 | string.format("%s / %s (%i%%)", 32 | disp_time(value / speed), 33 | disp_time(dur / speed), 34 | pp 35 | ) 36 | ) 37 | end 38 | end 39 | end 40 | 41 | function speed_change(name, value) 42 | if value ~= 1.0 then 43 | mp.observe_property("time-pos", "number", osd3) 44 | else 45 | mp.unobserve_property(osd3) 46 | mp.set_property("osd-msg3", "") 47 | end 48 | 49 | local tp = mp.get_property_number("time-pos") 50 | local speed = mp.get_property_number("speed") 51 | local dur = mp.get_property_number("duration") 52 | local pp = mp.get_property_number("percent-pos") 53 | 54 | if tp ~= nil and tp > 0.5 and speed ~= nil and dur ~= nil and pp ~= nil then 55 | mp.command( 56 | string.format('show-text "%s / %s (%i%%)\nx%.2f"', 57 | disp_time(tp / speed), 58 | disp_time(dur / speed), 59 | pp, 60 | speed 61 | ) 62 | ) 63 | end 64 | 65 | local pth = mp.get_property("path") 66 | if pth ~= nil then 67 | for i, work_in_path in pairs(SHOW_SPEED_IN_PATHS) do 68 | if pth:find(work_in_path) then 69 | local osd_w, osd_h, aspect = mp.get_osd_size() 70 | local ass = assdraw:ass_new() 71 | ass:new_event() 72 | ass:an(9) 73 | ass:append(string.format('x%.2f', speed)) 74 | mp.set_osd_ass(osd_w, osd_h, ass.text) 75 | 76 | break 77 | end 78 | end 79 | end 80 | end 81 | 82 | function started() 83 | local speed = mp.get_property_number("speed") 84 | local dur = mp.get_property_number("duration") 85 | 86 | if speed ~= nil and dur ~= nil then 87 | mp.set_property("osd-playing-msg", 88 | string.format("${filename} \n %s \n ${playlist-pos-1}/${playlist-count}", 89 | disp_time(dur / speed) 90 | ) 91 | ) 92 | else 93 | mp.set_property("osd-playing-msg", "") 94 | end 95 | end 96 | 97 | mp.register_event("file-loaded", started) 98 | mp.observe_property("speed", "number", speed_change) 99 | -------------------------------------------------------------------------------- /total_playtime.lua: -------------------------------------------------------------------------------- 1 | --~ Shows total playtime of current playlist. 2 | --~ If number of items in playlist didn't change since last calculation - it doesn't probe files anew. 3 | --~ requires ffprobe (ffmpeg) 4 | 5 | key_binding = 'F12' 6 | -- save probed files for future reference -- ${fname} \t ${duration} 7 | save_probed = true 8 | saved_probed_filename = '~/.config/mpv/scripts/total_playtime.list' 9 | 10 | ----------------------------------- 11 | local assdraw = require('mp.assdraw') 12 | local osd_w, osd_h, aspect = mp.get_osd_size() 13 | 14 | saved_probed_filename = saved_probed_filename:gsub('~', os.getenv('HOME')) 15 | 16 | local utils = require 'mp.utils' 17 | 18 | function disp_time(time) 19 | local hours = math.floor(time/3600) 20 | local minutes = math.floor((time % 3600)/60) 21 | local seconds = math.floor(time % 60) 22 | 23 | return string.format("%02d:%02d:%02d", hours, minutes, seconds) 24 | end 25 | 26 | function setContains(set, key) 27 | return set[key] ~= nil 28 | end 29 | playlist = {} 30 | playlist_total = -1 31 | 32 | function total_time() 33 | if #playlist ~= playlist_total then 34 | if save_probed then 35 | if io.open(saved_probed_filename, "rb") then 36 | probed_file = {} 37 | for line in io.lines(saved_probed_filename) do 38 | for k, v in line:gmatch("(.+)\t(.+)") do 39 | probed_file[k] = v 40 | end 41 | end 42 | else 43 | probed_file = {} 44 | end 45 | end 46 | 47 | local cwd = utils.getcwd() 48 | for pl_num, f in ipairs(mp.get_property_native("playlist")) do 49 | f = utils.join_path(cwd, f.filename) 50 | -- attempt basic path normalization 51 | if on_windows then 52 | f = string.gsub(f, "\\", "/") 53 | end 54 | f = string.gsub(f, "/%./", "/") 55 | local n 56 | repeat 57 | f, n = string.gsub(f, "/[^/]*/%.%./", "/", 1) 58 | until n == 0 59 | 60 | f = string.gsub(f, "\"", "\\\"") 61 | f = string.gsub(f, "%$", "\\$") 62 | 63 | if save_probed and probed_file[f] then 64 | fprobe = probed_file[f] 65 | else 66 | fprobe = io.popen('ffprobe -v quiet -of csv=p=0 -show_entries format=duration "'.. f .. '"'):read() 67 | 68 | if fprobe and save_probed then 69 | file = io.open(saved_probed_filename, "a") 70 | file:write(f .. '\t' .. fprobe .."\n") 71 | file:close() 72 | end 73 | end 74 | if ( tonumber(fprobe) ~= nil) then 75 | playlist[#playlist + 1] = { f, tonumber(fprobe), pl_num } 76 | end 77 | 78 | 79 | local ass = assdraw:ass_new() 80 | ass:new_event() 81 | ass:an(3) 82 | ass:append(string.format("Calculating: %s/%s", #playlist, mp.get_property("playlist-count"))) 83 | mp.set_osd_ass(osd_w, osd_h, ass.text) 84 | 85 | -- mp.osd_message(string.format("Calculating: %s/%s", #playlist, mp.get_property("playlist-count"))) 86 | end 87 | playlist_total = #playlist 88 | 89 | mp.set_osd_ass(0, 0, "{}") 90 | end 91 | 92 | total_dur = 0 93 | played_dur = mp.get_property_number("time-pos") 94 | current_pos = mp.get_property_number("playlist-pos-1", 0) 95 | 96 | for i, fn in pairs(playlist) do 97 | if fn[2] ~= nil then 98 | total_dur = total_dur + fn[2] 99 | if i < current_pos then 100 | played_dur = played_dur + fn[2] 101 | end 102 | end 103 | end 104 | 105 | osdm = string.format(" %s / %s (%s%%) \n %s / %s (%.2fx) \n %s/%s", 106 | disp_time(played_dur), 107 | disp_time(total_dur), 108 | math.floor(played_dur*100/total_dur), 109 | disp_time(played_dur/mp.get_property_number("speed")), 110 | disp_time(total_dur/mp.get_property_number("speed")), 111 | mp.get_property_number("speed"), 112 | mp.get_property("playlist-pos-1"), 113 | mp.get_property("playlist-count") 114 | ) 115 | 116 | mp.osd_message(osdm) 117 | end 118 | 119 | mp.add_forced_key_binding(key_binding, "total_time", total_time) 120 | 121 | -------------------------------------------------- 122 | -------------------------------------------------- 123 | -------------------------------------------------- 124 | 125 | function sort_playlist_to_0() 126 | sort_playlist(1) 127 | end 128 | 129 | reverse = 0 130 | function sort_playlist(start_0) 131 | total_time() 132 | 133 | table.sort(playlist, function (left, right) 134 | -- print(left[2]) 135 | if reverse == 0 then 136 | return left[2] < right[2] 137 | else 138 | return left[2] > right[2] 139 | end 140 | end) 141 | 142 | if reverse == 0 then 143 | reverse = 1 144 | else 145 | reverse = 0 146 | end 147 | 148 | out = '' 149 | 150 | for i, f in pairs(playlist) do 151 | if f[2] ~= nil then 152 | for i2, f2 in ipairs(mp.get_property_native("playlist")) do 153 | if f2.filename == f[1] then 154 | mp.commandv('playlist-move', i2 - 1, i - 1) 155 | 156 | if f2.filename == mp.get_property("path") then 157 | -- out = string.format('%s>>%s\t\t%s\n', out, disp_time(f[2]), f[1]:gsub('.+/', '')) 158 | out = string.format('%s%s\t\t%s\n', out, disp_time(f[2]), f[1]:gsub('.+/', '')) 159 | else 160 | out = string.format('%s%s\t\t%s\n', out, disp_time(f[2]), f[1]:gsub('.+/', '')) 161 | end 162 | break 163 | end 164 | end 165 | end 166 | end 167 | 168 | if start_0 ~= nil then 169 | mp.set_property('playlist-pos', 0) 170 | os.execute('sleep .1') 171 | end 172 | mp.osd_message(out, 3) 173 | end 174 | 175 | mp.add_forced_key_binding('KP4', "sort_playlist", sort_playlist) 176 | mp.add_forced_key_binding('shift+KP4', "sort_playlist_to_0", sort_playlist_to_0) 177 | --------------------------------------------------------------------------------