deltandy123 / dearrow-invidious Goto Github PK
View Code? Open in Web Editor NEWDeArrow userscript for Invidious
License: MIT License
DeArrow userscript for Invidious
License: MIT License
Please refer to ajayyy/DeArrow#39 (comment).
// ==UserScript==
// @name DeArrow for Invidious
// @namespace http://tampermonkey.net/
// @version 0.2.3
// @description Adds support for DeArrow in Invidious
// @match https://yewtu.be/*
// @match https://iv.ggtyler.dev/*
// @icon https://dearrow.ajay.app/logo.svg
// @grant GM.xmlHttpRequest
// @author Macic-Dev
// @author Minion3665
// @author Basil
// @author Ajay
// ==/UserScript==
(async function() {
'use strict';
/**
* A simple fetch polyfill that uses the GreaseMonkey API
*
* @param {string} url - the URL to fetch
*/
function fetch(url) {
return new Promise(resolve => {
GM.xmlHttpRequest({
method: 'GET',
url,
responseType: 'blob',
onload: res => {
const headers = res.responseHeaders
.split('\r\n')
.reduce((prev, str) => {
const [key, val] = str.split(/: (.*)/s);
if (key === '') return prev;
prev[key.toLowerCase()] = val;
return prev;
}, {});
resolve({
headers: {
get: key => headers[key.toLowerCase()]
},
status: res.status,
blob: async () => res.response,
json: async () => JSON.parse(await new Response(res.response).text())
});
}
});
});
}
/**
* Converts a Blob to a data URL in order to get around CSP
*
* @param {Blob} blob - the URL to fetch
*/
function blobToDataURI(blob) {
return new Promise(resolve => {
const reader = new FileReader();
reader.readAsDataURL(blob);
reader.onloadend = () => resolve(reader.result);
});
}
/**
* Fetch data for a video, and then update the elements passed to reflect that
*
* @param {string} videoId - the YouTube ID of the video (the bit that comes after v= in watch URLs)
* @param {HTMLElement} titleElement - the element containing the video title which will be updated if DeArrow has a title
* @param {HTMLElement|undefined} thumbnailElement - the element containing the video thumbnail which will be updated if DeArrow has a thumbnail
*/
async function fetchAndUpdate(videoId, titleElement, thumbnailElement = undefined) {
const oldTitle = titleElement.textContent;
const oldThumbnail = thumbnailElement?.src;
const cachedThumbnailAPIResponse = await fetch(`https://dearrow-thumb.ajay.app/api/v1/getThumbnail?videoID=${videoId}`);
const cachedNewTitle = cachedThumbnailAPIResponse.headers.get('X-Title');
if (cachedNewTitle) replaceTitle(titleElement, cachedNewTitle);
if (thumbnailElement !== undefined && cachedThumbnailAPIResponse.status === 200) {
const cachedNewThumbnail = await cachedThumbnailAPIResponse.blob();
thumbnailElement.src = await blobToDataURI(cachedNewThumbnail);
}
const brandingAPIResponse = await (await fetch(`https://sponsor.ajay.app/api/branding?videoID=${videoId}`)).json();
{
let topTitle = brandingAPIResponse.titles[0];
let usedTitle = (topTitle && (topTitle.votes >= 0 || topTitle.locked)) ? topTitle : null;
replaceTitle(titleElement, usedTitle?.title ?? oldTitle);
}
{
let topThumbnail = brandingAPIResponse.thumbnails[0];
let usedThumbnail = (topThumbnail && (topThumbnail.votes >= 0 || topThumbnail.locked)) ? topThumbnail : null;
let randomTime = brandingAPIResponse.videoDuration ? brandingAPIResponse.videoDuration * brandingAPIResponse.randomTime : 0;
if (usedThumbnail && usedThumbnail.original) {
thumbnailElement.src = oldThumbnail;
} else {
const votedThumbnailAPIResponse = await fetch(`https://dearrow-thumb.ajay.app/api/v1/getThumbnail?videoID=${videoId}&time=${usedThumbnail?.timestamp ?? randomTime}`);
thumbnailElement.src = await blobToDataURI(await votedThumbnailAPIResponse.blob());
}
}
}
// Replaces the title of elements
function replaceTitle(element, text) {
if (element.nodeName === 'H1') {
for (const child of element.childNodes) {
if (child.nodeName !== '#text') continue;
child.textContent = text;
break;
}
} else {
element.textContent = text;
}
}
// Videos on page
const thumbnailDivs = document.querySelectorAll('div.thumbnail');
thumbnailDivs.forEach((div) => {
if (div.parentNode.nodeName === 'DIV') {
// First link. Selector could be better.
const link = div.querySelector('a');
// Make sure we aren't fetching channel URLs
if (link.href.startsWith('/channel/')) return;
const videoUrl = new URL(link.href);
const videoId = videoUrl.searchParams.get('v');
const titleP = div.parentNode.children[1].querySelector('p');
const thumbnailImg = div.querySelector('img.thumbnail');
fetchAndUpdate(videoId, titleP, thumbnailImg);
} else {
// Make sure we aren't fetching channel URLs
if (div.parentNode.href.startsWith('/channel/')) return;
const videoUrl = new URL(div.querySelector('a').href);
const videoId = videoUrl.searchParams.get('v');
const titleP = [...div.parentNode.querySelectorAll('p')][1];
const thumbnailImg = div.querySelector('img.thumbnail');
fetchAndUpdate(videoId, titleP, thumbnailImg);
}
});
// Current video
const currentUrl = new URL(document.URL);
if (currentUrl.pathname == '/watch') {
const currentId = currentUrl.searchParams.get('v');
const titleH = document.querySelector('h1');
const thumbnailDiv = document.querySelector('.vjs-poster');
await fetchAndUpdate(currentId, titleH, thumbnailDiv);
if (thumbnailDiv.src) thumbnailDiv.style.backgroundImage = `url(${thumbnailDiv.src})`;
document.title = `${titleH.textContent} - Invidious`;
}
})();
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.