1 Video mode
Gold Holk edited this page 2022-08-20 13:11:08 +08:00

This is a custom mode which contains a lot of binding to deal with videos playing in webpage.

This my (Gholk) binding. I bind most commands at left hand. Feel free to modify this to fit the Tridactyl's default binding.

All js code are joined but not compressed. To modify or read them, just use uglifyjs --beautify or some what. They are not obfuscated.

Basic seeking

set video_seek 5
" seek forward/backward seconds defined in video_seek
set videomaps.w jsep $ex('video_with').then(video => {const count = Number(JS_ARG) || 1; const tic = Number(get('video_seek')); video.currentTime += tic * count }); 1;
set videomaps.b jsep $ex('video_with').then(video => {const count = Number(JS_ARG) || 1; const tic = Number(get('video_seek')); video.currentTime -= tic * count }); 1;

set video_seek_op 120
seturl ^https://www.youtube.com/watch\?v=116OjLa1DwY video_seek_op 42
set videomaps.C video_with video.currentTime = Number(get('video_seek_op'))
set videomaps.a video_with video.currentTime = 0
set videomaps.A video_with video.currentTime = video.duration

Although I do not know who will seek to the end or the beginning, I still do it.

Seek with specify time

The arguments which pass to the goto and the goby commands should be a spaces splited number. The last number is the second, and previous number is minute, and hour. If the first number is prefix with -, goto command will count from the end of the video, and the goby command will count from the current time.

set videomaps.gt fillcmdline video_goto
set videomaps.i fillcmdline video_goto
set videomaps.I fillcmdline video_goby

alias video_goby js -d@ let time = JS_ARGS.filter(Boolean); let sign = '+'; if (time[0].match(/^[-+]/)) { sign = time[0].charAt(0); time[0] = time[0].slice(1) } time = time.filter(Boolean).map(Number); const second = time.reduce((s, n) => s*60+n, 0); tri.controller.acceptExCmd(`video_with video.currentTime ${sign}= ${second}`) @
alias video_goto js -d@ let time = JS_ARGS.filter(Boolean); let sign = '+'; if (time[0].match(/^[-+]/)) { sign = time[0].charAt(0); time[0] = time[0].slice(1) } time = time.filter(Boolean).map(Number); let second = time.reduce((s, n) => s*60+n, 0); if (sign == '-') second = `video.duration - ${second}`; tri.controller.acceptExCmd(`video_with video.currentTime = ${second}`) @

E.g:

" go to 1m 30s of the video
video_goto 1 30
" go to 1h 30m 22s of the video
video_goto 1 30 22
" go to the last 1:30 of the video
video_goto -1 30

" seek 1:30 from the current position
video_goby 1 30
" go back 1:30 from the current position
video_goby -1 30

P.S. These commands are not very useful in fact.

Mark the timestamp

These commands can mark and jump to the timestamps in video, just like built-in markadd or markjump.

set videomaps.m gobble 1 video_mark_add
set videomaps.' gobble 1 video_mark_goto
set videomaps.ge video_mark_empty

set videomaps.E video_mark_goby +1
set videomaps.e video_mark_goby -1
set video_mark_tollorance 1
alias video_mark_add jsep void $ex('video_with').then(video => { const mark = JS_ARG; tri.videoMark.addMark(mark, video.currentTime); $ex('video_mode') })
alias video_mark_empty js const vm = tri.videoMark; vm.historyStore = Object.values(vm.mark).sort((a,b) => a-b);
alias video_mark_goby jsep void $ex('video_with').then(video => { const current = video.currentTime; const n = Number(JS_ARG); const time = tri.videoMark.goby(current, n); video.currentTime = time; $ex('video_mode'); })
alias video_mark_goto jsep void $ex('video_with').then(video => { const mark = JS_ARG; tri.videoMark.addBlur(video.currentTime); const time = tri.videoMark.mark[mark]; if (typeof time == 'number') video.currentTime = time; $ex('video_mode') })

alias video_mark_init jse if(!tri.videoMark){tri.videoMark={historyStore:[],mark:{},goby(current,n){const index=this.historyStore.findIndex(t=>{if(t>current)return true});const move=n<0?n:n-1;let time;if(~index)time=this.historyStore.at(index+move);else time=this.historyStore.at(move);if(Math.abs(time-current)>this.tollorance)return time;else return this.goby(current,n>0?n+1:n-1)},add(time){this.historyStore.push(time);this.historyStore.sort((a,b)=>a-b)},addBlur(time){const exist=this.historyStore.some(t=>Math.abs(t-time)<this.tollorance);if(!exist)this.add(time);return!exist},addMark(mark,time){this.mark[mark]=time;const index=this.historyStore.findIndex(t=>Math.abs(t-time)<this.tollorance);if(~index)this.historyStore[index]=time;else this.add(time)},tollorance:Number(get('video_mark_tollorance')) || 1,markEventHandler(videoEvent){const video=videoEvent.target;const time=video.currentTime;this.addBlur(time);const previousTime=this.getTimerTime();this.addBlur(previousTime)},timerEventHandler(event){const video=event.target;this.videoTimer={epoch:Date.now(),video:video.currentTime,rate:video.playbackRate}},videoTimer:null,getTimerTime(){const now=Date.now();const t=this.videoTimer;if(t)return(now-t.epoch)/1e3*t.rate+t.video}};void async function(){const vm=tri.videoMark;while(true){await sleep(800);const video=await $ex("video_with");if(video){const handler=tri.videoMark.markEventHandler.bind(tri.videoMark);video.addEventListener("seeked",handler);video.addEventListener("pause",handler);const timer=vm.timerEventHandler.bind(vm);video.addEventListener("playing",timer);video.addEventListener("ratechange",timer);timer({target:video});break}}}()}

These commands should call after the video_mark_init. Personally, I call video_mark_init when entering the video mode.

The m and ' will mark a timestamp with a character. Lowercase and uppercase are considered as different character.

The video_mark_goby will go to the nth next/prev mark from the current timestamp. If the nth mark has difference time below the video_mark_tollorance, this timestamp will be skiped. Moreover, everytime the user seek or pause the video, it will make a anonymouse mark, which can be jumped to with the video_mark_goby command. When seek, both the before timestamp and the after timestamp will be marked too. By the way, if any mark already exist within the tollorance before a anonymouse mark is created, the creation of the anonymouse mark will be canceled.

Enter and exit the mode

alias video_mode composite mode video ; video_mark_init
alias exit_video mode normal
bind gv video_mode
set videomaps.V exit_video
set videomaps.z mode normal

bindurl ^https://www.youtube.com/watch\? v video_mode
autocmd DocLoad ^https://www.youtube.com/watch\? video_mode

Misc

set videomaps.gf fullscreen
set videomaps.q fullscreen
set videomaps.🕷🕷INHERITS🕷🕷 nmaps

Helper command

They just like js, but pre-define some useful functions.

alias video_with jse let video; if (document.activeElement.name == 'VIDEO') video = document.activeElement; else video = $all('video').find(v => !v.paused); if (!video) video = $('video'); video;
alias jse js 'use strict'; function $all(q, root=document) { return Array.from(root.querySelectorAll(q)) }; function $(q, root=document) { return root.querySelector(q) }; let $ex = (s) => tri.controller.acceptExCmd(s) ; let $set = (...args) => tri.config.set(...args);
alias jsep js -p 'use strict'; function $all(q, root=document) { return Array.from(root.querySelectorAll(q)) }; function $(q, root=document) { return root.querySelector(q) }; let $ex = (s) => tri.controller.acceptExCmd(s) ; let $set = (...args) => tri.config.set(...args);