key_binding = 'F12'
-- save probed files for future reference -- ${fname} \t ${duration}
save_probed = true
saved_probed_filename = '~/.config/mpv/scripts/total_playtime.list'

-----------------------------------

saved_probed_filename = saved_probed_filename:gsub('~', os.getenv('HOME'))

local utils = require 'mp.utils'

function disp_time(time)
	local hours = math.floor(time/3600)
	local minutes = math.floor((time % 3600)/60)
	local seconds = math.floor(time % 60)

	return string.format("%02d:%02d:%02d", hours, minutes, seconds)
end

function setContains(set, key)
	return set[key] ~= nil
end
playlist = {}
playlist_total = -1

function total_time()
	if #playlist ~= playlist_total then
		if save_probed then
			if io.open(saved_probed_filename, "rb") then
				probed_file = {}
				for line in io.lines(saved_probed_filename) do
					for k, v in line:gmatch("(.+)\t(.+)") do
						probed_file[k] = v
					end
				end
			else
				probed_file = {}
			end
		end

		local cwd = utils.getcwd()
		for pl_num, f in ipairs(mp.get_property_native("playlist")) do
			f = utils.join_path(cwd, f.filename)
			-- attempt basic path normalization
			if on_windows then
				f = string.gsub(f, "\\", "/")
			end
			f = string.gsub(f, "/%./", "/")
			local n
			repeat
				f, n = string.gsub(f, "/[^/]*/%.%./", "/", 1)
			until n == 0

			f = string.gsub(f, "\"", "\\\"")

			if probed_file[f] then
				fprobe = probed_file[f]
			else
				fprobe = io.popen('ffprobe -v quiet -of csv=p=0 -show_entries format=duration "'.. f .. '"'):read()

				if fprobe and save_probed then
					file = io.open(saved_probed_filename, "a")
					file:write(f .. '\t' .. fprobe .."\n")
					file:close()
				end
			end

			playlist[#playlist + 1] = { f, tonumber(fprobe), pl_num }

			mp.osd_message(string.format("Calculating: %s/%s", #playlist, mp.get_property("playlist-count")))
		end
		playlist_total = #playlist
	end

	total_dur = 0
	played_dur = mp.get_property_number("time-pos")
	current_pos = mp.get_property_number("playlist-pos-1", 0)

	for i, fn in pairs(playlist) do
		if fn[2] ~= nil then
			total_dur = total_dur + fn[2]
			if i < current_pos then
				played_dur = played_dur + fn[2]
			end
		end
	end

	mp.osd_message(string.format("%s/%s (%s%%) \n %s/%s", disp_time(played_dur), disp_time(total_dur), math.floor(played_dur*100/total_dur), mp.get_property("playlist-pos-1"), mp.get_property("playlist-count")))
end

mp.add_forced_key_binding(key_binding, "total_time", total_time)

--------------------------------------------------
--------------------------------------------------
--------------------------------------------------

function sort_playlist_to_0()
	sort_playlist(1)
end

reverse = 0
function sort_playlist(start_0)
	total_time()

	table.sort(playlist, function (left, right)
		if reverse == 0 then
			return left[2] < right[2]
		else
			return left[2] > right[2]
		end
	end)

	if reverse == 0 then
		reverse = 1
	else
		reverse = 0
	end

	out = ''

	for i, f in pairs(playlist) do
		if f[2] ~= nil then
			for i2, f2 in ipairs(mp.get_property_native("playlist")) do
				if f2.filename == f[1] then
					mp.commandv('playlist-move', i2 - 1, i - 1)

					if f2.filename == mp.get_property("path") then
						-- out = string.format('%s>>%s\t\t%s\n', out, disp_time(f[2]), f[1]:gsub('.+/', ''))
						out = string.format('%s%s\t\t%s\n', out, disp_time(f[2]), f[1]:gsub('.+/', ''))
					else
						out = string.format('%s%s\t\t%s\n', out, disp_time(f[2]), f[1]:gsub('.+/', ''))
					end
					break
				end
			end
		end
	end

	if start_0 ~= nil then
		mp.set_property('playlist-pos', 0)
		os.execute('sleep .1')
	end
	mp.osd_message(out, 3)
end

mp.add_forced_key_binding('KP4', "sort_playlist", sort_playlist)
mp.add_forced_key_binding('shift+KP4', "sort_playlist_to_0", sort_playlist_to_0)
