我习惯用VLC Player播放视频。它有个功能,如果电影看了一半,下次再打开时,会提示是否从上次中断的地方继续播放下去。但这个功能貌似不是很可靠。所以想自己搞个可靠的解决方案。
VLC Player可以用Lua写插件。Lua语言也是第一次用,经过不少时间的查找资料和调试,终于成功运行。
require 'common'function descriptor()return { title = "Monitor Position on Stop", shortcode = "mps", capabilities = { "input-listener", "playing-listener" } } endlocal file = nilfunction activate()local input = vlc.object.input() if not input thenvlc.msg.err("[Monitor Position]No input object2 available")returnendlocal filename = "C:\\Temp\\foo.txt"file, err = io.open(filename, "a+")if not file thenvlc.msg.err("Failed to open file: " .. (err or "unknown error"))returnendlocal lines = {}for line in file:lines() dotable.insert(lines, line)endfor i = #lines, 1, -1 dostartIdx, endIdx = string.find(lines[i], "|")if startIdx ~= nil and endIdx ~= nil thenclean_path = getFilePath()if clean_path == string.sub(lines[i], 1, startIdx - 1) thencommon.seek(tonumber(string.sub(lines[i], endIdx + 1)))breakendendend endfunction getFilePath()local input = vlc.object.input()if not input thenvlc.msg.err("[Monitor Position] No input available")return ""endlocal item = vlc.input.item()local uri = item:uri() or "unknown"local decoded_path = vlc.strings.decode_uri(uri) or "unknown"local clean_path = decoded_pathif decoded_path:match("^file:///") thenclean_path = decoded_path:sub(9):gsub("/", "\\") end return '"' .. clean_path .. '"' endfunction playing_changed()local input = vlc.object.input()if not input thenvlc.msg.err("[Monitor Position] No input available")returnendlocal state = vlc.var.get(input, "state") -- 4=stopped, 3=pausedvlc.msg.err("[Monitor Position] Playing state changed to: " .. state)if state == 4 or state == 3 then -- Stopped (or end-reached)local clean_path = getFilePath() local pos_us = vlc.var.get(input, "time") or 0local pos_sec = pos_us / 1000000local log_line = string.format('%s|%d\n\n', clean_path, pos_sec)if file thenfile:write(log_line)file:flush()endend endfunction meta_changed() endfunction input_changed() end
激活插件时,首先执行 activate 函数,从文件中读取记录,如果有和当前播放文件名相同的,则从记录的播放时间开始播放。当点击暂停按钮或者停止按钮或者关掉VLC Player时,就把当前的播放时间记录到文件里。
meta_changed() 和 input_changed() 两个函数是空的,作用是避免在日志文件里出现没必要的warning信息。调试语句都用vlc.msg.err而不用vlc.msg.info,目的是为了避免打开日志文件时,出现大量无关信息,影响阅读。当然,在调试完成,运行基本正常后,可以改成info。
但有个问题,这个插件不会自动激活,每次打开VLC Player后,都必须手工到View菜单下,找到插件,再点击激活。感觉很不方便。于是找自动激活的办法。
查找资料后,发现唯一的方法是通过Interface脚本实现。但是Interface脚本里,不能用上面的playing_changed函数,而只能用一个死循环,类似windows的消息循环来实现。感觉占用cpu,不是很满意。
花了不少时间,想了个办法,用autoit脚本去激活:
#include <Constants.au3> Opt("WinTitleMatchMode", $OPT_MATCHANY)$hWnd = _WinWaitActivate("- VLC media player","") $aPos = WinGetPos($hWnd) MouseClick("right", $aPos[0] + 100, $aPos[1] + $aPos[3] - 20) For $i = 1 to 10Send("{DOWN}") Next Send("{RIGHT}") For $i = 1 to 9Send("{DOWN}") Next Send("{ENTER}")Func _WinWaitActivate($title,$text,$timeout=0)WinWait($title,$text,$timeout)If Not WinActive($title,$text) Then WinActivate($title,$text)Return WinWaitActive($title,$text,$timeout) EndFunc
其中9这个数字是调试出来的,具体要循环几次,要看插件在菜单中的位置。
然后写个Interface脚本,就一行:
os.execute("C:\\autoit\\autoit3.exe C:\\autoit\\activateVlcExtension.au3")
然后在vlcrc文件(一般在C:\Users\<用户名>\AppData\Roaming\vlc目录下)里,找到
# Lua interface (string)
lua-intf=<Interface脚本名>
最后,打开VLC Player,点开Tools - Preference,勾选All,然后找到Main interfaces,点选Lua interpreter,保存。重新启动VLC Player,就可以了。