severen1999

Lua - MPV Gif Script

Nov 27th, 2021 (edited)
925
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. -- Original by Ruin0x11
  2. -- Ported to Windows by Scheliux, Dragoner7
  3. -- Ported to Windows 10 Latest MPV - Sevwren
  4. -- Create animated GIFs with mpv
  5. -- Requires ffmpeg.
  6. -- Usage: "g" to set start frame, "G" to set end frame, "Ctrl+g" to create.
  7. -- Currently the burn_subtitles function is broken.  
  8. require 'mp.options'
  9. local msg = require 'mp.msg'
  10.  
  11. local options = {
  12.     dir = "G:/mpv/gifs",
  13.     rez = 600,
  14.     fps = 15,
  15. }
  16.  
  17. read_options(options, "gif")
  18.  
  19.  
  20. local fps
  21.  
  22. -- Check for invalid fps values
  23. -- Can you believe Lua doesn't have a proper ternary operator in the year of our lord 2020?
  24. if options.fps ~= nil and options.fps >= 1 and options.fps < 30 then
  25.     fps = options.fps
  26. else
  27.     fps = 15
  28. end
  29.  
  30. -- Set this to the filters to pass into ffmpeg's -vf option.
  31. -- filters="fps=24,scale=320:-1:flags=spline"
  32. --filters=string.format("fps=%s,scale='trunc(ih*dar/2)*2:trunc(ih/2)*2',setsar=1/1,scale=%s:-1:flags=spline", fps, options.rez) --change spline to lanczos depending on preference
  33. filters=string.format("fps=%s,scale='trunc(ih*dar/2)*2:trunc(ih/2)*2',setsar=1/1,scale=%s:-1:flags=lanczos", fps, options.rez) --change spline to lanczos depending on preference
  34.  
  35. -- Setup output directory
  36. output_directory=string.gsub(options.dir, '\"', '')
  37.  
  38. start_time = -1
  39. end_time = -1
  40. palette="%TEMP%palette.png"
  41.  
  42. -- The roundabout way has to be used due to a some weird
  43. -- behavior with %TEMP% on the subtitles= parameter in ffmpeg
  44. -- on Windows–it needs to be quadruple backslashed
  45. subs = "C:/Users/%USERNAME%/AppData/Local/Temp/subs.srt"
  46.  
  47. function make_gif_with_subtitles()
  48.     make_gif_internal(true)
  49. end
  50.  
  51. function make_gif()
  52.     make_gif_internal(false)
  53. end    
  54.  
  55. function table_length(t)
  56.     local count = 0
  57.     for _ in pairs(t) do count = count + 1 end
  58.     return count
  59. end
  60.  
  61.  
  62. function make_gif_internal(burn_subtitles)
  63.     local start_time_l = start_time
  64.     local end_time_l = end_time
  65.     if start_time_l == -1 or end_time_l == -1 or start_time_l >= end_time_l then
  66.         mp.osd_message("Invalid start/end time.")
  67.         return
  68.     end
  69.  
  70.     mp.osd_message("Creating GIF.")
  71.  
  72.     -- shell escape
  73.     function esc(s)
  74.         return string.gsub(s, '"', '"\\""')
  75.     end
  76.  
  77.     function esc_for_sub(s)
  78.         s = string.gsub(s, [[\]], [[/]])
  79.         s = string.gsub(s, '"', '"\\""')
  80.         s = string.gsub(s, ":", [[\\:]])
  81.         s = string.gsub(s, "'", [[\\']])
  82.        return s
  83.    end
  84.  
  85.    local pathname = mp.get_property("path", "")
  86.    local trim_filters = esc(filters)
  87.  
  88.    local position = start_time_l
  89.    local duration = end_time_l - start_time_l
  90.  
  91.    if burn_subtitles then
  92.        -- Determine currently active sub track
  93.  
  94.        local i = 0
  95.        local tracks_count = mp.get_property_number("track-list/count")
  96.        local subs_array = {}
  97.        
  98.        -- check for subtitle tracks
  99.  
  100.        while i < tracks_count do
  101.            local type = mp.get_property(string.format("track-list/%d/type", i))
  102.            local selected = mp.get_property(string.format("track-list/%d/selected", i))
  103.  
  104.            -- if it's a sub track, save it
  105.  
  106.             if type == "sub" then
  107.                 local length = table_length(subs_array)
  108.                 subs_array[length] = selected == "yes"
  109.             end
  110.             i = i + 1
  111.         end
  112.  
  113.         if table_length(subs_array) > 0 then
  114.  
  115.             local correct_track = 0
  116.  
  117.             -- iterate through saved subtitle tracks until the correct one is found
  118.  
  119.             for index, is_selected in pairs(subs_array) do
  120.                 if (is_selected) then
  121.                     correct_track = index
  122.                 end
  123.             end
  124.  
  125.             trim_filters = trim_filters .. string.format(",subtitles=%s:si=%s", esc_for_sub(pathname), correct_track)
  126.  
  127.         end
  128.  
  129.     end
  130.  
  131.  
  132.     -- first, create the palette
  133.     args = string.format('ffmpeg -v warning -ss %s -t %s -i "%s" -vf "%s,palettegen" -y "%s"', position, duration, esc(pathname), esc(trim_filters), esc(palette))
  134.     msg.debug(args)
  135.     os.execute(args)
  136.  
  137.     -- then, make the gif
  138.     local filename = mp.get_property("filename/no-ext")
  139.     local file_path = output_directory .. "/" .. filename
  140.  
  141.     -- increment filename
  142.     for i=0,999 do
  143.         local fn = string.format('%s_%03d.gif',file_path,i)
  144.         if not file_exists(fn) then
  145.             gifname = fn
  146.             break
  147.         end
  148.     end
  149.     if not gifname then
  150.         mp.osd_message('No available filenames!')
  151.         return
  152.     end
  153.  
  154.     local copyts = ""
  155.  
  156.     if burn_subtitles then
  157.         copyts = "-copyts"
  158.     end
  159.  
  160.     args = string.format('ffmpeg -v warning -ss %s %s -t %s -i "%s" -i "%s" -lavfi "%s [x]; [x][1:v] paletteuse" -y "%s"', position, copyts, duration, esc(pathname), esc(palette), esc(trim_filters), esc(gifname))
  161.     os.execute(args)
  162.  
  163.     local ok, err, code = os.rename(gifname, gifname)
  164.     if ok then
  165.         msg.info("GIF created: " .. gifname)
  166.         mp.osd_message("GIF created: " .. gifname)
  167.     else
  168.         mp.osd_message("Error creating file, check CLI for more info.")
  169.     end
  170. end
  171.  
  172. function set_gif_start()
  173.     start_time = mp.get_property_number("time-pos", -1)
  174.     mp.osd_message("GIF Start: " .. start_time)
  175. end
  176.  
  177. function set_gif_end()
  178.     end_time = mp.get_property_number("time-pos", -1)
  179.     mp.osd_message("GIF End: " .. end_time)
  180. end
  181.  
  182. function file_exists(name)
  183.     local f=io.open(name,"r")
  184.     if f~=nil then io.close(f) return true else return false end
  185. end
  186.  
  187. mp.add_key_binding("g", "set_gif_start", set_gif_start)
  188. mp.add_key_binding("G", "set_gif_end", set_gif_end)
  189. mp.add_key_binding("Ctrl+g", "make_gif", make_gif)
  190. mp.add_key_binding("Ctrl+G", "make_gif_with_subtitles", make_gif_with_subtitles)
  191.  
RAW Paste Data