Created
June 24, 2022 08:26
-
-
Save q00u/f1136af9b5fb0af3e8c03253b16976a8 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript== | |
// @name Chapter Sorter Reaper Scans | |
// @namespace https://gist.github.com/q00u | |
// @version 0.3 | |
// @description Sort released chapters in User Settings by date | |
// @author Phoenix G | |
// @match https://reaperscans.com/user-settings/ | |
// @match https://reaperscans.com/user-settings/?tab=bookmark | |
// @icon http://f1.allesedv.com/16/reaperscans.com | |
// @grant none | |
// ==/UserScript== | |
(function () { | |
// Parse Messy Time@2.1.0: | |
const months = [ | |
'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', | |
'September', 'October', 'November', 'December', | |
]; | |
const days = [ | |
'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', | |
]; | |
const hmsre = RegExp( | |
'(\\d+\\.?\\d*(?:[:h]\\d+\\.?\\d*(?:[:m]\\d+\\.\\d*s?)?)?)', | |
); | |
const tokre = RegExp( | |
'\\s+|(\\d+(?:st|th|nd|rd|th))\\b' | |
+ `|${hmsre.source}([A-Za-z]+)` | |
+ `|([A-Za-z]+)${hmsre.source}`, | |
); | |
const parse = function (str, opts) { | |
if (!opts) opts = {}; | |
let now = opts.now || new Date(); | |
if (typeof now === 'number' || typeof now === 'string') now = new Date(now); | |
let ago = false; | |
const tokens = str.split(tokre).filter(Boolean).map(lc); | |
const res = {}; | |
for (let i = 0; i < tokens.length; i++) { | |
const t = tokens[i]; | |
let next = tokens[i + 1]; | |
const prev = tokens[i - 1]; | |
var m; | |
if (m = /(\d+)(st|nd|rd|th)/i.exec(t)) { | |
if (next === 'of') { | |
next = tokens[i + 2]; | |
i++; | |
} | |
res.date = Number(m[1]); | |
if (monthish(next)) { | |
res.month = next; | |
i++; | |
} | |
} else if ((m = /(\d+)(st|nd|rd|th)?/i.exec(next)) | |
&& monthish(t)) { | |
res.month = t; | |
res.date = Number(m[1]); | |
i++; | |
if (/^\d+$/.test(tokens[i + 1])) { // year | |
res.year = Number(tokens[i + 1]); | |
i++; | |
} | |
} else if ((m = hmsre.exec(t)) && isunit(next)) { | |
if (tokens[i - 1] === 'in') { | |
for (var j = i; j < tokens.length; j += 2) { | |
if (tokens[j] === 'and') j--; | |
else if ((m = hmsre.exec(tokens[j])) | |
&& ishunit(tokens[j + 1])) { | |
addu(parseh(tokens[j]), nunit(tokens[j + 1])); | |
} else if ((m = /^(\d+\.?\d*)/.exec(tokens[j])) | |
&& isdunit(tokens[j + 1])) { | |
daddu(Number(m[1]), nunit(tokens[j + 1])); | |
} else break; | |
} | |
i = j; | |
} else { | |
for (var j = i + 2; j < tokens.length; j++) { | |
if (tokens[j] === 'ago') { | |
ago = true; | |
break; | |
} | |
} | |
if (j === tokens.length) continue; | |
for (let k = i; k < j; k++) { | |
if ((m = hmsre.exec(tokens[k])) && ishunit(tokens[k + 1])) { | |
subu(parseh(tokens[k]), nunit(tokens[k + 1])); | |
} else if ((m = /^(\d+\.?\d*)/.exec(tokens[k])) | |
&& isdunit(tokens[k + 1])) { | |
dsubu(Number(m[1]), nunit(tokens[k + 1])); | |
} | |
} | |
i = j; | |
} | |
} else if (/noon/.test(t)) { | |
res.hours = 12; | |
res.minutes = 0; | |
res.seconds = 0; | |
} else if (/midnight/.test(t)) { | |
res.hours = 0; | |
res.minutes = 0; | |
res.seconds = 0; | |
} else if (/\d+[:h]\d+/.test(t) || /^(am|pm)/.test(next)) { | |
const hms = parseh(t, next); | |
if (hms[0] !== null) res.hours = hms[0]; | |
if (hms[1] !== null) res.minutes = hms[1]; | |
if (hms[2] !== null) res.seconds = hms[2]; | |
} else if ((m = /^(\d+)/.exec(t)) && monthish(next)) { | |
var x = Number(m[1]); | |
if (res.year === undefined && x > 31) res.year = x; | |
else if (res.date === undefined) res.date = x; | |
if (res.month === undefined) res.month = next; | |
i++; | |
} else if (monthish(t) && (m = /^(\d+)/.exec(next))) { | |
var x = Number(m[1]); | |
if (res.year === undefined && x > 31) res.year = x; | |
else if (res.date === undefined) res.date = x; | |
if (res.month === undefined) res.month = t; | |
i++; | |
} else if ((m = /^(\d+)/.exec(t)) && monthish(prev)) { | |
var x = Number(m[1]); | |
if (res.year === undefined) res.year = x; | |
else if (res.hours === undefined) res.hours = x; | |
} else if (m = /^[`'\u00b4\u2019](\d+)/.exec(t)) { | |
res.year = Number(m[1]); | |
} else if (/^\d{4}[\W_]\d{1,2}[\W_]\d{1,2}/.test(t)) { | |
const yms = t.split(/[\W_]/); | |
res.year = Number(yms[0]); | |
res.month = Number(yms[1]) - 1; | |
res.date = Number(yms[2]); | |
} else if (m = /^(\d+)/.exec(t)) { | |
var x = Number(m[1]); | |
if (res.hours === undefined && x < 24) res.hours = x; | |
else if (res.date === undefined && x <= 31) res.date = x; | |
else if (res.year === undefined && x > 31) res.year = x; | |
else if (res.year == undefined | |
&& res.hours !== undefined && res.date !== undefined) { | |
res.year = x; | |
} else if (res.hours === undefined | |
&& res.date !== undefined && res.year !== undefined) { | |
res.hours = x; | |
} else if (res.date === undefined | |
&& res.hours !== undefined && res.year !== undefined) { | |
res.date = x; | |
} | |
} else if (/^today$/.test(t) && res.date === undefined) { | |
res.date = now.getDate(); | |
res.month = months[now.getMonth()]; | |
res.year = now.getFullYear(); | |
} else if (/^now$/.test(t) && res.date === undefined) { | |
res.hours = now.getHours(); | |
res.minutes = now.getMinutes(); | |
res.seconds = now.getSeconds(); | |
res.date = now.getDate(); | |
res.month = months[now.getMonth()]; | |
res.year = now.getFullYear(); | |
} else if (/^to?m+o?r+o?w?/.test(t) && res.date === undefined) { | |
const tomorrow = new Date(now.valueOf() + 24 * 60 * 60 * 1000); | |
res.date = tomorrow.getDate(); | |
if (res.month === undefined) { | |
res.month = months[tomorrow.getMonth()]; | |
} | |
if (res.year === undefined) { | |
res.year = tomorrow.getFullYear(); | |
} | |
} else if (/^yesterday/.test(t) && res.date === undefined) { | |
const yst = new Date(now.valueOf() - 24 * 60 * 60 * 1000); | |
res.date = yst.getDate(); | |
if (res.month === undefined) { | |
res.month = months[yst.getMonth()]; | |
} | |
if (res.year === undefined) { | |
res.year = yst.getFullYear(); | |
} | |
} else if (t === 'next' && dayish(next) && res.date === undefined) { | |
setFromDay(next, 7); | |
i++; | |
} else if (t === 'last' && dayish(next) && res.date === undefined) { | |
setFromDay(next, -7); | |
i++; | |
} else if (dayish(t) && res.date === undefined) { | |
setFromDay(t, 0); | |
} | |
} | |
if (res.year < 100) { | |
const y = now.getFullYear(); | |
const py = y % 100; | |
if (py + 10 < res.year) { | |
res.year += y - py - 100; | |
} else res.year += y - py; | |
} | |
if (res.month && typeof res.month !== 'number') { | |
res.month = nmonth(res.month); | |
} | |
const out = new Date(now); | |
out.setHours(res.hours === undefined ? 0 : res.hours); | |
out.setMinutes(res.minutes === undefined ? 0 : res.minutes); | |
out.setSeconds(res.seconds === undefined ? 0 : res.seconds); | |
let monthSet = res.month; | |
if (typeof res.month === 'number') { | |
out.setMonth(res.month); | |
} else if (res.month) { | |
monthSet = months.indexOf(res.month); | |
out.setMonth(monthSet); | |
} | |
if (res.date !== undefined) out.setDate(res.date); | |
if (monthSet !== undefined && out.getMonth() !== monthSet) { | |
out.setMonth(monthSet); | |
} | |
if (res.year) out.setYear(res.year); | |
else if (out < now && !ago | |
&& (Math.abs(out.getMonth() + 12 - now.getMonth()) % 12) >= 1) { | |
out.setYear(now.getFullYear() + 1); | |
} | |
return out; | |
function setFromDay(t, x) { | |
const dayi = days.indexOf(nday(t)); | |
const xdays = (7 + dayi - now.getDay()) % 7 + x; | |
const d = new Date(now.valueOf() + xdays * 24 * 60 * 60 * 1000); | |
res.date = d.getDate(); | |
if (res.month === undefined) { | |
res.month = months[d.getMonth()]; | |
} | |
if (res.year === undefined) { | |
res.year = d.getFullYear(); | |
} | |
} | |
function opu(hms, u, op) { | |
if (u == 'hours') { | |
res.hours = op(now.getHours(), hms[0]); | |
res.minutes = op(now.getMinutes(), hms[1] === null ? 0 : hms[1]); | |
res.seconds = op(now.getSeconds(), hms[2] === null ? 0 : hms[2]); | |
} else if (u == 'minutes') { | |
if (res.hours === undefined) res.hours = now.getHours(); | |
res.minutes = op(now.getMinutes(), hms[0] === null ? 0 : hms[0]); | |
res.seconds = op(now.getSeconds(), hms[1] === null ? 0 : hms[1]); | |
} else if (u == 'seconds') { | |
if (res.hours === undefined) res.hours = now.getHours(); | |
if (res.minutes === undefined) res.minutes = now.getMinutes(); | |
res.seconds = op(now.getSeconds(), hms[0] === null ? 0 : hms[0]); | |
} | |
} | |
function subu(hms, u) { opu(hms, u, sub); } | |
function addu(hms, u) { opu(hms, u, add); } | |
function dopu(n, u, op) { | |
if (res.hours === undefined) res.hours = now.getHours(); | |
if (res.minutes === undefined) res.minutes = now.getMinutes(); | |
if (res.seconds === undefined) res.seconds = now.getSeconds(); | |
if (u === 'days') { | |
res.date = op(now.getDate(), n); | |
} else if (u === 'weeks') { | |
res.date = op(now.getDate(), n * 7); | |
} else if (u === 'months') { | |
res.month = op(now.getMonth(), n); | |
} else if (u === 'years') { | |
res.year = op(now.getFullYear(), n); | |
} | |
} | |
function dsubu(n, u) { dopu(n, u, sub); } | |
function daddu(n, u) { dopu(n, u, add); } | |
}; | |
function add(a, b) { return a + b; } | |
function sub(a, b) { return a - b; } | |
function lc(s) { return String(s).toLowerCase(); } | |
function ishunit(s) { | |
const n = nunit(s); | |
return n === 'hours' || n === 'minutes' || n === 'seconds'; | |
} | |
function isdunit(s) { | |
const n = nunit(s); | |
return n === 'days' || n === 'weeks' || n === 'months' || n === 'years'; | |
} | |
function isunit(s) { return Boolean(nunit(s)); } | |
function nunit(s) { | |
if (/^(ms|millisecs?|milliseconds?)$/.test(s)) return 'milliseconds'; | |
if (/^(s|secs?|seconds?)$/.test(s)) return 'seconds'; | |
if (/^(m|mins?|minutes?)$/.test(s)) return 'minutes'; | |
if (/^(h|hrs?|hours?)$/.test(s)) return 'hours'; | |
if (/^(d|days?)$/.test(s)) return 'days'; | |
if (/^(w|wks?|weeks?)$/.test(s)) return 'weeks'; | |
if (/^(mo|mnths?|months?)$/.test(s)) return 'months'; | |
if (/^(y|yrs?|years?)$/.test(s)) return 'years'; | |
} | |
function monthish(s) { return Boolean(nmonth(s)); } | |
function dayish(s) { | |
return /^(mon|tue|wed|thu|fri|sat|sun)/i.test(s); | |
} | |
function nmonth(s) { | |
if (/^jan/i.test(s)) return 'January'; | |
if (/^feb/i.test(s)) return 'February'; | |
if (/^mar/i.test(s)) return 'March'; | |
if (/^apr/i.test(s)) return 'April'; | |
if (/^may/i.test(s)) return 'May'; | |
if (/^jun/i.test(s)) return 'June'; | |
if (/^jul/i.test(s)) return 'July'; | |
if (/^aug/i.test(s)) return 'August'; | |
if (/^sep/i.test(s)) return 'September'; | |
if (/^oct/i.test(s)) return 'October'; | |
if (/^nov/i.test(s)) return 'November'; | |
if (/^dec/i.test(s)) return 'December'; | |
} | |
function nday(s) { | |
if (/^mon/i.test(s)) return 'Monday'; | |
if (/^tue/i.test(s)) return 'Tuesday'; | |
if (/^wed/i.test(s)) return 'Wednesday'; | |
if (/^thu/i.test(s)) return 'Thursday'; | |
if (/^fri/i.test(s)) return 'Friday'; | |
if (/^sat/i.test(s)) return 'Saturday'; | |
if (/^sun/i.test(s)) return 'Sunday'; | |
} | |
function parseh(s, next) { | |
const m = /(\d+\.?\d*)(?:[:h](\d+\.?\d*)(?:[:m](\d+\.?\d*s?\.?\d*))?)?/.exec(s); | |
const hms = [Number(m[1]), null, null]; | |
if (/^am/.test(next) && hms[0] == 12) hms[0] -= 12; | |
if (/^pm/.test(next) && hms[0] < 12) hms[0] += 12; | |
if (m[2]) hms[1] = Number(m[2]); | |
if (m[3]) hms[2] = Number(m[3]); | |
if (hms[0] > floorup(hms[0])) { | |
hms[1] = floorup((hms[0] - floorup(hms[0])) * 60); | |
hms[0] = floorup(hms[0]); | |
} | |
if (hms[1] > floorup(hms[1])) { | |
hms[2] = floorup((hms[1] - floorup(hms[1])) * 60); | |
hms[1] = floorup(hms[1]); | |
} | |
return hms; | |
} | |
function floorup(x) { | |
return Math.floor(Math.round(x * 1e6) / 1e6); | |
} | |
// Your code here... | |
console.log('Reaper Scans Chapter Sorter'); | |
// console.log('parse 2 days ago:', parse('2 days ago')); | |
const bookmarks = document.getElementsByClassName('list-bookmark')[0].children[1]; | |
// console.log('bookmarks:', bookmarks); | |
[...bookmarks.children] | |
.sort((a, b) => { | |
// const atext = a.children[1]?.children[0]?.innerText; // Updated Time on right | |
const atext = a.children[0]?.children[0].children[1]?.children[1]?.children[0]?.children[1]?.innerText // x hours ago time on left | |
//console.log('atext:', atext); | |
const atime = atext ? parse(atext) : 0; | |
//console.log('atime:', atime); | |
// const btext = b.children[1]?.children[0]?.innerText; | |
const btext = b.children[0]?.children[0].children[1]?.children[1]?.children[0]?.children[1]?.innerText | |
const btime = btext ? parse(btext) : 0; | |
return btime - atime; | |
}) | |
.forEach((node) => bookmarks.appendChild(node)); | |
}()); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment