-
Notifications
You must be signed in to change notification settings - Fork 24
/
bookmarker-menu.lua
708 lines (628 loc) · 22.9 KB
/
bookmarker-menu.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
-- // Bookmarker Menu v1.3.1 for mpv \\ --
-- See README.md for instructions
-- Maximum number of characters for bookmark name
local maxChar = 100
-- Number of bookmarks to be displayed per page
local bookmarksPerPage = 10
-- Whether to close the Bookmarker menu after loading a bookmark
local closeAfterLoad = true
-- Whether to close the Bookmarker menu after replacing a bookmark
local closeAfterReplace = true
-- Whether to ask for confirmation to replace a bookmark (Uses the Typer for confirmation)
local confirmReplace = false
-- Whether to ask for confirmation to delete a bookmark (Uses the Typer for confirmation)
local confirmDelete = false
-- The rate (in seconds) at which the bookmarker needs to refresh its interface; lower is more frequent
local rate = 1.5
-- The filename for the bookmarks file
local bookmarkerName = "bookmarker.json"
-- All the "global" variables and utilities; don't touch these
local utils = require 'mp.utils'
local styleOn = mp.get_property("osd-ass-cc/0")
local styleOff = mp.get_property("osd-ass-cc/1")
local bookmarks = {}
local currentSlot = 0
local currentPage = 1
local maxPage = 1
local active = false
local mode = "none"
local bookmarkStore = {}
local oldSlot = 0
-- // Controls \\ --
-- List of custom controls and their function
local bookmarkerControls = {
ESC = function() abort("") end,
DOWN = function() jumpSlot(1) end,
UP = function() jumpSlot(-1) end,
RIGHT = function() jumpPage(1) end,
LEFT = function() jumpPage(-1) end,
s = function() addBookmark() end,
S = function() mode="save" typerStart() end,
p = function() mode="replace" typerStart() end,
r = function() mode="rename" typerStart() end,
f = function() mode="filepath" typerStart() end,
m = function() mode="move" moverStart() end,
DEL = function() mode="delete" typerStart() end,
ENTER = function() jumpToBookmark(currentSlot) end,
KP_ENTER = function() jumpToBookmark(currentSlot) end
}
local bookmarkerFlags = {
DOWN = {repeatable = true},
UP = {repeatable = true},
RIGHT = {repeatable = true},
LEFT = {repeatable = true}
}
-- Activate the custom controls
function activateControls(name, controls, flags)
for key, func in pairs(controls) do
mp.add_forced_key_binding(key, name..key, func, flags[key])
end
end
-- Deactivate the custom controls
function deactivateControls(name, controls)
for key, _ in pairs(controls) do
mp.remove_key_binding(name..key)
end
end
-- // Typer \\ --
-- Controls for the Typer
local typerControls = {
ESC = function() typerExit() end,
ENTER = function() typerCommit() end,
KP_ENTER = function() typerCommit() end,
RIGHT = function() typerCursor(1) end,
LEFT = function() typerCursor(-1) end,
BS = function() typer("backspace") end,
DEL = function() typer("delete") end,
SPACE = function() typer(" ") end,
SHARP = function() typer("#") end,
KP0 = function() typer("0") end,
KP1 = function() typer("1") end,
KP2 = function() typer("2") end,
KP3 = function() typer("3") end,
KP4 = function() typer("4") end,
KP5 = function() typer("5") end,
KP6 = function() typer("6") end,
KP7 = function() typer("7") end,
KP8 = function() typer("8") end,
KP9 = function() typer("9") end,
KP_DEC = function() typer(".") end
}
-- All standard keys for the Typer
local typerKeys = {"a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","1","2","3","4","5","6","7","8","9","0","!","@","$","%","^","&","*","(",")","-","_","=","+","[","]","{","}","\\","|",";",":","'","\"",",",".","<",">","/","?","`","~"}
-- For some reason, semicolon is not possible, but it's listed there just in case anyway
local typerText = ""
local typerPos = 0
local typerActive = false
-- Function to activate the Typer
-- use typerStart() for custom controls around activating the Typer
function activateTyper()
for key, func in pairs(typerControls) do
mp.add_forced_key_binding(key, "typer"..key, func, {repeatable=true})
end
for i, key in ipairs(typerKeys) do
mp.add_forced_key_binding(key, "typer"..key, function() typer(key) end, {repeatable=true})
end
typerText = ""
typerActive = true
end
-- Function to deactivate the Typer
-- use typerExit() for custom controls around deactivating the Typer
function deactivateTyper()
for key, _ in pairs(typerControls) do
mp.remove_key_binding("typer"..key)
end
for i, key in ipairs(typerKeys) do
mp.remove_key_binding("typer"..key)
end
typerActive = false
return typerText
end
-- Function to move the cursor of the typer; can wrap around
function typerCursor(direction)
typerPos = typerPos + direction
if typerPos < 0 then typerPos = typerText:len() end
if typerPos > typerText:len() then typerPos = 0 end
typer("")
end
-- Function for handling the text as it is being typed
function typer(s)
-- Don't touch this part
if s == "backspace" then
if typerPos > 0 then
typerText = typerText:sub(1, typerPos - 1) .. typerText:sub(typerPos + 1)
typerPos = typerPos - 1
end
elseif s == "delete" then
if typerPos < typerText:len() then
typerText = typerText:sub(1, typerPos) .. typerText:sub(typerPos + 2)
end
else
if mode == "filepath" or typerText:len() < maxChar then
typerText = typerText:sub(1, typerPos) .. s .. typerText:sub(typerPos + 1)
typerPos = typerPos + s:len()
end
end
-- Enter custom script and display message here
local preMessage = "Enter a bookmark name:"
if mode == "save" then
preMessage = styleOn.."{\\b1}Save a new bookmark with custom name:{\\b0}"..styleOff
elseif mode == "replace" then
preMessage = styleOn.."{\\b1}Type \"y\" to replace the following bookmark:{\\b0}\n"..displayName(bookmarks[currentSlot]["name"])..styleOff
elseif mode == "delete" then
preMessage = styleOn.."{\\b1}Type \"y\" to delete the following bookmark:{\\b0}\n"..displayName(bookmarks[currentSlot]["name"])..styleOff
elseif mode == "rename" then
preMessage = styleOn.."{\\b1}Rename an existing bookmark:{\\b0}"..styleOff
elseif mode == "filepath" then
preMessage = styleOn.."{\\b1}Change the bookmark's filepath:{\\b0}"..styleOff
end
local postMessage = ""
local split = typerPos + math.floor(typerPos / maxChar)
local messageLines = math.floor((typerText:len() - 1) / maxChar) + 1
for i = 1, messageLines do
postMessage = postMessage .. typerText:sub((i-1) * maxChar + 1, i * maxChar) .. "\n"
end
postMessage = postMessage:sub(1,postMessage:len()-1)
mp.osd_message(preMessage.."\n"..postMessage:sub(1,split)..styleOn.."{\\c&H00FFFF&}{\\b1}|{\\r}"..styleOff..postMessage:sub(split+1), 9999)
end
-- // Mover \\ --
-- Controls for the Mover
local moverControls = {
ESC = function() moverExit() end,
DOWN = function() jumpSlot(1) end,
UP = function() jumpSlot(-1) end,
RIGHT = function() jumpPage(1) end,
LEFT = function() jumpPage(-1) end,
s = function() addBookmark() end,
m = function() moverCommit() end,
ENTER = function() moverCommit() end,
KP_ENTER = function() moverCommit() end
}
local moverFlags = {
DOWN = {repeatable = true},
UP = {repeatable = true},
RIGHT = {repeatable = true},
LEFT = {repeatable = true}
}
-- Function to activate the Mover
function moverStart()
if bookmarkExists(currentSlot) then
deactivateControls("bookmarker", bookmarkerControls)
activateControls("mover", moverControls, moverFlags)
displayBookmarks()
else
abort(styleOn.."{\\c&H0000FF&}{\\b1}Can't find the bookmark at slot "..currentSlot)
end
end
-- Function to commit the action of the Mover
function moverCommit()
saveBookmarks()
moverExit()
end
-- Function to deactivate the Mover
-- If isError is set, then it'll abort
function moverExit(isError)
deactivateControls("mover", moverControls)
mode = "none"
if not isError then
loadBookmarks()
displayBookmarks()
activateControls("bookmarker", bookmarkerControls, bookmarkerFlags)
end
end
-- // General utilities \\ --
-- Check if the operating system is Mac OS
function isMacOS()
local homedir = os.getenv("HOME")
return (homedir ~= nil and string.sub(homedir,1,6) == "/Users")
end
-- Check if the operating system is Windows
function isWindows()
local windir = os.getenv("windir")
return (windir~=nil)
end
-- Check whether a certain file exists
function fileExists(path)
local f = io.open(path,"r")
if f~=nil then
io.close(f)
return true
else
return false
end
end
-- Get the filepath of a file from the mpv config folder
function getFilepath(filename)
if isWindows() then
return os.getenv("APPDATA"):gsub("\\", "/") .. "/mpv/" .. filename
else
return os.getenv("HOME") .. "/.config/mpv/" .. filename
end
end
-- Load a table from a JSON file
-- Returns nil if the file can't be found
function loadTable(path)
local contents = ""
local myTable = {}
local file = io.open( path, "r" )
if file then
local contents = file:read( "*a" )
myTable = utils.parse_json(contents);
io.close(file)
return myTable
end
return nil
end
-- Save a table as a JSON file file
-- Returns true if successful
function saveTable(t, path)
local contents = utils.format_json(t)
local file = io.open(path .. ".tmp", "wb")
file:write(contents)
io.close(file)
os.remove(path)
os.rename(path .. ".tmp", path)
return true
end
-- Convert a pos (seconds) to a hh:mm:ss.mmm format
function parseTime(pos)
local hours = math.floor(pos/3600)
local minutes = math.floor((pos % 3600)/60)
local seconds = math.floor((pos % 60))
local milliseconds = math.floor(pos % 1 * 1000)
return string.format("%02d:%02d:%02d.%03d",hours,minutes,seconds,milliseconds)
end
-- // Bookmark functions \\ --
-- Checks whether the specified bookmark exists
function bookmarkExists(slot)
return (slot >= 1 and slot <= #bookmarks)
end
-- Calculates the current page and the total number of pages
function calcPages()
currentPage = math.floor((currentSlot - 1) / bookmarksPerPage) + 1
if currentPage == 0 then currentPage = 1 end
maxPage = math.floor((#bookmarks - 1) / bookmarksPerPage) + 1
if maxPage == 0 then maxPage = 1 end
end
-- Get the amount of bookmarks on the specified page
function getAmountBookmarksOnPage(page)
local n = bookmarksPerPage
if page == maxPage then n = #bookmarks % bookmarksPerPage end
if n == 0 then n = bookmarksPerPage end
if #bookmarks == 0 then n = 0 end
return n
end
-- Get the index of the first slot on the specified page
function getFirstSlotOnPage(page)
return (page - 1) * bookmarksPerPage + 1
end
-- Get the index of the last slot on the specified page
function getLastSlotOnPage(page)
local endSlot = getFirstSlotOnPage(page) + getAmountBookmarksOnPage(page) - 1
if endSlot > #bookmarks then endSlot = #bookmarks end
return endSlot
end
-- Jumps a certain amount of slots forward or backwards in the bookmarks list
-- Keeps in mind if the current mode is to move bookmarks
function jumpSlot(i)
if mode == "move" then
oldSlot = currentSlot
bookmarkStore = bookmarks[oldSlot]
end
currentSlot = currentSlot + i
local startSlot = getFirstSlotOnPage(currentPage)
local endSlot = getLastSlotOnPage(currentPage)
if currentSlot < startSlot then currentSlot = endSlot end
if currentSlot > endSlot then currentSlot = startSlot end
if mode == "move" then
table.remove(bookmarks, oldSlot)
table.insert(bookmarks, currentSlot, bookmarkStore)
end
displayBookmarks()
end
-- Jumps a certain amount of pages forward or backwards in the bookmarks list
-- Keeps in mind if the current mode is to move bookmarks
function jumpPage(i)
if mode == "move" then
oldSlot = currentSlot
bookmarkStore = bookmarks[oldSlot]
end
local oldPos = currentSlot - getFirstSlotOnPage(currentPage) + 1
currentPage = currentPage + i
if currentPage < 1 then currentPage = maxPage + currentPage end
if currentPage > maxPage then currentPage = currentPage - maxPage end
local bookmarksOnPage = getAmountBookmarksOnPage(currentPage)
if oldPos > bookmarksOnPage then oldPos = bookmarksOnPage end
currentSlot = getFirstSlotOnPage(currentPage) + oldPos - 1
if mode == "move" then
table.remove(bookmarks, oldSlot)
table.insert(bookmarks, currentSlot, bookmarkStore)
end
displayBookmarks()
end
-- Parses a bookmark name for storing, also trimming it
-- Replaces %t with the timestamp of the bookmark
-- Replaces %p with the time position of the bookmark
function parseName(name)
local pos = 0
if mode == "rename" then pos = bookmarks[currentSlot]["pos"] else pos = mp.get_property_number("time-pos") end
name, _ = name:gsub("%%t", parseTime(pos))
name, _ = name:gsub("%%p", pos)
name = trimName(name)
return name
end
-- Parses a bookmark name for displaying, also trimming it
-- Replaces all { with an escaped { so it won't be interpreted as a tag
function displayName(name)
name, _ = name:gsub("{", "\\{")
name = trimName(name)
return name
end
-- Trims a name to the max number of characters
function trimName(name)
if name:len() > maxChar then name = name:sub(1,maxChar) end
return name
end
-- Parses a Windows path with backslashes to one with normal slashes
function parsePath(path)
if type(path) == "string" then path, _ = path:gsub("\\", "/") end
return path
end
-- Loads all the bookmarks in the global table and sets the current page and total number of pages
-- Also checks for older versions of bookmarks and "updates" them
-- Also checks for bookmarks made by "mpv-bookmarker" and converts them
-- Also removes anything it doesn't recognize as a bookmark
function loadBookmarks()
bookmarks = loadTable(getFilepath(bookmarkerName))
if bookmarks == nil then bookmarks = {} end
local doSave = false
local doEject = false
local doReplace = false
local ejects = {}
local newmarks = {}
for key, bookmark in pairs(bookmarks) do
if type(key) == "number" then
if bookmark.version == nil or bookmark.version == 1 then
if bookmark.name ~= nil and bookmark.path ~= nil and bookmark.pos ~= nil then
bookmark.path = parsePath(bookmark.path)
bookmark.version = 2
doSave = true
else
table.insert(ejects, key)
doEject = true
end
end
else
if bookmark.filename ~= nil and bookmark.pos ~= nil and bookmark.filepath ~= nil then
local newmark = {
name = trimName(""..bookmark.filename.." @ "..parseTime(bookmark.pos)),
pos = bookmark.pos,
path = parsePath(bookmark.filepath),
version = 2
}
table.insert(newmarks, newmark)
end
doReplace = true
doSave = true
end
end
if doEject then
for i = #ejects, 1, -1 do table.remove(bookmarks, ejects[i]) end
doSave = true
end
if doReplace then bookmarks = newmarks end
if doSave then saveBookmarks() end
if #bookmarks > 0 and currentSlot == 0 then currentSlot = 1 end
calcPages()
end
-- Save the globally loaded bookmarks to the JSON file
function saveBookmarks()
saveTable(bookmarks, getFilepath(bookmarkerName))
end
-- Make a bookmark of the current media file, position and name
-- Name can be specified or left blank to automake a name
-- Returns the bookmark if successful or nil if it can't make a bookmark
function makeBookmark(bname)
if mp.get_property("path") ~= nil then
if bname == nil then bname = mp.get_property("media-title").." @ %t" end
local bookmark = {
name = parseName(bname),
pos = mp.get_property_number("time-pos"),
path = parsePath(mp.get_property("path")),
version = 2
}
return bookmark
else
return nil
end
end
-- Add the current position as a bookmark to the global table and then saves it
-- Returns the slot of the newly added bookmark
-- Returns -1 if there's an error
function addBookmark(name)
local bookmark = makeBookmark(name)
if bookmark == nil then
abort(styleOn.."{\\c&H0000FF&}{\\b1}Can't find the media file to create the bookmark for")
return -1
end
table.insert(bookmarks, bookmark)
if #bookmarks == 1 then currentSlot = 1 end
calcPages()
saveBookmarks()
displayBookmarks()
return #bookmarks
end
-- Edit a property of a bookmark at the specified slot
-- Returns -1 if there's an error
function editBookmark(slot, property, value)
if bookmarkExists(slot) then
if property == "name" then value = parseName(value) end
bookmarks[slot][property] = value
saveBookmarks()
else
abort(styleOn.."{\\c&H0000FF&}{\\b1}Can't find the bookmark at slot "..slot)
return -1
end
end
-- Replaces the bookmark at the specified slot with a provided bookmark
-- Keeps the name and its position in the list
-- If the slot is not specified, picks the currently selected bookmark to replace
-- If a bookmark is not provided, generates a new bookmark
function replaceBookmark(slot)
if slot == nil then slot = currentSlot end
if bookmarkExists(slot) then
local bookmark = makeBookmark(bookmarks[slot]["name"])
if bookmark == nil then
abort(styleOn.."{\\c&H0000FF&}{\\b1}Can't find the media file to create the bookmark for")
return -1
end
bookmarks[slot] = bookmark
saveBookmarks()
if closeAfterReplace then
abort(styleOn.."{\\c&H00FF00&}{\\b1}Successfully replaced bookmark:{\\r}\n"..displayName(bookmark["name"]))
return -1
end
return 1
else
abort(styleOn.."{\\c&H0000FF&}{\\b1}Can't find the bookmark at slot "..slot)
return -1
end
end
-- Quickly saves a bookmark without bringing up the menu
function quickSave()
if not active then
loadBookmarks()
local slot = addBookmark()
if slot > 0 then mp.osd_message("Saved new bookmark at slot " .. slot) end
end
end
-- Quickly loads the last bookmark without bringing up the menu
function quickLoad()
if not active then
loadBookmarks()
local slot = #bookmarks
if slot > 0 then mp.osd_message("Loaded bookmark at slot " .. slot) end
jumpToBookmark(slot)
end
end
-- Deletes the bookmark in the specified slot from the global table and then saves it
function deleteBookmark(slot)
table.remove(bookmarks, slot)
if currentSlot > #bookmarks then currentSlot = #bookmarks end
calcPages()
saveBookmarks()
displayBookmarks()
end
-- Jump to the specified bookmark
-- This means loading it, reading it, and jumping to the file + position in the bookmark
function jumpToBookmark(slot)
if bookmarkExists(slot) then
local bookmark = bookmarks[slot]
if string.sub(bookmark["path"], 1, 4) == "http" or fileExists(bookmark["path"]) then
if parsePath(mp.get_property("path")) == bookmark["path"] then
mp.set_property_number("time-pos", bookmark["pos"])
else
mp.commandv("loadfile", parsePath(bookmark["path"]), "replace", "start="..bookmark["pos"])
end
if closeAfterLoad then abort(styleOn.."{\\c&H00FF00&}{\\b1}Successfully found file for bookmark:{\\r}\n"..displayName(bookmark["name"])) end
else
abort(styleOn.."{\\c&H0000FF&}{\\b1}Can't find file for bookmark:\n" .. displayName(bookmark["name"]))
end
else
abort(styleOn.."{\\c&H0000FF&}{\\b1}Can't find the bookmark at slot " .. slot)
end
end
-- Displays the current page of bookmarks
function displayBookmarks()
-- Determine which slot is the first and last on the current page
local startSlot = getFirstSlotOnPage(currentPage)
local endSlot = getLastSlotOnPage(currentPage)
-- Prepare the text to display and display it
local display = styleOn .. "{\\b1}Bookmarks page " .. currentPage .. "/" .. maxPage .. ":{\\b0}"
for i = startSlot, endSlot do
local btext = displayName(bookmarks[i]["name"])
local selection = ""
if i == currentSlot then
selection = "{\\b1}{\\c&H00FFFF&}>"
if mode == "move" then btext = "----------------" end
btext = btext
end
display = display .. "\n" .. selection .. i .. ": " .. btext .. "{\\r}"
end
mp.osd_message(display, rate)
end
local timer = mp.add_periodic_timer(rate * 0.95, displayBookmarks)
timer:kill()
-- Commits the message entered with the Typer with custom scripts preceding it
-- Should typically end with typerExit()
function typerCommit()
local status = 0
if mode == "save" then
status = addBookmark(typerText)
elseif mode == "replace" and typerText == "y" then
status = replaceBookmark(currentSlot, makeBookmark(bookmarks[currentSlot]["name"]))
elseif mode == "delete" and typerText == "y" then
deleteBookmark(currentSlot)
elseif mode == "rename" then
editBookmark(currentSlot, "name", typerText)
elseif mode == "filepath" then
editBookmark(currentSlot, "path", typerText)
end
if status >= 0 then typerExit() end
end
-- Exits the Typer without committing with custom scripts preceding it
function typerExit()
deactivateTyper()
displayBookmarks()
timer:resume()
mode = "none"
activateControls("bookmarker", bookmarkerControls, bookmarkerFlags)
end
-- Starts the Typer with custom scripts preceding it
function typerStart()
if (mode == "save" or mode=="replace") and mp.get_property("path") == nil then
abort(styleOn.."{\\c&H0000FF&}{\\b1}Can't find the media file to create the bookmark for")
return -1
end
if (mode == "replace" or mode == "rename" or mode == "filepath" or mode == "delete") and not bookmarkExists(currentSlot) then
abort(styleOn.."{\\c&H0000FF&}{\\b1}Can't find the bookmark at slot "..currentSlot)
return -1
end
if (mode == "replace" and not confirmReplace) or (mode == "delete" and not confirmDelete) then
typerText = "y"
typerCommit()
return
end
deactivateControls("bookmarker", bookmarkerControls)
timer:kill()
activateTyper()
if mode == "rename" then typerText = bookmarks[currentSlot]["name"] end
if mode == "filepath" then typerText = bookmarks[currentSlot]["path"] end
typerPos = typerText:len()
typer("")
end
-- Aborts the program with an optional error message
function abort(message)
mode = "none"
moverExit(true)
deactivateTyper()
deactivateControls("bookmarker", bookmarkerControls)
timer:kill()
mp.osd_message(message)
active = false
end
-- Handles the state of the bookmarker
function handler()
if active then
abort("")
else
activateControls("bookmarker", bookmarkerControls, bookmarkerFlags)
loadBookmarks()
displayBookmarks()
timer:resume()
active = true
end
end
mp.register_script_message("bookmarker-menu", handler)
mp.register_script_message("bookmarker-quick-save", quickSave)
mp.register_script_message("bookmarker-quick-load", quickLoad)