Skip to content

Commit

Permalink
Initial commit (full features, readme+license)
Browse files Browse the repository at this point in the history
Creates thumbnails iteratively now, in multiple passes.
This way the end of the file can be previewed quickly,
without having to wait for all the thumbs from start to end
to be generated.

Also lots of other stuff.
Should be robust, lest users prove me wrong.
TheAMM committed Dec 5, 2017
1 parent 13f76d7 commit 7074706
Showing 12 changed files with 1,105 additions and 126 deletions.
674 changes: 674 additions & 0 deletions LICENSE

Large diffs are not rendered by default.

118 changes: 118 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
# `mpv_thumbnail_script.lua`

[![](docs/mpv_thumbnail_script.jpg "Thumbnail preview for Sintel (2010) on mpv's seekbar")](https://www.youtube.com/watch?v=a9cmt176WDI)
[*Click the image or here to see the script in action*](https://www.youtube.com/watch?v=a9cmt176WDI)

----

## What is it?

`mpv_thumbnail_script.lua` is a script/replacement OSC for [mpv](https://github.com/mpv-player/mpv) to display preview thumbnails when hovering over the seekbar, without any external dependencies[<sup>1</sup>](#footnotes), cross-platform-ly[<sup>2</sup>](#footnotes)!

The script supports all four built-in OSC layouts, [as seen in this Youtube video](https://www.youtube.com/watch?v=WsfWmO41p8A).
The script will also do multiple passes over the video, generating thumbnails with increasing frequency until the target is reached.
This allows you to preview the end of the file before every thumbnail has been generated.

## How do I install it?

Grab both the `mpv_thumbnail_script_server.lua` and `mpv_thumbnail_script_client_osc.lua` from the [releases page](https://github.com/TheAMM/mpv_thumbnail_script/releases) (or [see below](#development) how to "build" (concatenate) it yourself) and place them both to your mpv's `scripts` directory. (**Note!** Also see Configuration below)

For example:
* Linux/Unix/Mac: `~/.config/mpv/scripts/mpv_thumbnail_script_server.lua` & `~/.config/mpv/scripts/mpv_thumbnail_script_client_osc.lua`
* Windows: `%APPDATA%\Roaming\mpv\scripts\mpv_thumbnail_script_server.lua` & `%APPDATA%\Roaming\mpv\scripts\mpv_thumbnail_script_client_osc.lua`

See the [Files section](https://mpv.io/manual/master/#files) in mpv's manual for more info.

The script can also use FFmpeg for faster thumbnail generation, which is highly recommended.
Just make sure `ffmpeg[.exe]` is in your `PATH`.

## How do I use it?

Just open a file and hover over the seekbar!
Although by default, videos over an hour will require you to press the `T` (that's `shift+t`) keybind.
You may change this duration check in the configuration (`autogenerate_max_duration`).

**Also of note:** the script does not manage the thumbnails in any way, you should clear the directory from time to time.

## Configuration

**Note!** Because this script replaces the built-in OSC, you will have to set `osc=no` in your mpv's [main config file](https://mpv.io/manual/master/#files).

Create a file called `mpv_thumbnail_script.conf` inside your mpv's `lua-settings` directory to adjust the script's options.

For example:
* Linux/Unix/Mac: `~/.config/mpv/lua-settings/mpv_thumbnail_script.conf`
* Windows: `%APPDATA%\Roaming\mpv\lua-settings\mpv_thumbnail_script.conf`

See the [Files section](https://mpv.io/manual/master/#files) in mpv's manual for more info.

In this file you may set the following options:
```ini
# The thumbnail cache directory.
# On Windows this defaults to %TEMP%\mpv_thumbs_cache,
# and on other platforms to /tmp/mpv_thumbs_cache.
# The directory will be created automatically, but must be writeable!
cache_directory=/tmp/my_mpv_thumbnails

# Whether to generate thumbnails automatically on video load, without a keypress
# Defaults to yes
autogenerate=[yes/no]

# Only automatically thumbnail videos shorter than this (in seconds)
# You will have to press T (or your own keybind) to enable the thumbnail previews
# Set to 0 to disable the check, ie. thumbnail videos no matter how long they are
# Defaults to 3600 (one hour)
autogenerate_max_duration=3600

# Use mpv to generate thumbnail even if ffmpeg is found in PATH
# It's better to use ffmpeg, but the choice is yours
# Defaults to no
prefer_mpv=[yes/no]

# Enable to disable the built-in keybind ("T") to add your own, see after the block
disable_keybinds=[yes/no]

# The maximum dimensions of the thumbnails, in pixels
# Defaults to 200 and 200
thumbnail_width=200
thumbnail_height=200

# The thumbnail count target
# (This will result in a thumbnail every ~10 seconds for a 25 minute video)
thumbnail_count=150

# The above target count will be adjusted by the minimum and
# maximum time difference between thumbnails.
# The thumbnail_count will be used to calculate a target separation,
# and min/max_delta will be used to constrict it.

# In other words, thumbnails will be:
# - at least min_delta seconds apart (limiting the amount)
# - at most max_delta seconds apart (raising the amount if needed)
# Defaults to 5 and 90, values are seconds
min_delta=5
max_delta=90
# 120 seconds aka 2 minutes will add more thumbnails only when the video is over 5 hours long!
```

With `disable_keybind=yes`, you can add your own keybind to [`input.conf`](https://mpv.io/manual/master/#input-conf) with `script-binding generate-thumbnails`, for example:
```ini
shift+alt+s script-binding generate-thumbnails
```

## Development

Included in the repository is the `concat_files.py` tool I use for automatically concatenating files upon their change, and also mapping changes to the output file back to the source files. It's really handy on stack traces when mpv gives you a line and column on the output file - no need to hunt down the right place in the source files!

The script requires Python 3, so install that. Nothing more, though. Call it with `concat_files.py cat_osc.json`.

You may also, of course, just `cat` the files together yourself. See the [`cat_osc.json`](cat_osc.json)/[`cat_server.json`](cat_server.json) for the order.

### Donation

If you *really* get a kick out of this (weirdo), you can [paypal me](https://www.paypal.me/TheAMM) or send bitcoins to `1K9FH7J3YuC9EnQjjDZJtM4EFUudHQr52d`. Just having the option there, is all.

#### Footnotes
<sup>1</sup>You *may* need to add `mpv[.exe]` to your `PATH` (and *will* have to add `ffmpeg[.exe]` if you want faster generation).

<sup>2</sup>Developed & tested on Windows and Linux (Ubuntu), but it *should* work on Mac and whatnot as well, if <sup>1</sup> has been taken care of.
6 changes: 6 additions & 0 deletions cat_osc.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
{
"output" : "mpv_thumbnail_script_client_osc.lua",
"files" : [
"src/license_blurb.lua",
"<version>",
"lib/helpers.lua",
"src/options.lua",
"src/thumbnailer_shared.lua",
"src/patched_osc.lua"
],

"version_file" : "version.txt",
"version_template_file" : "src/version.tmpl.lua",

"header_prefix" : "--[ ",
"header_suffix" : " ]--"
}
6 changes: 6 additions & 0 deletions cat_server.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
{
"output" : "mpv_thumbnail_script_server.lua",
"files" : [
"src/license_blurb.lua",
"<version>",
"lib/helpers.lua",
"src/options.lua",
"src/thumbnailer_shared.lua",
"src/thumbnailer_server.lua"
],

"version_file" : "version.txt",
"version_template_file" : "src/version.tmpl.lua",

"header_prefix" : "--[ ",
"header_suffix" : " ]--"
}
Binary file added docs/mpv_thumbnail_script.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 16 additions & 0 deletions src/license_blurb.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
--[[
Copyright (C) 2017 AMM
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
]]--
24 changes: 20 additions & 4 deletions src/options.lua
Original file line number Diff line number Diff line change
@@ -6,22 +6,38 @@ local thumbnailer_options = {
-- The thumbnail directory
cache_directory = join_paths(default_cache_base, "mpv_thumbs_cache"),

-- Automatically generate the thumbnails on video load, without a keypress
autogenerate = true,

-- Only automatically thumbnail videos shorter than this (seconds)
autogenerate_max_duration = 3600, -- 1 hour

-- Use mpv to generate thumbnail even if ffmpeg is found in PATH
-- Note: mpv is a bit slower, but includes eg. subtitles in the previews!
prefer_mpv = false,

-- Disable the built-in keybind ("T")
-- Disable the built-in keybind ("T") to add your own
disable_keybinds = false,

-- The maximum dimensions of the thumbnails
-- The maximum dimensions of the thumbnails (pixels)
thumbnail_width = 200,
thumbnail_height = 200,

-- asd
-- The thumbnail count target
-- (This will result in a thumbnail every ~10 seconds for a 25 minute video)
thumbnail_count = 150,

-- The above target count will be adjusted by the minimum and
-- maximum time difference between thumbnails.
-- The thumbnail_count will be used to calculate a target separation,
-- and min/max_delta will be used to constrict it.

-- In other words, thumbnails will be:
-- at least min_delta seconds apart (limiting the amount)
-- at most max_delta seconds apart (raising the amount if needed)
min_delta = 5,
max_delta = 120,
-- 120 seconds aka 2 minutes will add more thumbnails when the video is over 5 hours!
max_delta = 90,
}

read_options(thumbnailer_options, SCRIPT_NAME)
230 changes: 139 additions & 91 deletions src/patched_osc.lua
Original file line number Diff line number Diff line change
@@ -11,93 +11,6 @@ local opt = require 'mp.options'
local utils = require 'mp.utils'


-- mpv_thumbnail_script.lua --

Thumbnailer:register_client()

local osc_thumb_state = {
visible = false,
overlay_id = 1,

last_path = nil,
last_x = nil,
last_y = nil,
}


function hide_thumbnail()
osc_thumb_state.visible = false
osc_thumb_state.last_path = nil
mp.command_native({ "overlay-remove", osc_thumb_state.overlay_id })
end

function display_thumbnail(pos, value, ass)
-- If thumbnails are not available, bail
if not (Thumbnailer.state.enabled and Thumbnailer.state.available) then
return
end

local duration = mp.get_property_number("duration", nil)
if not ((duration == nil) or (value == nil)) then
target_position = duration * (value / 100)

local msx, msy = get_virt_scale_factor()
local thumb_size = Thumbnailer.state.thumbnail_size
local thumb_path, thumb_index = Thumbnailer:get_thumbnail_path(target_position)

if thumb_path == nil then

local aw = thumb_size.w * msx
local ah = thumb_size.h * msy
local y_offset = get_thumbnail_y_offset(thumb_size, 1)

ass:new_event()
ass:pos(pos.x - aw/2, pos.y - y_offset - ah)

ass:append(("{\\bord0\\1c&H000000&\\1a&H%X&"):format(80))
ass:draw_start()
ass:rect_cw(0, 0, aw, ah)
ass:draw_stop()

ass:new_event()
ass:pos(pos.x, pos.y - y_offset - ah/2)
ass:append(("{\\bord0\\fscx%f\\fscy%f}"):format(100*msx, 100*msy))
ass:an(5)

local thumbs_ready = Thumbnailer.state.finished_thumbnails
local thumbs_total = Thumbnailer.state.thumbnail_count
local perc = math.floor((thumbs_ready / thumbs_total) * 100)
ass:append(("%d%%\\N%d / %d\\N(%d)"):format(perc, thumbs_ready, thumbs_total, thumb_index+1))

else
local y_offset = get_thumbnail_y_offset(thumb_size, msy)

local thumb_x = math.floor(pos.x / msx - thumb_size.w/2)
local thumb_y = math.floor(pos.y / msy - thumb_size.h - y_offset)

osc_thumb_state.visible = true
if not (osc_thumb_state.last_path == thumb_path and osc_thumb_state.last_x == thumb_x and osc_thumb_state.last_y == thumb_y) then
local overlay_add_args = {
"overlay-add", osc_thumb_state.overlay_id,
thumb_x, thumb_y,
thumb_path,
0,
"bgra",
thumb_size.w, thumb_size.h,
4 * thumb_size.w
}
mp.command_native(overlay_add_args)

osc_thumb_state.last_path = thumb_path
osc_thumb_state.last_x = thumb_x
osc_thumb_state.last_y = thumb_y
end
end
end
end

-- // mpv_thumbnail_script.lua // --

--
-- Parameters
--
@@ -148,7 +61,11 @@ if user_opts.hidetimeout < 0 then
msg.warn("hidetimeout cannot be negative. Using " .. user_opts.hidetimeout)
end


-- mpv_thumbnail_script.lua --

Thumbnailer:register_client()

function get_thumbnail_y_offset(thumb_size, msy)
local layout = user_opts.layout
local offset = 0
@@ -165,6 +82,130 @@ function get_thumbnail_y_offset(thumb_size, msy)

return offset / msy
end


local osc_thumb_state = {
visible = false,
overlay_id = 1,

last_path = nil,
last_x = nil,
last_y = nil,
}

function hide_thumbnail()
osc_thumb_state.visible = false
osc_thumb_state.last_path = nil
mp.command_native({ "overlay-remove", osc_thumb_state.overlay_id })
end

function display_thumbnail(pos, value, ass)
-- If thumbnails are not available, bail
if not (Thumbnailer.state.enabled and Thumbnailer.state.available) then
return
end

local duration = mp.get_property_number("duration", nil)
if not ((duration == nil) or (value == nil)) then
target_position = duration * (value / 100)

local msx, msy = get_virt_scale_factor()
local thumb_size = Thumbnailer.state.thumbnail_size
local thumb_path, thumb_index, closest_index = Thumbnailer:get_thumbnail_path(target_position)

local thumbs_ready = Thumbnailer.state.finished_thumbnails
local thumbs_total = Thumbnailer.state.thumbnail_count
local perc = math.floor((thumbs_ready / thumbs_total) * 100)

if thumbs_ready ~= thumbs_total then
local ass_w = thumb_size.w * msx
local ass_h = thumb_size.h * msy
local y_offset = get_thumbnail_y_offset(thumb_size, 1)

local bg_h = ass_h + 30 * msy
local bg_left = pos.x - ass_w/2
local framegraph_h = 10 * msy

local bg_top = nil
local text_top = nil
local framegraph_top = nil

if user_opts.layout == "topbar" then
bg_top = pos.y - ( y_offset + thumb_size.h )
text_top = bg_top + ass_h + framegraph_h
framegraph_top = bg_top + ass_h
else
bg_top = pos.y - y_offset - bg_h
text_top = bg_top
framegraph_top = bg_top + 20 * msy
end

-- Draw background
ass:new_event()
ass:pos(bg_left, bg_top)
ass:append(("{\\bord0\\1c&H000000&\\1a&H%X&"):format(80))
ass:draw_start()
-- ass:round_rect_cw(0, 0, ass_w, bg_h, 5)
ass:rect_cw(0, 0, ass_w, bg_h)
ass:draw_stop()

ass:new_event()
ass:pos(pos.x, text_top)
ass:an(8)
-- Scale text to correct size
ass:append(("{\\bord0\\fscx%f\\fscy%f}"):format(100*msx, 100*msy))
ass:append(("%d%% - %d/%d"):format(perc, thumbs_ready, thumbs_total))

-- Draw the generation progress
local block_w = (thumb_size.w / thumbs_total) * msy
ass:new_event()
ass:pos(bg_left, framegraph_top)
ass:append(("{\\bord0\\1c&HFFFFFF&\\1a&H%X&"):format(0))
ass:draw_start(2)
for i in pairs(Thumbnailer.state.thumbnails) do
if i ~= closest_index then
ass:rect_cw(i*block_w, 0, (i+1)*block_w, framegraph_h)
end
end
ass:draw_stop()

if closest_index ~= nil then
ass:new_event()
ass:pos(bg_left, framegraph_top)
ass:append(("{\\bord0\\1c&H4444FF&\\1a&H%X&"):format(0))
ass:draw_start(2)
ass:rect_cw(closest_index*block_w, 0, (closest_index+1)*block_w, framegraph_h)
ass:draw_stop()
end
end

if thumb_path then
local overlay_y_offset = get_thumbnail_y_offset(thumb_size, msy)

local thumb_x = math.floor(pos.x / msx - thumb_size.w/2)
local thumb_y = math.floor(pos.y / msy - thumb_size.h - overlay_y_offset)

osc_thumb_state.visible = true
if not (osc_thumb_state.last_path == thumb_path and osc_thumb_state.last_x == thumb_x and osc_thumb_state.last_y == thumb_y) then
local overlay_add_args = {
"overlay-add", osc_thumb_state.overlay_id,
thumb_x, thumb_y,
thumb_path,
0,
"bgra",
thumb_size.w, thumb_size.h,
4 * thumb_size.w
}
mp.command_native(overlay_add_args)

osc_thumb_state.last_path = thumb_path
osc_thumb_state.last_x = thumb_x
osc_thumb_state.last_y = thumb_y
end
end
end
end

-- // mpv_thumbnail_script.lua // --


@@ -2404,13 +2445,20 @@ function enable_osc(enable)
end
end

-- Patched in --
-- mpv_thumbnail_script.lua --

local builtin_osc_enabled = mp.get_property_native('osc')
if builtin_osc_enabled then
msg.error("You must disable the built-in OSC with osc=no in your configuration!")
return
local err = "You must disable the built-in OSC with osc=no in your configuration!"
mp.osd_message(err, 5)
msg.error(err)

-- This may break, but since we can, let's try to just disable the builtin OSC.
mp.set_property_native('osc', false)
end
-- -- --

-- // mpv_thumbnail_script.lua // --


validate_user_opts()

86 changes: 70 additions & 16 deletions src/thumbnailer_server.lua
Original file line number Diff line number Diff line change
@@ -22,6 +22,7 @@ function create_thumbnail_ffmpeg(file_path, timestamp, size, output_path)
local ffmpeg_command = {
"ffmpeg",
"-loglevel", "quiet",
"-noaccurate_seek",
"-ss", format_time(timestamp, ":"),
"-i", file_path,

@@ -35,8 +36,7 @@ function create_thumbnail_ffmpeg(file_path, timestamp, size, output_path)

"-y", output_path
}
local ret = utils.subprocess({args=ffmpeg_command})
return ret
return utils.subprocess({args=ffmpeg_command})
end


@@ -61,9 +61,11 @@ function check_output(ret, output_path)
end


function generate_thumbnails()
function generate_thumbnails(from_keypress)
if not Thumbnailer.state.available then
-- print("Thumbnailer state not ready")
if from_keypress then
mp.osd_message("Nothing to thumbnail", 2)
end
return
end

@@ -95,43 +97,95 @@ function generate_thumbnails()

mp.commandv("script-message", "mpv_thumbnail_script-enabled")

for thumbnail_index = 0, thumbnail_count-1 do
local generate_thumbnail_for_index = function(thumbnail_index)
local thumbnail_path = file_template:format(thumbnail_index)
local timestamp = math.min(file_duration, thumbnail_index * thumbnail_delta)

if not path_exists(thumbnail_path) then
-- The expected size (raw BGRA image)
local thumbnail_raw_size = (thumbnail_size.w * thumbnail_size.h * 4)

local need_thumbnail_generation = false

-- Check if the thumbnail already exists and is the correct size
local thumbnail_file = io.open(thumbnail_path, "rb")
if thumbnail_file == nil then
need_thumbnail_generation = true
else
local existing_thumbnail_filesize = thumbnail_file:seek("end")
if existing_thumbnail_filesize ~= thumbnail_raw_size then
-- Size doesn't match, so (re)generate
msg.warn("Thumbnail", thumbnail_index, "did not match expected size, regenerating")
need_thumbnail_generation = true
end
thumbnail_file:close()
end

if need_thumbnail_generation then
local ret = thumbnail_func(file_path, timestamp, thumbnail_size, thumbnail_path)
local success = check_output(ret, thumbnail_path)

if success == nil then
-- Killed by us, changing files, ignore
return
return true
elseif not success then
-- Failure
mp.osd_message("Thumbnailing failed, check console for details", 3.5)
return
return true
end
end

-- Verify thumbnail size
-- Sometimes ffmpeg will output an empty file when seeking to a "bad" section (usually the end)
thumbnail_file = io.open(thumbnail_path, "rb")

-- Bail if we can't read the file (it should really exist by now, we checked this in check_output!)
if thumbnail_file == nil then
msg.error("Thumbnail suddenly disappeared!")
return true
end

mp.commandv("script-message", "mpv_thumbnail_script-ready", tostring(thumbnail_index+1), thumbnail_path)
-- Check the size of the generated file
local thumbnail_file_size = thumbnail_file:seek("end")
thumbnail_file:close()

-- Check if the file is big enough
local missing_bytes = math.max(0, thumbnail_raw_size - thumbnail_file_size)
if missing_bytes > 0 then
-- Pad the file if it's missing content (eg. ffmpeg seek to file end)
thumbnail_file = io.open(thumbnail_path, "ab")
thumbnail_file:write(string.rep(string.char(0) * missing_bytes))
thumbnail_file:close()
end

mp.commandv("script-message", "mpv_thumbnail_script-ready", tostring(thumbnail_index), thumbnail_path)
end

-- Keep track of which thumbnails we've checked during the passes (instead of proper math for no-overlap)
local generated_thumbnails = {}

-- Do several passes over the thumbnails with increasing frequency
for res = 6, 0, -1 do
local nth = (2^res)

for thumbnail_index = 0, thumbnail_count-1, nth do
if not generated_thumbnails[thumbnail_index] then
local bail = generate_thumbnail_for_index(thumbnail_index)
if bail then return end
generated_thumbnails[thumbnail_index] = true
end
end
end
end

-- function on_file_loaded()
-- if thumbnailer_options.autogenerate then
-- generate_thumbnails()
-- end
-- end
-- mp.observe_property("video-dec-params", "native", on_file_loaded)

function on_script_keypress()
mp.osd_message("Starting thumbnail generation", 2)
generate_thumbnails()
generate_thumbnails(true)
mp.osd_message("All thumbnails generated", 2)
end

-- Set up listeners and keybinds

mp.register_script_message("mpv_thumbnail_script-generate", generate_thumbnails)

local thumb_script_key = not thumbnailer_options.disable_keybinds and "T" or nil
65 changes: 50 additions & 15 deletions src/thumbnailer_shared.lua
Original file line number Diff line number Diff line change
@@ -13,7 +13,8 @@ local Thumbnailer = {

thumbnail_size = nil,

finished_thumbnails = 0
finished_thumbnails = 0,
thumbnails = {}
}
}

@@ -22,6 +23,7 @@ function Thumbnailer:clear_state()
self.state.ready = false
self.state.available = false
self.state.finished_thumbnails = 0
self.state.thumbnails = {}
end


@@ -30,8 +32,12 @@ function Thumbnailer:on_file_loaded()
end

function Thumbnailer:on_thumb_ready(index)
if index > self.state.finished_thumbnails then
self.state.finished_thumbnails = index
self.state.thumbnails[index] = true

-- Recount (just in case)
self.state.finished_thumbnails = 0
for i in pairs(self.state.thumbnails) do
self.state.finished_thumbnails = self.state.finished_thumbnails + 1
end
end

@@ -55,7 +61,18 @@ function Thumbnailer:update_state()
self.state.ready = true

self.state.available = false
if self.state.thumbnail_delta ~= nil and self.state.thumbnail_size ~= nil and self.state.thumbnail_count > 0 then

-- Make sure the file has video (and not just albumart)
local track_list = mp.get_property_native("track-list")
local has_video = false
for i, track in pairs(track_list) do
if track.type == "video" and not track.external and not track.albumart then
has_video = true
break
end
end

if has_video and self.state.thumbnail_delta ~= nil and self.state.thumbnail_size ~= nil and self.state.thumbnail_count > 0 then
self.state.available = true
end

@@ -101,7 +118,6 @@ function Thumbnailer:get_delta()

local target_delta = (file_duration / thumbnailer_options.thumbnail_count)
local delta = math.max(thumbnailer_options.min_delta, math.min(thumbnailer_options.max_delta, target_delta))
-- print("DELTA:", target_delta, delta)

return delta
end
@@ -114,33 +130,52 @@ function Thumbnailer:get_thumbnail_count()
end
local file_duration = mp.get_property_native("duration")

return math.floor(file_duration / delta) + 1
return math.floor(file_duration / delta)
end

function Thumbnailer:get_closest(thumbnail_index)
local min_distance = self.state.thumbnail_count+1
local closest = nil

for index, value in pairs(self.state.thumbnails) do
local distance = math.abs(index - thumbnail_index)
if distance < min_distance then
min_distance = distance
closest = index
end
end
return closest, min_distance
end

function Thumbnailer:get_thumbnail_path(time_position)
local thumbnail_index = math.min(math.floor(time_position / self.state.thumbnail_delta), self.state.thumbnail_count-1)

if thumbnail_index < self.state.finished_thumbnails then
return self.state.thubmnail_template:format(thumbnail_index), thumbnail_index
local closest, distance = self:get_closest(thumbnail_index)

if closest ~= nil then
return self.state.thubmnail_template:format(closest), thumbnail_index, closest
else
return nil, thumbnail_index
return nil, thumbnail_index, nil
end
end

function Thumbnailer:register_client()
mp.register_script_message("mpv_thumbnail_script-ready", function(index, path) self:on_thumb_ready(tonumber(index), path) end)
-- For when autogenerate is off
-- Wait for server to tell us we're live
mp.register_script_message("mpv_thumbnail_script-enabled", function() self.state.enabled = true end)

-- Notify server to generate thumbnails
-- Notify server to generate thumbnails when video loads/changes
mp.observe_property("video-dec-params", "native", function()
if thumbnailer_options.autogenerate then
mp.commandv("script-message", "mpv_thumbnail_script-generate")
local duration = mp.get_property_native("duration")
local max_duration = thumbnailer_options.autogenerate_max_duration

if duration and thumbnailer_options.autogenerate then
-- Notify if autogenerate is on and video is not too long
if duration < max_duration or max_duration == 0 then
mp.commandv("script-message", "mpv_thumbnail_script-generate")
end
end
end)
end

-- mp.register_event("file-loaded", function() Thumbnailer:on_file_loaded() end)
mp.observe_property("video-dec-params", "native", function(name, params) Thumbnailer:on_video_change(params) end)

5 changes: 5 additions & 0 deletions src/version.tmpl.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
--[[
mpv_thumbnail_script.lua {version} - commit {commit_short} (branch {branch})
https://github.com/TheAMM/mpv_thumbnail_script
Built on {utc_now:%Y-%m-%d %H:%M:%S}
]]--
1 change: 1 addition & 0 deletions version.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
0.1.0

0 comments on commit 7074706

Please sign in to comment.