Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
// ==UserScript==
// @name geekVideoSeek
// @namespace http://tampermonkey.net/
// @version 0.1
// @description try to take over the world!
// @author You
// @match https://u.geekbang.org/lesson/*
// @grant none
// ==/UserScript==
(function() {
'use strict';
// Your code here...
const pat = /((?:\d{1,2}\W*[::]\ ?\W*)?\d{1,2}\W*[::]\ ?\W*\d{1,2})\W*-/g
function waitForResult(func, interval = 1000, maxTrials = 10) {
return new Promise((resolve, reject) => {
let trial = 1
function wait() {
const res = func()
if (res) {
resolve(res)
return
}
trial++
if (trial >= maxTrials) {
reject(new Error('max trials exceeded'))
return
}
setTimeout(wait, interval)
}
wait()
})
}
function toSeconds(text) {
return text.split(/[::]/).reduce((acc, val) => acc * 60 + Number(val), 0)
}
function seekVideo(seconds) {
const video = document.querySelector('video')
video.currentTime = seconds
}
function createButton(text) {
const res = document.createElement('button')
res.innerText = text
res.setAttribute('style', [
'background: none;',
'border: none;',
'padding: 0;',
'color: #069;',
'text-decoration: underline;',
'cursor: pointer;',
'display: block;',
].join(' '))
return res
}
waitForResult(() => {
const res = [...document.querySelectorAll('li, p')]
.filter(e => e.innerText.match(pat) !== null)
if (res.length > 0) return res
})
.then(res => {
for (const e of res) {
const str = e.innerText
e.innerText = ''
const matches = [...str.matchAll(pat)]
const startIndices = matches.map(m => m.index).concat(str.length)
for (let i = 0; i < matches.length; i++) {
const seconds = toSeconds(matches[i][1])
const caption = str.substring(startIndices[i], startIndices[i + 1])
const btn = createButton(caption)
btn.onclick = () => seekVideo(seconds)
e.appendChild(btn)
}
}
})
.catch(err => {
console.error(err)
})
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.