Advertisement
Guest User

webm.lua

a guest
Aug 25th, 2018
490
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 39.86 KB | None | 0 0
  1. -- This file was autogenerated, changes to the code should be made in webm.moon, and then compiled to Lua with moonc.
  2. local mp = require("mp")
  3. local assdraw = require("mp.assdraw")
  4. local msg = require("mp.msg")
  5. local utils = require("mp.utils")
  6. local mpopts = require("mp.options")
  7. local options = {
  8. -- Defaults to shift+w
  9. keybind = "W",
  10. -- If empty, saves on the same directory of the playing video.
  11. -- A starting "~" will be replaced by the home dir.
  12. output_directory = "",
  13. run_detached = false,
  14. -- Format string for the output file
  15. -- %f - Filename, with extension
  16. -- %F - Filename, without extension
  17. -- %T - Media title, if it exists, or filename, with extension (useful for some streams, such as YouTube).
  18. -- %s, %e - Start and end time, with milliseconds
  19. -- %S, %E - Start and time, without milliseconds
  20. -- %M - "-audio", if audio is enabled, empty otherwise
  21. output_format = "%F-[%s-%e]%M",
  22. -- Scale video to a certain height, keeping the aspect ratio. -1 disables it.
  23. scale_height = 720,
  24. -- Target filesize, in kB.
  25. -- target_filesize = 2999,
  26. target_filesize = 45000,
  27. -- If true, will use stricter flags to ensure the resulting file doesn't
  28. -- overshoot the target filesize. Not recommended, as constrained quality
  29. -- mode should work well, unless you're really having trouble hitting
  30. -- the target size.
  31. strict_filesize_constraint = false,
  32. strict_bitrate_multiplier = 0.95,
  33. -- In kilobits.
  34. strict_audio_bitrate = 96,
  35. video_codec = "libvpx",
  36. audio_codec = "libopus",
  37. twopass = false,
  38. -- Set the number of encoding threads, for codecs libvpx and libvpx-vp9
  39. libvpx_threads = 4,
  40. additional_flags = "",
  41. -- Useful for flags that may impact output filesize, such as crf, qmin, qmax etc
  42. -- Won't be applied when strict_filesize_constraint is on.
  43. non_strict_additional_flags = "--ovcopts-add=crf=18,quality=good",
  44. -- Only encode tracks that are actually playing
  45. only_active_tracks = true,
  46. output_extension = "webm",
  47. -- The font size used in the menu. Isn't used for the notifications (started encode, finished encode etc)
  48. font_size = 36,
  49. margin = 10,
  50. message_duration = 5
  51. }
  52. mpopts.read_options(options)
  53. local bold
  54. bold = function(text)
  55. return "{\\b1}" .. tostring(text) .. "{\\b0}"
  56. end
  57. local message
  58. message = function(text, duration)
  59. local ass = mp.get_property_osd("osd-ass-cc/0")
  60. ass = ass .. text
  61. return mp.osd_message(ass, duration or options.message_duration)
  62. end
  63. local append
  64. append = function(a, b)
  65. for _, val in ipairs(b) do
  66. a[#a + 1] = val
  67. end
  68. return a
  69. end
  70. local seconds_to_time_string
  71. seconds_to_time_string = function(seconds, no_ms, full)
  72. if seconds < 0 then
  73. return "unknown"
  74. end
  75. local ret = ""
  76. if not (no_ms) then
  77. ret = string.format(".%03d", seconds * 1000 % 1000)
  78. end
  79. ret = string.format("%02d:%02d%s", math.floor(seconds / 60) % 60, math.floor(seconds) % 60, ret)
  80. if full or seconds > 3600 then
  81. ret = string.format("%d:%s", math.floor(seconds / 3600), ret)
  82. end
  83. return ret
  84. end
  85. local seconds_to_path_element
  86. seconds_to_path_element = function(seconds, no_ms, full)
  87. local time_string = seconds_to_time_string(seconds, no_ms, full)
  88. local _
  89. time_string, _ = time_string:gsub(":", "_")
  90. return time_string
  91. end
  92. local file_exists
  93. file_exists = function(name)
  94. local f = io.open(name, "r")
  95. if f ~= nil then
  96. io.close(f)
  97. return true
  98. end
  99. return false
  100. end
  101. local format_filename
  102. format_filename = function(startTime, endTime)
  103. local replaceTable = {
  104. ["%%f"] = mp.get_property("filename"),
  105. ["%%F"] = mp.get_property("filename/no-ext"),
  106. ["%%s"] = seconds_to_path_element(startTime),
  107. ["%%S"] = seconds_to_path_element(startTime, true),
  108. ["%%e"] = seconds_to_path_element(endTime),
  109. ["%%E"] = seconds_to_path_element(endTime, true),
  110. ["%%T"] = mp.get_property("media-title"),
  111. ["%%M"] = (mp.get_property_native('aid') and not mp.get_property_native('mute')) and '-audio' or ''
  112. }
  113. local filename = options.output_format
  114. for format, value in pairs(replaceTable) do
  115. local _
  116. filename, _ = filename:gsub(format, value)
  117. end
  118. local _
  119. filename, _ = filename:gsub("[<>:\"/\\|?*]", "")
  120. return tostring(filename) .. "." .. tostring(options.output_extension)
  121. end
  122. local parse_directory
  123. parse_directory = function(dir)
  124. local home_dir = os.getenv("HOME")
  125. if not home_dir then
  126. home_dir = os.getenv("USERPROFILE")
  127. end
  128. if not home_dir then
  129. local drive = os.getenv("HOMEDRIVE")
  130. local path = os.getenv("HOMEPATH")
  131. if drive and path then
  132. home_dir = utils.join_path(drive, path)
  133. else
  134. msg.warn("Couldn't find home dir.")
  135. home_dir = ""
  136. end
  137. end
  138. local _
  139. dir, _ = dir:gsub("^~", home_dir)
  140. return dir
  141. end
  142. local get_null_path
  143. get_null_path = function()
  144. if file_exists("/dev/null") then
  145. return "/dev/null"
  146. end
  147. return "NUL"
  148. end
  149. local dimensions_changed = true
  150. local _video_dimensions = { }
  151. local get_video_dimensions
  152. get_video_dimensions = function()
  153. if not (dimensions_changed) then
  154. return _video_dimensions
  155. end
  156. local video_params = mp.get_property_native("video-out-params")
  157. if not video_params then
  158. return nil
  159. end
  160. dimensions_changed = false
  161. local keep_aspect = mp.get_property_bool("keepaspect")
  162. local w = video_params["w"]
  163. local h = video_params["h"]
  164. local dw = video_params["dw"]
  165. local dh = video_params["dh"]
  166. if mp.get_property_number("video-rotate") % 180 == 90 then
  167. w, h = h, w
  168. dw, dh = dh, dw
  169. end
  170. _video_dimensions = {
  171. top_left = { },
  172. bottom_right = { },
  173. ratios = { }
  174. }
  175. local window_w, window_h = mp.get_osd_size()
  176. if keep_aspect then
  177. local unscaled = mp.get_property_native("video-unscaled")
  178. local panscan = mp.get_property_number("panscan")
  179. local fwidth = window_w
  180. local fheight = math.floor(window_w / dw * dh)
  181. if fheight > window_h or fheight < h then
  182. local tmpw = math.floor(window_h / dh * dw)
  183. if tmpw <= window_w then
  184. fheight = window_h
  185. fwidth = tmpw
  186. end
  187. end
  188. local vo_panscan_area = window_h - fheight
  189. local f_w = fwidth / fheight
  190. local f_h = 1
  191. if vo_panscan_area == 0 then
  192. vo_panscan_area = window_h - fwidth
  193. f_w = 1
  194. f_h = fheight / fwidth
  195. end
  196. if unscaled or unscaled == "downscale-big" then
  197. vo_panscan_area = 0
  198. if unscaled or (dw <= window_w and dh <= window_h) then
  199. fwidth = dw
  200. fheight = dh
  201. end
  202. end
  203. local scaled_width = fwidth + math.floor(vo_panscan_area * panscan * f_w)
  204. local scaled_height = fheight + math.floor(vo_panscan_area * panscan * f_h)
  205. local split_scaling
  206. split_scaling = function(dst_size, scaled_src_size, zoom, align, pan)
  207. scaled_src_size = math.floor(scaled_src_size * 2 ^ zoom)
  208. align = (align + 1) / 2
  209. local dst_start = math.floor((dst_size - scaled_src_size) * align + pan * scaled_src_size)
  210. if dst_start < 0 then
  211. dst_start = dst_start + 1
  212. end
  213. local dst_end = dst_start + scaled_src_size
  214. if dst_start >= dst_end then
  215. dst_start = 0
  216. dst_end = 1
  217. end
  218. return dst_start, dst_end
  219. end
  220. local zoom = mp.get_property_number("video-zoom")
  221. local align_x = mp.get_property_number("video-align-x")
  222. local pan_x = mp.get_property_number("video-pan-x")
  223. _video_dimensions.top_left.x, _video_dimensions.bottom_right.x = split_scaling(window_w, scaled_width, zoom, align_x, pan_x)
  224. local align_y = mp.get_property_number("video-align-y")
  225. local pan_y = mp.get_property_number("video-pan-y")
  226. _video_dimensions.top_left.y, _video_dimensions.bottom_right.y = split_scaling(window_h, scaled_height, zoom, align_y, pan_y)
  227. else
  228. _video_dimensions.top_left.x = 0
  229. _video_dimensions.bottom_right.x = window_w
  230. _video_dimensions.top_left.y = 0
  231. _video_dimensions.bottom_right.y = window_h
  232. end
  233. _video_dimensions.ratios.w = w / (_video_dimensions.bottom_right.x - _video_dimensions.top_left.x)
  234. _video_dimensions.ratios.h = h / (_video_dimensions.bottom_right.y - _video_dimensions.top_left.y)
  235. return _video_dimensions
  236. end
  237. local set_dimensions_changed
  238. set_dimensions_changed = function()
  239. dimensions_changed = true
  240. end
  241. local clamp
  242. clamp = function(min, val, max)
  243. if val <= min then
  244. return min
  245. end
  246. if val >= max then
  247. return max
  248. end
  249. return val
  250. end
  251. local clamp_point
  252. clamp_point = function(top_left, point, bottom_right)
  253. return {
  254. x = clamp(top_left.x, point.x, bottom_right.x),
  255. y = clamp(top_left.y, point.y, bottom_right.y)
  256. }
  257. end
  258. local VideoPoint
  259. do
  260. local _class_0
  261. local _base_0 = {
  262. set_from_screen = function(self, sx, sy)
  263. local d = get_video_dimensions()
  264. local point = clamp_point(d.top_left, {
  265. x = sx,
  266. y = sy
  267. }, d.bottom_right)
  268. self.x = math.floor(d.ratios.w * (point.x - d.top_left.x) + 0.5)
  269. self.y = math.floor(d.ratios.h * (point.y - d.top_left.y) + 0.5)
  270. end,
  271. to_screen = function(self)
  272. local d = get_video_dimensions()
  273. return {
  274. x = math.floor(self.x / d.ratios.w + d.top_left.x + 0.5),
  275. y = math.floor(self.y / d.ratios.h + d.top_left.y + 0.5)
  276. }
  277. end
  278. }
  279. _base_0.__index = _base_0
  280. _class_0 = setmetatable({
  281. __init = function(self)
  282. self.x = -1
  283. self.y = -1
  284. end,
  285. __base = _base_0,
  286. __name = "VideoPoint"
  287. }, {
  288. __index = _base_0,
  289. __call = function(cls, ...)
  290. local _self_0 = setmetatable({}, _base_0)
  291. cls.__init(_self_0, ...)
  292. return _self_0
  293. end
  294. })
  295. _base_0.__class = _class_0
  296. VideoPoint = _class_0
  297. end
  298. local Region
  299. do
  300. local _class_0
  301. local _base_0 = {
  302. is_valid = function(self)
  303. return self.x > -1 and self.y > -1 and self.w > -1 and self.h > -1
  304. end,
  305. set_from_points = function(self, p1, p2)
  306. self.x = math.min(p1.x, p2.x)
  307. self.y = math.min(p1.y, p2.y)
  308. self.w = math.abs(p1.x - p2.x)
  309. self.h = math.abs(p1.y - p2.y)
  310. end
  311. }
  312. _base_0.__index = _base_0
  313. _class_0 = setmetatable({
  314. __init = function(self)
  315. self.x = -1
  316. self.y = -1
  317. self.w = -1
  318. self.h = -1
  319. end,
  320. __base = _base_0,
  321. __name = "Region"
  322. }, {
  323. __index = _base_0,
  324. __call = function(cls, ...)
  325. local _self_0 = setmetatable({}, _base_0)
  326. cls.__init(_self_0, ...)
  327. return _self_0
  328. end
  329. })
  330. _base_0.__class = _class_0
  331. Region = _class_0
  332. end
  333. local get_active_tracks
  334. get_active_tracks = function()
  335. local accepted = {
  336. video = true,
  337. audio = not mp.get_property_bool("mute"),
  338. sub = mp.get_property_bool("sub-visibility")
  339. }
  340. local active = { }
  341. for _, track in ipairs(mp.get_property_native("track-list")) do
  342. if track["selected"] and accepted[track["type"]] then
  343. active[#active + 1] = track
  344. end
  345. end
  346. return active
  347. end
  348. local get_color_conversion_filters
  349. get_color_conversion_filters = function()
  350. local colormatrixFilter = {
  351. ["bt.709"] = "bt709",
  352. ["bt.2020"] = "bt2020"
  353. }
  354. local ret = { }
  355. local colormatrix = mp.get_property_native("video-params/colormatrix")
  356. if options.video_codec == "libvpx" and colormatrixFilter[colormatrix] then
  357. append(ret, {
  358. "colormatrix=" .. tostring(colormatrixFilter[colormatrix]) .. ":bt601"
  359. })
  360. end
  361. return ret
  362. end
  363. local get_scale_filters
  364. get_scale_filters = function()
  365. if options.scale_height > 0 then
  366. return {
  367. "scale=-1:" .. tostring(options.scale_height)
  368. }
  369. end
  370. return { }
  371. end
  372. local get_playback_options
  373. get_playback_options = function()
  374. local ret = { }
  375. local sub_ass_force_style = mp.get_property("sub-ass-force-style")
  376. if sub_ass_force_style and sub_ass_force_style ~= "" then
  377. append(ret, {
  378. "--sub-ass-force-style",
  379. sub_ass_force_style
  380. })
  381. end
  382. return ret
  383. end
  384. local encode
  385. encode = function(region, startTime, endTime)
  386. local path = mp.get_property("path")
  387. if not path then
  388. message("No file is being played")
  389. return
  390. end
  391. local is_stream = not file_exists(path)
  392. local command = {
  393. "mpv",
  394. path,
  395. "--start=" .. seconds_to_time_string(startTime, false, true),
  396. "--end=" .. seconds_to_time_string(endTime, false, true),
  397. "--ovc=" .. tostring(options.video_codec),
  398. "--oac=" .. tostring(options.audio_codec)
  399. }
  400. local vid = -1
  401. local aid = -1
  402. local sid = -1
  403. if options.only_active_tracks then
  404. for _, track in ipairs(get_active_tracks()) do
  405. local _exp_0 = track["type"]
  406. if "video" == _exp_0 then
  407. vid = track['id']
  408. elseif "audio" == _exp_0 then
  409. aid = track['id']
  410. elseif "sub" == _exp_0 then
  411. sid = track['id']
  412. end
  413. end
  414. end
  415. append(command, {
  416. "--vid=" .. (vid >= 0 and tostring(vid) or "no"),
  417. "--aid=" .. (aid >= 0 and tostring(aid) or "no"),
  418. "--sid=" .. (sid >= 0 and tostring(sid) or "no")
  419. })
  420. append(command, get_playback_options())
  421. local filters = { }
  422. append(filters, get_color_conversion_filters())
  423. if region and region:is_valid() then
  424. append(filters, {
  425. "crop=" .. tostring(region.w) .. ":" .. tostring(region.h) .. ":" .. tostring(region.x) .. ":" .. tostring(region.y)
  426. })
  427. end
  428. append(filters, get_scale_filters())
  429. if #filters > 0 then
  430. append(command, {
  431. "--vf",
  432. "lavfi=[" .. tostring(table.concat(filters, ',')) .. "]"
  433. })
  434. end
  435. if options.video_codec == "libvpx" or options.audio_codec == "libvpx-vp9" then
  436. append(command, {
  437. "--ovcopts-add=threads=" .. tostring(options.libvpx_threads)
  438. })
  439. end
  440. if options.target_filesize > 0 then
  441. local dT = endTime - startTime
  442. if options.strict_filesize_constraint then
  443. local video_kilobits = options.target_filesize * 8
  444. if aid >= 0 then
  445. video_kilobits = video_kilobits - dT * options.strict_audio_bitrate
  446. append(command, {
  447. "--oacopts-add=b=" .. tostring(options.strict_audio_bitrate) .. "k"
  448. })
  449. end
  450. video_kilobits = video_kilobits * options.strict_bitrate_multiplier
  451. local bitrate = math.floor(video_kilobits / dT)
  452. append(command, {
  453. "--ovcopts-add=b=" .. tostring(bitrate) .. "k",
  454. "--ovcopts-add=minrate=" .. tostring(bitrate) .. "k",
  455. "--ovcopts-add=maxrate=" .. tostring(bitrate) .. "k"
  456. })
  457. else
  458. local bitrate = math.floor(options.target_filesize * 8 / dT)
  459. append(command, {
  460. "--ovcopts-add=b=" .. tostring(bitrate) .. "k"
  461. })
  462. end
  463. end
  464. for token in string.gmatch(options.additional_flags, "[^%s]+") do
  465. command[#command + 1] = token
  466. end
  467. if not options.strict_filesize_constraint then
  468. for token in string.gmatch(options.non_strict_additional_flags, "[^%s]+") do
  469. command[#command + 1] = token
  470. end
  471. end
  472. if options.twopass and not is_stream then
  473. local first_pass_cmdline
  474. do
  475. local _accum_0 = { }
  476. local _len_0 = 1
  477. for _index_0 = 1, #command do
  478. local arg = command[_index_0]
  479. _accum_0[_len_0] = arg
  480. _len_0 = _len_0 + 1
  481. end
  482. first_pass_cmdline = _accum_0
  483. end
  484. append(first_pass_cmdline, {
  485. "--ovcopts-add=flags=+pass1",
  486. "-of=" .. tostring(options.output_extension),
  487. "-o=" .. tostring(get_null_path())
  488. })
  489. message("Starting first pass...")
  490. msg.verbose("First-pass command line: ", table.concat(first_pass_cmdline, " "))
  491. local res = utils.subprocess({
  492. args = first_pass_cmdline,
  493. cancellable = false
  494. })
  495. if res.status ~= 0 then
  496. message("First pass failed! Check the logs for details.")
  497. return
  498. end
  499. append(command, {
  500. "--ovcopts-add=flags=+pass2"
  501. })
  502. end
  503. local dir = ""
  504. if is_stream then
  505. dir = parse_directory("~")
  506. else
  507. local _
  508. dir, _ = utils.split_path(path)
  509. end
  510. if options.output_directory ~= "" then
  511. dir = parse_directory(options.output_directory)
  512. end
  513. local formatted_filename = format_filename(startTime, endTime)
  514. local out_path = utils.join_path(dir, formatted_filename)
  515. append(command, {
  516. "-o=" .. tostring(out_path)
  517. })
  518. msg.info("Encoding to", out_path)
  519. msg.verbose("Command line:", table.concat(command, " "))
  520. if options.run_detached then
  521. message("Started encode, process was detached.")
  522. return utils.subprocess_detached({
  523. args = command
  524. })
  525. else
  526. message("Started encode...")
  527. local res = utils.subprocess({
  528. args = command,
  529. cancellable = false
  530. })
  531. if res.status == 0 then
  532. return message("Encoded successfully! Saved to\\N" .. tostring(bold(out_path)))
  533. else
  534. return message("Encode failed! Check the logs for details.")
  535. end
  536. end
  537. end
  538. local Page
  539. do
  540. local _class_0
  541. local _base_0 = {
  542. add_keybinds = function(self)
  543. for key, func in pairs(self.keybinds) do
  544. mp.add_forced_key_binding(key, key, func, {
  545. repeatable = true
  546. })
  547. end
  548. end,
  549. remove_keybinds = function(self)
  550. for key, _ in pairs(self.keybinds) do
  551. mp.remove_key_binding(key)
  552. end
  553. end,
  554. clear = function(self)
  555. local window_w, window_h = mp.get_osd_size()
  556. mp.set_osd_ass(window_w, window_h, "")
  557. return mp.osd_message("", 0)
  558. end,
  559. prepare = function(self)
  560. return nil
  561. end,
  562. dispose = function(self)
  563. return nil
  564. end,
  565. show = function(self)
  566. self.visible = true
  567. self:add_keybinds()
  568. self:prepare()
  569. self:clear()
  570. return self:draw()
  571. end,
  572. hide = function(self)
  573. self.visible = false
  574. self:remove_keybinds()
  575. self:clear()
  576. return self:dispose()
  577. end,
  578. setup_text = function(self, ass)
  579. ass:pos(options.margin, options.margin)
  580. return ass:append("{\\fs" .. tostring(options.font_size) .. "}")
  581. end
  582. }
  583. _base_0.__index = _base_0
  584. _class_0 = setmetatable({
  585. __init = function() end,
  586. __base = _base_0,
  587. __name = "Page"
  588. }, {
  589. __index = _base_0,
  590. __call = function(cls, ...)
  591. local _self_0 = setmetatable({}, _base_0)
  592. cls.__init(_self_0, ...)
  593. return _self_0
  594. end
  595. })
  596. _base_0.__class = _class_0
  597. Page = _class_0
  598. end
  599. local CropPage
  600. do
  601. local _class_0
  602. local _parent_0 = Page
  603. local _base_0 = {
  604. reset = function(self)
  605. local dimensions = get_video_dimensions()
  606. local xa, ya
  607. do
  608. local _obj_0 = dimensions.top_left
  609. xa, ya = _obj_0.x, _obj_0.y
  610. end
  611. self.pointA:set_from_screen(xa, ya)
  612. local xb, yb
  613. do
  614. local _obj_0 = dimensions.bottom_right
  615. xb, yb = _obj_0.x, _obj_0.y
  616. end
  617. self.pointB:set_from_screen(xb, yb)
  618. if self.visible then
  619. return self:draw()
  620. end
  621. end,
  622. setPointA = function(self)
  623. local posX, posY = mp.get_mouse_pos()
  624. self.pointA:set_from_screen(posX, posY)
  625. if self.visible then
  626. return self:draw()
  627. end
  628. end,
  629. setPointB = function(self)
  630. local posX, posY = mp.get_mouse_pos()
  631. self.pointB:set_from_screen(posX, posY)
  632. if self.visible then
  633. return self:draw()
  634. end
  635. end,
  636. cancel = function(self)
  637. return self.callback(false, nil)
  638. end,
  639. finish = function(self)
  640. local region = Region()
  641. region:set_from_points(self.pointA, self.pointB)
  642. return self.callback(true, region)
  643. end,
  644. prepare = function(self)
  645. local properties = {
  646. "keepaspect",
  647. "video-out-params",
  648. "video-unscaled",
  649. "panscan",
  650. "video-zoom",
  651. "video-align-x",
  652. "video-pan-x",
  653. "video-align-y",
  654. "video-pan-y",
  655. "osd-width",
  656. "osd-height"
  657. }
  658. for _, p in ipairs(properties) do
  659. mp.observe_property(p, "native", set_dimensions_changed)
  660. end
  661. end,
  662. dispose = function(self)
  663. return mp.unobserve_property(set_dimensions_changed)
  664. end,
  665. draw_box = function(self, ass)
  666. local region = Region()
  667. region:set_from_points(self.pointA:to_screen(), self.pointB:to_screen())
  668. local d = get_video_dimensions()
  669. ass:new_event()
  670. ass:pos(0, 0)
  671. ass:append('{\\bord0}')
  672. ass:append('{\\shad0}')
  673. ass:append('{\\c&H000000&}')
  674. ass:append('{\\alpha&H77}')
  675. ass:draw_start()
  676. ass:rect_cw(d.top_left.x, d.top_left.y, region.x, region.y + region.h)
  677. ass:rect_cw(region.x, d.top_left.y, d.bottom_right.x, region.y)
  678. ass:rect_cw(d.top_left.x, region.y + region.h, region.x + region.w, d.bottom_right.y)
  679. ass:rect_cw(region.x + region.w, region.y, d.bottom_right.x, d.bottom_right.y)
  680. return ass:draw_stop()
  681. end,
  682. draw = function(self)
  683. local window = { }
  684. window.w, window.h = mp.get_osd_size()
  685. local ass = assdraw.ass_new()
  686. self:draw_box(ass)
  687. ass:new_event()
  688. self:setup_text(ass)
  689. ass:append(tostring(bold('Crop:')) .. "\\N")
  690. ass:append(tostring(bold('1:')) .. " change point A (" .. tostring(self.pointA.x) .. ", " .. tostring(self.pointA.y) .. ")\\N")
  691. ass:append(tostring(bold('2:')) .. " change point B (" .. tostring(self.pointB.x) .. ", " .. tostring(self.pointB.y) .. ")\\N")
  692. ass:append(tostring(bold('r:')) .. " reset to whole screen\\N")
  693. ass:append(tostring(bold('ESC:')) .. " cancel crop\\N")
  694. ass:append(tostring(bold('ENTER:')) .. " confirm crop\\N")
  695. return mp.set_osd_ass(window.w, window.h, ass.text)
  696. end
  697. }
  698. _base_0.__index = _base_0
  699. setmetatable(_base_0, _parent_0.__base)
  700. _class_0 = setmetatable({
  701. __init = function(self, callback, region)
  702. self.pointA = VideoPoint()
  703. self.pointB = VideoPoint()
  704. self.keybinds = {
  705. ["1"] = (function()
  706. local _base_1 = self
  707. local _fn_0 = _base_1.setPointA
  708. return function(...)
  709. return _fn_0(_base_1, ...)
  710. end
  711. end)(),
  712. ["2"] = (function()
  713. local _base_1 = self
  714. local _fn_0 = _base_1.setPointB
  715. return function(...)
  716. return _fn_0(_base_1, ...)
  717. end
  718. end)(),
  719. ["r"] = (function()
  720. local _base_1 = self
  721. local _fn_0 = _base_1.reset
  722. return function(...)
  723. return _fn_0(_base_1, ...)
  724. end
  725. end)(),
  726. ["ESC"] = (function()
  727. local _base_1 = self
  728. local _fn_0 = _base_1.cancel
  729. return function(...)
  730. return _fn_0(_base_1, ...)
  731. end
  732. end)(),
  733. ["ENTER"] = (function()
  734. local _base_1 = self
  735. local _fn_0 = _base_1.finish
  736. return function(...)
  737. return _fn_0(_base_1, ...)
  738. end
  739. end)()
  740. }
  741. self:reset()
  742. self.callback = callback
  743. if region and region:is_valid() then
  744. self.pointA.x = region.x
  745. self.pointA.y = region.y
  746. self.pointB.x = region.x + region.w
  747. self.pointB.y = region.y + region.h
  748. end
  749. end,
  750. __base = _base_0,
  751. __name = "CropPage",
  752. __parent = _parent_0
  753. }, {
  754. __index = function(cls, name)
  755. local val = rawget(_base_0, name)
  756. if val == nil then
  757. local parent = rawget(cls, "__parent")
  758. if parent then
  759. return parent[name]
  760. end
  761. else
  762. return val
  763. end
  764. end,
  765. __call = function(cls, ...)
  766. local _self_0 = setmetatable({}, _base_0)
  767. cls.__init(_self_0, ...)
  768. return _self_0
  769. end
  770. })
  771. _base_0.__class = _class_0
  772. if _parent_0.__inherited then
  773. _parent_0.__inherited(_parent_0, _class_0)
  774. end
  775. CropPage = _class_0
  776. end
  777. local Option
  778. do
  779. local _class_0
  780. local _base_0 = {
  781. leftKey = function(self)
  782. local _exp_0 = self.optType
  783. if "bool" == _exp_0 then
  784. self.value = not self.value
  785. elseif "list" == _exp_0 then
  786. if self.value > 1 then
  787. self.value = self.value - 1
  788. end
  789. end
  790. end,
  791. rightKey = function(self)
  792. local _exp_0 = self.optType
  793. if "bool" == _exp_0 then
  794. self.value = not self.value
  795. elseif "list" == _exp_0 then
  796. if self.value < #self.possibleValues then
  797. self.value = self.value + 1
  798. end
  799. end
  800. end,
  801. getValue = function(self)
  802. local _exp_0 = self.optType
  803. if "bool" == _exp_0 then
  804. return self.value
  805. elseif "list" == _exp_0 then
  806. local value, _
  807. do
  808. local _obj_0 = self.possibleValues[self.value]
  809. value, _ = _obj_0[1], _obj_0[2]
  810. end
  811. return value
  812. end
  813. end,
  814. setValue = function(self, value)
  815. local _exp_0 = self.optType
  816. if "bool" == _exp_0 then
  817. self.value = value
  818. elseif "list" == _exp_0 then
  819. local set = false
  820. for i, possiblePair in ipairs(self.possibleValues) do
  821. local possibleValue, _
  822. possibleValue, _ = possiblePair[1], possiblePair[2]
  823. if possibleValue == value then
  824. set = true
  825. self.value = i
  826. break
  827. end
  828. end
  829. if not set then
  830. return msg.warn("Tried to set invalid value " .. tostring(value) .. " to " .. tostring(self.displayText) .. " option.")
  831. end
  832. end
  833. end,
  834. getDisplayValue = function(self)
  835. local _exp_0 = self.optType
  836. if "bool" == _exp_0 then
  837. return self.value and "yes" or "no"
  838. elseif "list" == _exp_0 then
  839. local value, displayValue
  840. do
  841. local _obj_0 = self.possibleValues[self.value]
  842. value, displayValue = _obj_0[1], _obj_0[2]
  843. end
  844. return displayValue or value
  845. end
  846. end,
  847. draw = function(self, ass, selected)
  848. if selected then
  849. ass:append(tostring(bold(self.displayText)) .. ": ")
  850. else
  851. ass:append(tostring(self.displayText) .. ": ")
  852. end
  853. if self.optType == "bool" or self.value > 1 then
  854. ass:append("ā—€ ")
  855. end
  856. ass:append(self:getDisplayValue())
  857. if self.optType == "bool" or self.value < #self.possibleValues then
  858. ass:append(" ā–¶")
  859. end
  860. return ass:append("\\N")
  861. end
  862. }
  863. _base_0.__index = _base_0
  864. _class_0 = setmetatable({
  865. __init = function(self, optType, displayText, value, possibleValues)
  866. self.optType = optType
  867. self.displayText = displayText
  868. self.possibleValues = possibleValues
  869. self.value = 1
  870. return self:setValue(value)
  871. end,
  872. __base = _base_0,
  873. __name = "Option"
  874. }, {
  875. __index = _base_0,
  876. __call = function(cls, ...)
  877. local _self_0 = setmetatable({}, _base_0)
  878. cls.__init(_self_0, ...)
  879. return _self_0
  880. end
  881. })
  882. _base_0.__class = _class_0
  883. Option = _class_0
  884. end
  885. local EncodeOptionsPage
  886. do
  887. local _class_0
  888. local _parent_0 = Page
  889. local _base_0 = {
  890. getCurrentOption = function(self)
  891. return self.options[self.currentOption][2]
  892. end,
  893. leftKey = function(self)
  894. (self:getCurrentOption()):leftKey()
  895. return self:draw()
  896. end,
  897. rightKey = function(self)
  898. (self:getCurrentOption()):rightKey()
  899. return self:draw()
  900. end,
  901. prevOpt = function(self)
  902. self.currentOption = math.max(1, self.currentOption - 1)
  903. return self:draw()
  904. end,
  905. nextOpt = function(self)
  906. self.currentOption = math.min(#self.options, self.currentOption + 1)
  907. return self:draw()
  908. end,
  909. confirmOpts = function(self)
  910. for _, optPair in ipairs(self.options) do
  911. local optName, opt
  912. optName, opt = optPair[1], optPair[2]
  913. options[optName] = opt:getValue()
  914. end
  915. self:hide()
  916. return self.callback(true)
  917. end,
  918. cancelOpts = function(self)
  919. self:hide()
  920. return self.callback(false)
  921. end,
  922. draw = function(self)
  923. local window_w, window_h = mp.get_osd_size()
  924. local ass = assdraw.ass_new()
  925. ass:new_event()
  926. self:setup_text(ass)
  927. ass:append(tostring(bold('Options:')) .. "\\N\\N")
  928. for i, optPair in ipairs(self.options) do
  929. local opt = optPair[2]
  930. opt:draw(ass, self.currentOption == i)
  931. end
  932. ass:append("\\Nā–² / ā–¼: navigate\\N")
  933. ass:append(tostring(bold('ENTER:')) .. " confirm options\\N")
  934. ass:append(tostring(bold('ESC:')) .. " cancel\\N")
  935. return mp.set_osd_ass(window_w, window_h, ass.text)
  936. end
  937. }
  938. _base_0.__index = _base_0
  939. setmetatable(_base_0, _parent_0.__base)
  940. _class_0 = setmetatable({
  941. __init = function(self, callback)
  942. self.callback = callback
  943. self.currentOption = 1
  944. local scaleHeightOpts = {
  945. {
  946. -1,
  947. "no"
  948. },
  949. {
  950. 360
  951. },
  952. {
  953. 480
  954. },
  955. {
  956. 520
  957. },
  958. {
  959. 576
  960. },
  961. {
  962. 640
  963. },
  964. {
  965. 720
  966. },
  967. {
  968. 800
  969. },
  970. {
  971. 1024
  972. },
  973. {
  974. 1080
  975. },
  976. {
  977. 1280
  978. },
  979. {
  980. 1440
  981. },
  982. {
  983. 2160
  984. },
  985. }
  986. self.options = {
  987. {
  988. "twopass",
  989. Option("bool", "Two Pass", options.twopass)
  990. },
  991. {
  992. "scale_height",
  993. Option("list", "Scale Height", options.scale_height, scaleHeightOpts)
  994. },
  995. {
  996. "strict_filesize_constraint",
  997. Option("bool", "Strict Filesize Constraint", options.strict_filesize_constraint)
  998. }
  999. }
  1000. self.keybinds = {
  1001. ["LEFT"] = (function()
  1002. local _base_1 = self
  1003. local _fn_0 = _base_1.leftKey
  1004. return function(...)
  1005. return _fn_0(_base_1, ...)
  1006. end
  1007. end)(),
  1008. ["RIGHT"] = (function()
  1009. local _base_1 = self
  1010. local _fn_0 = _base_1.rightKey
  1011. return function(...)
  1012. return _fn_0(_base_1, ...)
  1013. end
  1014. end)(),
  1015. ["UP"] = (function()
  1016. local _base_1 = self
  1017. local _fn_0 = _base_1.prevOpt
  1018. return function(...)
  1019. return _fn_0(_base_1, ...)
  1020. end
  1021. end)(),
  1022. ["DOWN"] = (function()
  1023. local _base_1 = self
  1024. local _fn_0 = _base_1.nextOpt
  1025. return function(...)
  1026. return _fn_0(_base_1, ...)
  1027. end
  1028. end)(),
  1029. ["ENTER"] = (function()
  1030. local _base_1 = self
  1031. local _fn_0 = _base_1.confirmOpts
  1032. return function(...)
  1033. return _fn_0(_base_1, ...)
  1034. end
  1035. end)(),
  1036. ["ESC"] = (function()
  1037. local _base_1 = self
  1038. local _fn_0 = _base_1.cancelOpts
  1039. return function(...)
  1040. return _fn_0(_base_1, ...)
  1041. end
  1042. end)()
  1043. }
  1044. end,
  1045. __base = _base_0,
  1046. __name = "EncodeOptionsPage",
  1047. __parent = _parent_0
  1048. }, {
  1049. __index = function(cls, name)
  1050. local val = rawget(_base_0, name)
  1051. if val == nil then
  1052. local parent = rawget(cls, "__parent")
  1053. if parent then
  1054. return parent[name]
  1055. end
  1056. else
  1057. return val
  1058. end
  1059. end,
  1060. __call = function(cls, ...)
  1061. local _self_0 = setmetatable({}, _base_0)
  1062. cls.__init(_self_0, ...)
  1063. return _self_0
  1064. end
  1065. })
  1066. _base_0.__class = _class_0
  1067. if _parent_0.__inherited then
  1068. _parent_0.__inherited(_parent_0, _class_0)
  1069. end
  1070. EncodeOptionsPage = _class_0
  1071. end
  1072. local PreviewPage
  1073. do
  1074. local _class_0
  1075. local _parent_0 = Page
  1076. local _base_0 = {
  1077. prepare = function(self)
  1078. local vf = mp.get_property_native("vf")
  1079. vf[#vf + 1] = {
  1080. name = "sub"
  1081. }
  1082. if self.region:is_valid() then
  1083. vf[#vf + 1] = {
  1084. name = "crop",
  1085. params = {
  1086. w = tostring(self.region.w),
  1087. h = tostring(self.region.h),
  1088. x = tostring(self.region.x),
  1089. y = tostring(self.region.y)
  1090. }
  1091. }
  1092. end
  1093. mp.set_property_native("vf", vf)
  1094. if self.startTime > -1 and self.endTime > -1 then
  1095. mp.set_property_native("ab-loop-a", self.startTime)
  1096. mp.set_property_native("ab-loop-b", self.endTime)
  1097. mp.set_property_native("time-pos", self.startTime)
  1098. end
  1099. return mp.set_property_native("pause", false)
  1100. end,
  1101. dispose = function(self)
  1102. mp.set_property("ab-loop-a", "no")
  1103. mp.set_property("ab-loop-b", "no")
  1104. for prop, value in pairs(self.originalProperties) do
  1105. mp.set_property_native(prop, value)
  1106. end
  1107. end,
  1108. draw = function(self)
  1109. local window_w, window_h = mp.get_osd_size()
  1110. local ass = assdraw.ass_new()
  1111. ass:new_event()
  1112. self:setup_text(ass)
  1113. ass:append("Press " .. tostring(bold('ESC')) .. " to exit preview.\\N")
  1114. return mp.set_osd_ass(window_w, window_h, ass.text)
  1115. end,
  1116. cancel = function(self)
  1117. self:hide()
  1118. return self.callback()
  1119. end
  1120. }
  1121. _base_0.__index = _base_0
  1122. setmetatable(_base_0, _parent_0.__base)
  1123. _class_0 = setmetatable({
  1124. __init = function(self, callback, region, startTime, endTime)
  1125. self.callback = callback
  1126. self.originalProperties = {
  1127. ["vf"] = mp.get_property_native("vf"),
  1128. ["time-pos"] = mp.get_property_native("time-pos"),
  1129. ["pause"] = mp.get_property_native("pause")
  1130. }
  1131. self.keybinds = {
  1132. ["ESC"] = (function()
  1133. local _base_1 = self
  1134. local _fn_0 = _base_1.cancel
  1135. return function(...)
  1136. return _fn_0(_base_1, ...)
  1137. end
  1138. end)()
  1139. }
  1140. self.region = region
  1141. self.startTime = startTime
  1142. self.endTime = endTime
  1143. self.isLoop = false
  1144. end,
  1145. __base = _base_0,
  1146. __name = "PreviewPage",
  1147. __parent = _parent_0
  1148. }, {
  1149. __index = function(cls, name)
  1150. local val = rawget(_base_0, name)
  1151. if val == nil then
  1152. local parent = rawget(cls, "__parent")
  1153. if parent then
  1154. return parent[name]
  1155. end
  1156. else
  1157. return val
  1158. end
  1159. end,
  1160. __call = function(cls, ...)
  1161. local _self_0 = setmetatable({}, _base_0)
  1162. cls.__init(_self_0, ...)
  1163. return _self_0
  1164. end
  1165. })
  1166. _base_0.__class = _class_0
  1167. if _parent_0.__inherited then
  1168. _parent_0.__inherited(_parent_0, _class_0)
  1169. end
  1170. PreviewPage = _class_0
  1171. end
  1172. local MainPage
  1173. do
  1174. local _class_0
  1175. local _parent_0 = Page
  1176. local _base_0 = {
  1177. setStartTime = function(self)
  1178. self.startTime = mp.get_property_number("time-pos")
  1179. if self.visible then
  1180. self:clear()
  1181. return self:draw()
  1182. end
  1183. end,
  1184. setEndTime = function(self)
  1185. self.endTime = mp.get_property_number("time-pos")
  1186. if self.visible then
  1187. self:clear()
  1188. return self:draw()
  1189. end
  1190. end,
  1191. draw = function(self)
  1192. local window_w, window_h = mp.get_osd_size()
  1193. local ass = assdraw.ass_new()
  1194. ass:new_event()
  1195. self:setup_text(ass)
  1196. ass:append(tostring(bold('WebM maker')) .. "\\N\\N")
  1197. ass:append(tostring(bold('c:')) .. " crop\\N")
  1198. ass:append(tostring(bold('1:')) .. " set start time (current is " .. tostring(seconds_to_time_string(self.startTime)) .. ")\\N")
  1199. ass:append(tostring(bold('2:')) .. " set end time (current is " .. tostring(seconds_to_time_string(self.endTime)) .. ")\\N")
  1200. ass:append(tostring(bold('o:')) .. " change encode options\\N")
  1201. ass:append(tostring(bold('p:')) .. " preview\\N")
  1202. ass:append(tostring(bold('e:')) .. " encode\\N\\N")
  1203. ass:append(tostring(bold('ESC:')) .. " close\\N")
  1204. return mp.set_osd_ass(window_w, window_h, ass.text)
  1205. end,
  1206. onUpdateCropRegion = function(self, updated, newRegion)
  1207. if updated then
  1208. self.region = newRegion
  1209. end
  1210. return self:show()
  1211. end,
  1212. crop = function(self)
  1213. self:hide()
  1214. local cropPage = CropPage((function()
  1215. local _base_1 = self
  1216. local _fn_0 = _base_1.onUpdateCropRegion
  1217. return function(...)
  1218. return _fn_0(_base_1, ...)
  1219. end
  1220. end)(), self.region)
  1221. return cropPage:show()
  1222. end,
  1223. onOptionsChanged = function(self, updated)
  1224. return self:show()
  1225. end,
  1226. changeOptions = function(self)
  1227. self:hide()
  1228. local encodeOptsPage = EncodeOptionsPage((function()
  1229. local _base_1 = self
  1230. local _fn_0 = _base_1.onOptionsChanged
  1231. return function(...)
  1232. return _fn_0(_base_1, ...)
  1233. end
  1234. end)())
  1235. return encodeOptsPage:show()
  1236. end,
  1237. onPreviewEnded = function(self)
  1238. return self:show()
  1239. end,
  1240. preview = function(self)
  1241. self:hide()
  1242. local previewPage = PreviewPage((function()
  1243. local _base_1 = self
  1244. local _fn_0 = _base_1.onPreviewEnded
  1245. return function(...)
  1246. return _fn_0(_base_1, ...)
  1247. end
  1248. end)(), self.region, self.startTime, self.endTime)
  1249. return previewPage:show()
  1250. end,
  1251. encode = function(self)
  1252. self:hide()
  1253. if self.startTime < 0 then
  1254. message("No start time, aborting")
  1255. return
  1256. end
  1257. if self.endTime < 0 then
  1258. message("No end time, aborting")
  1259. return
  1260. end
  1261. if self.startTime >= self.endTime then
  1262. message("Start time is ahead of end time, aborting")
  1263. return
  1264. end
  1265. return encode(self.region, self.startTime, self.endTime)
  1266. end
  1267. }
  1268. _base_0.__index = _base_0
  1269. setmetatable(_base_0, _parent_0.__base)
  1270. _class_0 = setmetatable({
  1271. __init = function(self)
  1272. self.keybinds = {
  1273. ["c"] = (function()
  1274. local _base_1 = self
  1275. local _fn_0 = _base_1.crop
  1276. return function(...)
  1277. return _fn_0(_base_1, ...)
  1278. end
  1279. end)(),
  1280. ["1"] = (function()
  1281. local _base_1 = self
  1282. local _fn_0 = _base_1.setStartTime
  1283. return function(...)
  1284. return _fn_0(_base_1, ...)
  1285. end
  1286. end)(),
  1287. ["2"] = (function()
  1288. local _base_1 = self
  1289. local _fn_0 = _base_1.setEndTime
  1290. return function(...)
  1291. return _fn_0(_base_1, ...)
  1292. end
  1293. end)(),
  1294. ["o"] = (function()
  1295. local _base_1 = self
  1296. local _fn_0 = _base_1.changeOptions
  1297. return function(...)
  1298. return _fn_0(_base_1, ...)
  1299. end
  1300. end)(),
  1301. ["p"] = (function()
  1302. local _base_1 = self
  1303. local _fn_0 = _base_1.preview
  1304. return function(...)
  1305. return _fn_0(_base_1, ...)
  1306. end
  1307. end)(),
  1308. ["e"] = (function()
  1309. local _base_1 = self
  1310. local _fn_0 = _base_1.encode
  1311. return function(...)
  1312. return _fn_0(_base_1, ...)
  1313. end
  1314. end)(),
  1315. ["ESC"] = (function()
  1316. local _base_1 = self
  1317. local _fn_0 = _base_1.hide
  1318. return function(...)
  1319. return _fn_0(_base_1, ...)
  1320. end
  1321. end)()
  1322. }
  1323. self.startTime = -1
  1324. self.endTime = -1
  1325. self.region = Region()
  1326. end,
  1327. __base = _base_0,
  1328. __name = "MainPage",
  1329. __parent = _parent_0
  1330. }, {
  1331. __index = function(cls, name)
  1332. local val = rawget(_base_0, name)
  1333. if val == nil then
  1334. local parent = rawget(cls, "__parent")
  1335. if parent then
  1336. return parent[name]
  1337. end
  1338. else
  1339. return val
  1340. end
  1341. end,
  1342. __call = function(cls, ...)
  1343. local _self_0 = setmetatable({}, _base_0)
  1344. cls.__init(_self_0, ...)
  1345. return _self_0
  1346. end
  1347. })
  1348. _base_0.__class = _class_0
  1349. if _parent_0.__inherited then
  1350. _parent_0.__inherited(_parent_0, _class_0)
  1351. end
  1352. MainPage = _class_0
  1353. end
  1354. local mainPage = MainPage()
  1355. return mp.add_key_binding(options.keybind, "display-webm-encoder", (function()
  1356. local _base_0 = mainPage
  1357. local _fn_0 = _base_0.show
  1358. return function(...)
  1359. return _fn_0(_base_0, ...)
  1360. end
  1361. end)(), {
  1362. repeatable = false
  1363. })
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement