Store video timespamps locally, hide videos that have a timespamp, button to hide all videos in a playlist (all your liked videos)
// ==UserScript==
// @name Hanime Resumer and Hider
// @namespace http://tampermonkey.net/
// @version 1.2.1
// @description Store video timespamps locally, hide videos that have a timespamp, button to hide all videos in a playlist (all your liked videos)
// @author You
// @match https://hanime.tv/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=hanime.tv
// @grant GM.setValue
// @grant GM.getValue
// ==/UserScript==
function l(...args){
console.log('[Resumer]', ...args)
}
function getVideoKeyFromUrl(url = location.href) {
let u;
try {
u = new URL(url, location.origin);
} catch (err) {
l('invalid URL', url, err);
return undefined;
}
// Normal video URL: https://hanime.tv/videos/hentai/some-video
let match = u.pathname.match(/\/videos\/hentai\/([^/?#]+)/);
if (match) return match[1];
// Playlist video URL: https://hanime.tv/playlists/<playlist-id>/video/some-video
match = u.pathname.match(/\/playlists\/[^/]+\/video\/([^/?#]+)/);
if (match) return match[1];
return undefined;
}
//Resumer
let lastUrl = undefined
//Observe changes to the DOM
const observer = new MutationObserver(async (mutationsList, observer) => {
let currentUrl = location.href
if(currentUrl != lastUrl){
//Get video element
let key = getVideoKeyFromUrl();
let video = document.querySelector('video#HTVPlayer_html5_api');
l('url', currentUrl, lastUrl, key);
if(video){
l('Observing', key, video);
//Resume
let previousTime = await GM.getValue(key)
if(previousTime){
video.currentTime = previousTime
l(`resuming ${key} ${video.currentTime}`)
}
//Save currentTime
video.ontimeupdate = () => {
key = getVideoKeyFromUrl();
l('update', key, video.currentTime);
GM.setValue(key, video.currentTime);
}
lastUrl = currentUrl;
} else if(!key){
lastUrl = currentUrl;
}
}
})
observer.observe(document, {subtree:true, childList:true, attributes:true})
async function hide(a){
let key = getVideoKeyFromUrl(a.href);
let previousTime = await GM.getValue(key);
if(key != undefined && previousTime !== undefined){
// l('hiding', key, previousTime);
a.style.filter = 'brightness(0.3)';
}
}
//Hider
const observer2 = new MutationObserver((mutationsList, observer) => {
let links = document.querySelectorAll('a');
for(let a of links) {
hide(a);
}
//playlists (inefficient)
/*if(document.URL.includes('/playlists/')){
for(let a of document.querySelectorAll('.video__item a')){
hide(a)
}
//Hide all liked videos
if(!document.querySelector('#hide-all')){
let group = document.querySelector('.btn-toggle.btn-toggle--selected')
group.insertAdjacentHTML('afterEnd', '<button id="hide-all" type="button" class="btn btn--active btn--flat" style="position: relative;"><div class="btn__content">Hide All</div></button>')
document.querySelector('#hide-all').onclick = async () => {
for(let a of document.querySelectorAll('.video__item a')){
let name = a.href.replace('https://hanime.tv/videos/hentai/', '')
name = name.split('?')[0] //to remove ?playlist
let previousTime = await GM.getValue(name)
if(previousTime === undefined){
l('hiding', name)
a.style.filter = 'brightness(0.1)'
GM.setValue(name, 0)
}
}
}
}
}*/
})
observer2.observe(document, {subtree:true, childList:true})