Greasy Fork is available in English.

Gerador de Prompt de Resumo do YouTube

Gera um prompt resumido com base nas legendas do vídeo no YouTube e copia para a área de transferência!

// ==UserScript==
// @name         Gerador de Prompt de Resumo do YouTube
// @namespace    http://tampermonkey.net/
// @version      2025-01-08
// @description  Gera um prompt resumido com base nas legendas do vídeo no YouTube e copia para a área de transferência!
// @author       Frederico Guilherme Klüser de Oliveira
// @match        https://www.youtube.com/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=youtube.com
// @grant        none
// @license MIT

// ==/UserScript==

(function () {
	'use strict';

	(() => {
		const copyToClipboard = (text) => {
			const inputTemp = document.createElement('input');
			document.body.appendChild(inputTemp);
			inputTemp.value = text;

			inputTemp.select();
			document.execCommand('copy');

			document.body.removeChild(inputTemp);
		};

		const waitElementByHierarchy = (
			hierarchy,
			config = {
				limitTime: 10000,
				from: document.body,
			},
		) =>
			new Promise((resolve, reject) => {
				const timeout = setTimeout(() => {
					clearInterval(interval);
					console.log(`timeout to find element by hierarchy: ${JSON.stringify(hierarchy)}`);
					reject(null);
				}, config.limitTime);

				const interval = setInterval(() => {
					console.log(`retry waitElementByHierarchy: ${JSON.stringify(hierarchy)}`);
					const element = findElementByHierarchy(hierarchy, config.from);

					if (element) {
						clearTimeout(timeout);
						clearInterval(interval);
						resolve(element);
					}
				}, 10);
			});

		const findElementByHierarchy = (hierarchy, from = document.body) => {
			let currentElements = [from];

			for (let i = 0; i < hierarchy.length; i += 1) {
				const { tag, attributes } = hierarchy[i];
				const matchingElements = [];

				currentElements.forEach((parentElement) => {
					const allElements = parentElement.getElementsByTagName(tag);

					for (let j = 0; j < allElements.length; j += 1) {
						const element = allElements[j];
						let match = true;

						for (let k = 0; k < attributes.length; k += 1) {
							const { attribute, value } = attributes[k];

							if (attribute === 'innerHTML') {
								if (element.innerHTML !== value) {
									match = false;
									break;
								}
							} else if (attribute === 'innerText') {
								if (element.innerText !== value) {
									match = false;
									break;
								}
							} else {
								if (element.getAttribute(attribute) !== value) {
									match = false;
									break;
								}
							}
						}

						if (match) {
							matchingElements.push(element);
						}
					}
				});

				if (matchingElements.length === 0) {
					return null; // Não encontrou nenhum elemento correspondente neste nível
				}

				currentElements = matchingElements; // Avança para o próximo nível com os elementos filtrados
			}

			// Retorna o primeiro elemento encontrado no último nível
			return currentElements.length > 0 ? currentElements[0] : null;
		};

		const findElementsByHierarchy = (hierarchy, from = document.body) => {
			let currentElements = [from];

			for (let i = 0; i < hierarchy.length; i += 1) {
				const { tag, attributes } = hierarchy[i];
				const matchingElements = [];

				currentElements.forEach((parentElement) => {
					const allElements = parentElement.getElementsByTagName(tag);

					for (let j = 0; j < allElements.length; j += 1) {
						const element = allElements[j];
						let match = true;

						for (let k = 0; k < attributes.length; k += 1) {
							const { attribute, value } = attributes[k];

							if (attribute === 'innerHTML') {
								if (element.innerHTML !== value) {
									match = false;
									break;
								}
							} else if (attribute === 'innerText') {
								if (element.innerText !== value) {
									match = false;
									break;
								}
							} else {
								if (element.getAttribute(attribute) !== value) {
									match = false;
									break;
								}
							}
						}

						if (match) {
							matchingElements.push(element);
						}
					}
				});

				if (matchingElements.length === 0) {
					return []; // Não encontrou nenhum elemento correspondente neste nível
				}

				currentElements = matchingElements; // Avança para o próximo nível com os elementos filtrados
			}

			// Retorna todos os elementos encontrados no último nível
			return currentElements;
		};

		const keyMap = {
			0: 'Digit0',
			1: 'Digit1',
			2: 'Digit2',
			3: 'Digit3',
			4: 'Digit4',
			5: 'Digit5',
			6: 'Digit6',
			7: 'Digit7',
			8: 'Digit8',
			9: 'Digit9',
			a: 'KeyA',
			b: 'KeyB',
			c: 'KeyC',
			d: 'KeyD',
			e: 'KeyE',
			f: 'KeyF',
			g: 'KeyG',
			h: 'KeyH',
			i: 'KeyI',
			j: 'KeyJ',
			k: 'KeyK',
			l: 'KeyL',
			m: 'KeyM',
			n: 'KeyN',
			o: 'KeyO',
			p: 'KeyP',
			q: 'KeyQ',
			r: 'KeyR',
			s: 'KeyS',
			t: 'KeyT',
			u: 'KeyU',
			v: 'KeyV',
			w: 'KeyW',
			x: 'KeyX',
			y: 'KeyY',
			z: 'KeyZ',
		};

		const addShortcut = (key, callback, preventDefault = true) => {
			const keyCode = keyMap[key.toLowerCase()] || key; // Converte para o código adequado

			document.addEventListener('keydown', (e) => {
				if (e.ctrlKey && e.code === keyCode) {
					if (preventDefault) {
						e.preventDefault();
					}
					callback(e);
				}
			});
		};

		addShortcut(
			'2',
			() => {
				document.getElementById('expand')?.click();

				waitElementByHierarchy([
					{
						tag: 'ytd-video-description-transcript-section-renderer',
						attributes: [],
					},
					{
						tag: 'div',
						attributes: [
							{
								attribute: 'id',
								value: 'primary-button',
							},
						],
					},
					{
						tag: 'button',
						attributes: [],
					},
				]).then((showMoreButton) => {
					showMoreButton.click();

					waitElementByHierarchy(
						[
							{
								tag: 'ytd-transcript-segment-list-renderer',
								attributes: [],
							},
						],
						{
							from: document.body,
							limitTime: 10000,
						},
					).then(() => {
						const subtitles = findElementsByHierarchy([
							{
								tag: 'ytd-transcript-segment-list-renderer',
								attributes: [],
							},
						]);

						const videoContent = subtitles.map((subtitle) => subtitle.innerText.replace('\n', ': ')).join('\n');

						const prompt = `Resuma o conteúdo do vídeo "${document.title}" em português, resuma de forma objetiva e clara. Aos final aponte os tempos do vídeo que começa a falar as partes importante (tempo que começa e tempo que termina), a seguir o conteúdo do vídeo: \n\n${videoContent}`;
						console.log(prompt);

						copyToClipboard(prompt);

						alert('Prompt copiado para a área de transferência');
					});
				});
			},
			true,
		);
	})();
})();