mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-06-05 21:59:27 +02:00
Add /yt-script command
This commit is contained in:
@ -1,6 +1,9 @@
|
|||||||
import { getRequestHeaders } from '../script.js';
|
import { getRequestHeaders } from '../script.js';
|
||||||
import { renderExtensionTemplateAsync } from './extensions.js';
|
import { renderExtensionTemplateAsync } from './extensions.js';
|
||||||
import { POPUP_RESULT, POPUP_TYPE, callGenericPopup } from './popup.js';
|
import { POPUP_RESULT, POPUP_TYPE, callGenericPopup } from './popup.js';
|
||||||
|
import { SlashCommand } from './slash-commands/SlashCommand.js';
|
||||||
|
import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from './slash-commands/SlashCommandArgument.js';
|
||||||
|
import { SlashCommandParser } from './slash-commands/SlashCommandParser.js';
|
||||||
import { isValidUrl } from './utils.js';
|
import { isValidUrl } from './utils.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -441,6 +444,32 @@ class YouTubeScraper {
|
|||||||
this.description = 'Download a transcript from a YouTube video.';
|
this.description = 'Download a transcript from a YouTube video.';
|
||||||
this.iconClass = 'fa-brands fa-youtube';
|
this.iconClass = 'fa-brands fa-youtube';
|
||||||
this.iconAvailable = true;
|
this.iconAvailable = true;
|
||||||
|
|
||||||
|
SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
||||||
|
name: 'yt-script',
|
||||||
|
callback: async (args, url) => {
|
||||||
|
try {
|
||||||
|
if (!url) {
|
||||||
|
throw new Error('URL or ID of the YouTube video is required');
|
||||||
|
}
|
||||||
|
|
||||||
|
const lang = String(args?.lang || '');
|
||||||
|
const { transcript } = await this.getScript(String(url).trim(), lang);
|
||||||
|
return transcript;
|
||||||
|
} catch (error) {
|
||||||
|
toastr.error(error.message);
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
helpString: 'Scrape a transcript from a YouTube video by ID or URL.',
|
||||||
|
returns: ARGUMENT_TYPE.STRING,
|
||||||
|
namedArgumentList: [
|
||||||
|
new SlashCommandNamedArgument('lang', 'ISO 639-1 language code of the transcript, e.g. "en"', ARGUMENT_TYPE.STRING, false, false, ''),
|
||||||
|
],
|
||||||
|
unnamedArgumentList: [
|
||||||
|
new SlashCommandArgument('URL or ID of the YouTube video', ARGUMENT_TYPE.STRING, true, false),
|
||||||
|
],
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -456,7 +485,12 @@ class YouTubeScraper {
|
|||||||
* @param {string} url URL of the YouTube video
|
* @param {string} url URL of the YouTube video
|
||||||
* @returns {string} ID of the YouTube video
|
* @returns {string} ID of the YouTube video
|
||||||
*/
|
*/
|
||||||
parseId(url){
|
parseId(url) {
|
||||||
|
// If the URL is already an ID, return it
|
||||||
|
if (/^[a-zA-Z0-9_-]{11}$/.test(url)) {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
const regex = /^.*(?:(?:youtu\.be\/|v\/|vi\/|u\/\w\/|embed\/|shorts\/)|(?:(?:watch)?\?v(?:i)?=|&v(?:i)?=))([^#&?]*).*/;
|
const regex = /^.*(?:(?:youtu\.be\/|v\/|vi\/|u\/\w\/|embed\/|shorts\/)|(?:(?:watch)?\?v(?:i)?=|&v(?:i)?=))([^#&?]*).*/;
|
||||||
const match = url.match(regex);
|
const match = url.match(regex);
|
||||||
return (match?.length && match[1] ? match[1] : url);
|
return (match?.length && match[1] ? match[1] : url);
|
||||||
@ -479,8 +513,22 @@ class YouTubeScraper {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const id = this.parseId(String(videoUrl).trim());
|
|
||||||
const toast = toastr.info('Working, please wait...');
|
const toast = toastr.info('Working, please wait...');
|
||||||
|
const { transcript, id } = await this.getScript(videoUrl, lang);
|
||||||
|
toastr.clear(toast);
|
||||||
|
|
||||||
|
const file = new File([transcript], `YouTube - ${id} - ${Date.now()}.txt`, { type: 'text/plain' });
|
||||||
|
return [file];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches the transcript of a YouTube video.
|
||||||
|
* @param {string} videoUrl Video URL or ID
|
||||||
|
* @param {string} lang Video language
|
||||||
|
* @returns {Promise<{ transcript: string, id: string }>} Transcript of the YouTube video with the video ID
|
||||||
|
*/
|
||||||
|
async getScript(videoUrl, lang) {
|
||||||
|
const id = this.parseId(String(videoUrl).trim());
|
||||||
|
|
||||||
const result = await fetch('/api/serpapi/transcript', {
|
const result = await fetch('/api/serpapi/transcript', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
@ -494,10 +542,7 @@ class YouTubeScraper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const transcript = await result.text();
|
const transcript = await result.text();
|
||||||
toastr.clear(toast);
|
return { transcript, id };
|
||||||
|
|
||||||
const file = new File([transcript], `YouTube - ${id} - ${Date.now()}.txt`, { type: 'text/plain' });
|
|
||||||
return [file];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user