config/mpv/scripts/autoload.lua

   1 -- This script automatically loads playlist entries before and after the
   2 -- the currently played file. It does so by scanning the directory a file is
   3 -- located in when starting playback. It sorts the directory entries
   4 -- alphabetically, and adds entries before and after the current file to
   5 -- the internal playlist. (It stops if the it would add an already existing
   6 -- playlist entry at the same position - this makes it "stable".)
   7 -- Add at most 5000 * 2 files when starting a file (before + after).
   8 MAXENTRIES = 5000
   9 
  10 local options = require 'mp.options'
  11 
  12 o = {
  13     disabled = false
  14 }
  15 options.read_options(o)
  16 
  17 function Set (t)
  18     local set = {}
  19     for _, v in pairs(t) do set[v] = true end
  20     return set
  21 end
  22 
  23 EXTENSIONS = Set {
  24     'mkv', 'avi', 'mp4', 'ogv', 'webm', 'rmvb', 'flv', 'wmv', 'mpeg', 'mpg', 'm4v', '3gp',
  25     'mp3', 'wav', 'ogv', 'flac', 'm4a', 'wma',
  26 }
  27 
  28 mputils = require 'mp.utils'
  29 
  30 function add_files_at(index, files)
  31     index = index - 1
  32     local oldcount = mp.get_property_number("playlist-count", 1)
  33     for i = 1, #files do
  34         mp.commandv("loadfile", files[i], "append")
  35         mp.commandv("playlist-move", oldcount + i - 1, index + i - 1)
  36     end
  37 end
  38 
  39 function get_extension(path)
  40     match = string.match(path, "%.([^%.]+)$" )
  41     if match == nil then
  42         return "nomatch"
  43     else
  44         return match
  45     end
  46 end
  47 
  48 table.filter = function(t, iter)
  49     for i = #t, 1, -1 do
  50         if not iter(t[i]) then
  51             table.remove(t, i)
  52         end
  53     end
  54 end
  55 
  56 -- splitbynum and alnumcomp from alphanum.lua (C) Andre Bogus
  57 -- Released under the MIT License
  58 -- http://www.davekoelle.com/files/alphanum.lua
  59 
  60 -- split a string into a table of number and string values
  61 function splitbynum(s)
  62     local result = {}
  63     for x, y in (s or ""):gmatch("(%d*)(%D*)") do
  64         if x ~= "" then table.insert(result, tonumber(x)) end
  65         if y ~= "" then table.insert(result, y) end
  66     end
  67     return result
  68 end
  69 
  70 function clean_key(k)
  71     k = (' '..k..' '):gsub("%s+", " "):sub(2, -2):lower()
  72     return splitbynum(k)
  73 end
  74 
  75 -- compare two strings
  76 function alnumcomp(x, y)
  77     local xt, yt = clean_key(x), clean_key(y)
  78     for i = 1, math.min(#xt, #yt) do
  79         local xe, ye = xt[i], yt[i]
  80         if type(xe) == "string" then ye = tostring(ye)
  81         elseif type(ye) == "string" then xe = tostring(xe) end
  82         if xe ~= ye then return xe < ye end
  83     end
  84     return #xt < #yt
  85 end
  86 
  87 function find_and_add_entries()
  88     local path = mp.get_property("path", "")
  89     local dir, filename = mputils.split_path(path)
  90     if o.disabled or #dir == 0 then
  91         return
  92     end
  93     local pl_count = mp.get_property_number("playlist-count", 1)
  94     if (pl_count > 1 and autoload == nil) or
  95        (pl_count == 1 and EXTENSIONS[string.lower(get_extension(filename))] == nil) then
  96         return
  97     else
  98         autoload = true
  99     end
 100 
 101     local files = mputils.readdir(dir, "files")
 102     if files == nil then
 103         return
 104     end
 105     table.filter(files, function (v, k)
 106         if string.match(v, "^%.") then
 107             return false
 108         end
 109         local ext = get_extension(v)
 110         if ext == nil then
 111             return false
 112         end
 113         return EXTENSIONS[string.lower(ext)]
 114     end)
 115     table.sort(files, alnumcomp)
 116 
 117     if dir == "." then
 118         dir = ""
 119     end
 120 
 121     local pl = mp.get_property_native("playlist", {})
 122     local pl_current = mp.get_property_number("playlist-pos", 0) + 1
 123     -- Find the current pl entry (dir+"/"+filename) in the sorted dir list
 124     local current
 125     for i = 1, #files do
 126         if files[i] == filename then
 127             current = i
 128             break
 129         end
 130     end
 131     if current == nil then
 132         return
 133     end
 134 
 135     local append = {[-1] = {}, [1] = {}}
 136     for direction = -1, 1, 2 do -- 2 iterations, with direction = -1 and +1
 137         for i = 1, MAXENTRIES do
 138             local file = files[current + i * direction]
 139             local pl_e = pl[pl_current + i * direction]
 140             if file == nil or file[1] == "." then
 141                 break
 142             end
 143 
 144             local filepath = dir .. file
 145             if pl_e then
 146                 -- If there's a playlist entry, and it's the same file, stop.
 147                 if pl_e.filename == filepath then
 148                     break
 149                 end
 150             end
 151 
 152             if direction == -1 then
 153                 if pl_current == 1 then -- never add additional entries in the middle
 154                     mp.msg.info("Prepending " .. file)
 155                     table.insert(append[-1], 1, filepath)
 156                 end
 157             else
 158                 mp.msg.info("Adding " .. file)
 159                 table.insert(append[1], filepath)
 160             end
 161         end
 162     end
 163 
 164     add_files_at(pl_current + 1, append[1])
 165     add_files_at(pl_current, append[-1])
 166 end
 167 
 168 mp.register_event("start-file", find_and_add_entries)
 169