您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Saves video progress on invidio.us and adds some more functonality
当前为
- // ==UserScript==
- // @name Invidious save video progress
- // @namespace http://tampermonkey.net/
- // @version 0.1.1
- // @description Saves video progress on invidio.us and adds some more functonality
- // @author Noruf
- // @match https://invidio.us/*
- // @match https://invidious.snopyta.org/*
- // @grant none
- // ==/UserScript==
- (function() {
- 'use strict';
- const timestamps = localStorage.timestamps ? JSON.parse(localStorage.timestamps) : {};
- let search = window.location.search;
- const isVideoPage = window.location.pathname.includes('watch');
- const videoId = isVideoPage? window.location.search.match(/v=(.*?)(&|$)/)[1]: ' ';
- var url = new URL(window.location.href);
- var time = url.searchParams.get("t");
- if(!time&×tamps[videoId]){
- search = replaceQueryParam('t', timestamps[videoId], search);
- window.location.replace(window.location.pathname + search);
- }
- onReadyEvent(addHistoryButton);
- onReadyEvent(changeLinks);
- if(isVideoPage) onReadyEvent(videoProgressMain);
- onReadyEvent(addCopyYoutubeLinkButton);
- function replaceQueryParam(param, newval, search) {
- const regex = new RegExp("([?;&])" + param + "[^&;]*[;&]?");
- const query = search.replace(regex, "$1").replace(/&$/, '');
- return (query.length > 2 ? query + "&" : "?") + (newval ? param + "=" + newval : '');
- }
- function onReadyEvent(callback){
- // in case the document is already rendered
- if (document.readyState!='loading') callback();
- // modern browsers
- else if (document.addEventListener) document.addEventListener('DOMContentLoaded', callback);
- // IE <= 8
- else {document.attachEvent('onreadystatechange', function(){
- if (document.readyState=='complete') callback();
- });}
- }
- function addCopyYoutubeLinkButton(){
- if(!isVideoPage)return;
- const a = document.querySelector('a[href*="youtube"');
- const p = document.createElement("a");
- p.appendChild(document.createTextNode(" copy"));
- a.parentElement.append(p);
- p.onclick = () => {
- copyToClipboard(a.href);
- };
- const altP = document.createElement("p");
- const altLink = document.createElement("a");
- altLink.appendChild(document.createTextNode("Alternate source"));
- altLink.href = `https://invidious.snopyta.org/watch?v=${videoId}`;
- altP.appendChild(altLink);
- const ul = p.parentElement.parentElement;
- ul.insertBefore(altP,ul.childNodes[2]);
- }
- function addHistoryButton(){
- const userfield = document.querySelector('.user-field');
- const newdiv = document.createElement('div');
- newdiv.className = 'pure-u-1-4';
- userfield.prepend(newdiv);
- const anchor = document.createElement('a');
- anchor.href = '/feed/history';
- anchor.className = 'pure-menu-heading';
- newdiv.append(anchor);
- const i = document.createElement('i');
- i.className = 'icon ion-md-time';
- anchor.append(i);
- }
- function changeLinks(){
- const thumbnails = document.querySelectorAll('div.thumbnail');
- thumbnails.forEach(t =>{
- const a = t.parentElement;
- const href = a.href;
- if(!href.includes("watch"))return;
- const id = href.match(/v=(.*?)(&|$)/)[1];
- if(timestamps[id]){
- a.href = `${href}&t=${timestamps[id]}s`;
- }
- if(isVideoPage)return;
- const YT = href.replace(window.location.host,'youtube.com');
- const copy = document.createElement("a");
- copy.appendChild(document.createTextNode("copy"));
- const open = document.createElement("a");
- open.href = YT;
- open.appendChild(document.createTextNode("open"));
- const div = document.createElement('h5');
- div.style['text-align'] = 'right';
- div.style['margin-top'] = '-5%';
- div.append('YT link: ',copy,' ',open);
- a.parentElement.append(div);
- copy.onclick = () => {
- copyToClipboard(YT);
- };
- });
- }
- function videoProgressMain (){
- const player = document.querySelector('video');
- player.onpause = () => {saveProgress(false)};
- window.addEventListener('beforeunload', function (e) {
- saveProgress(false);
- e.returnValue = ''; // Chrome requires returnValue to be set.
- });
- const saveToClipboard = document.createElement("BUTTON");
- saveToClipboard.className = "pure-button";
- saveToClipboard.appendChild(document.createTextNode("Save To Clipboard"))
- document.querySelector('#subscribe').parentElement.appendChild(saveToClipboard);
- const message = document.createElement("span");
- document.querySelector('#genre').parentElement.appendChild(message);
- saveToClipboard.onclick = () => {
- saveProgress(true);
- }
- function saveProgress(doCopy){
- const time = Math.floor(document.querySelector('video').currentTime);
- if(isNaN(player.duration))return;
- if(doCopy){
- copyToClipboard(getURL(time));
- }
- timestamps[videoId] = time;
- if(time < 60 || player.duration - time < 60) {
- delete timestamps[videoId];
- message.innerHTML = `Timestamp not saved!`;
- } else{
- message.innerHTML = `Saved at ${convertSeconds(time)}`;
- }
- history.replaceState( {} , '', replaceQueryParam('t',time,window.location.pathname + window.location.search));
- localStorage.timestamps = JSON.stringify(timestamps);
- }
- function getURL(seconds){
- return `https://invidio.us/watch?v=${videoId}&t=${seconds}s`;
- }
- function convertSeconds(seconds){
- return new Date(seconds * 1000).toISOString().substr(11, 8);
- }
- }
- function copyToClipboard(text) {
- const textArea = document.createElement("textarea");
- textArea.value = text;
- textArea.style.position = 'fixed';
- textArea.style.top = 0;
- textArea.style.left = 0;
- textArea.style.width = '2em';
- textArea.style.height = '2em';
- textArea.style.padding = 0;
- textArea.style.border = 'none';
- textArea.style.outline = 'none';
- textArea.style.boxShadow = 'none';
- textArea.style.background = 'transparent';
- document.body.appendChild(textArea);
- textArea.focus();
- textArea.select();
- try {
- const successful = document.execCommand('copy');
- const msg = successful ? 'successful' : 'unsuccessful';
- console.log('Copying text command was ' + msg);
- } catch (err) {
- console.error('Oops, unable to copy', err);
- }
- document.body.removeChild(textArea);
- }
- })();