mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-06-05 21:59:27 +02:00
Add YT script loader for data bank
This commit is contained in:
@ -93,8 +93,8 @@ class WebScraper {
|
||||
* Check if the scraper is available.
|
||||
* @returns {Promise<boolean>}
|
||||
*/
|
||||
isAvailable() {
|
||||
return Promise.resolve(true);
|
||||
async isAvailable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -167,8 +167,8 @@ class FileScraper {
|
||||
* Check if the scraper is available.
|
||||
* @returns {Promise<boolean>}
|
||||
*/
|
||||
isAvailable() {
|
||||
return Promise.resolve(true);
|
||||
async isAvailable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -199,6 +199,10 @@ class FandomScraper {
|
||||
this.iconClass = 'fa-solid fa-fire';
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the scraper is available.
|
||||
* @returns {Promise<boolean>}
|
||||
*/
|
||||
async isAvailable() {
|
||||
try {
|
||||
const result = await fetch('/api/plugins/fandom/probe', {
|
||||
@ -289,6 +293,77 @@ class FandomScraper {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Scrape transcript from a YouTube video.
|
||||
* @implements {Scraper}
|
||||
*/
|
||||
class YouTubeScraper {
|
||||
constructor() {
|
||||
this.id = 'youtube';
|
||||
this.name = 'YouTube';
|
||||
this.description = 'Download a transcript from a YouTube video.';
|
||||
this.iconClass = 'fa-solid fa-closed-captioning';
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the scraper is available.
|
||||
* @returns {Promise<boolean>}
|
||||
*/
|
||||
async isAvailable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the ID of a YouTube video from a URL.
|
||||
* @param {string} url URL of the YouTube video
|
||||
* @returns {string} ID of the YouTube video
|
||||
*/
|
||||
parseId(url){
|
||||
const regex = /^.*(?:(?:youtu\.be\/|v\/|vi\/|u\/\w\/|embed\/|shorts\/)|(?:(?:watch)?\?v(?:i)?=|&v(?:i)?=))([^#&?]*).*/;
|
||||
const match = url.match(regex);
|
||||
return (match?.length && match[1] ? match[1] : url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Scrape transcript from a YouTube video.
|
||||
* @returns {Promise<File[]>} File attachments scraped from the YouTube video
|
||||
*/
|
||||
async scrape() {
|
||||
let lang = '';
|
||||
const template = $(await renderExtensionTemplateAsync('attachments', 'youtube-scrape', {}));
|
||||
const videoUrl = await callGenericPopup(template, POPUP_TYPE.INPUT, '', { wide: false, large: false, okButton: 'Scrape', cancelButton: 'Cancel', rows: 2 });
|
||||
|
||||
template.find('input[name="youtubeLanguageCode"]').on('input', function () {
|
||||
lang = String($(this).val()).trim();
|
||||
});
|
||||
|
||||
if (!videoUrl) {
|
||||
return;
|
||||
}
|
||||
|
||||
const id = this.parseId(String(videoUrl).trim());
|
||||
const toast = toastr.info('Working, please wait...');
|
||||
|
||||
const result = await fetch('/api/serpapi/transcript', {
|
||||
method: 'POST',
|
||||
headers: getRequestHeaders(),
|
||||
body: JSON.stringify({ id, lang }),
|
||||
});
|
||||
|
||||
if (!result.ok) {
|
||||
const error = await result.text();
|
||||
throw new Error(error);
|
||||
}
|
||||
|
||||
const transcript = await result.text();
|
||||
toastr.clear(toast);
|
||||
|
||||
const file = new File([transcript], `YouTube - ${id} - ${Date.now()}.txt`, { type: 'text/plain' });
|
||||
return [file];
|
||||
}
|
||||
}
|
||||
|
||||
ScraperManager.registerDataBankScraper(new FileScraper());
|
||||
ScraperManager.registerDataBankScraper(new WebScraper());
|
||||
ScraperManager.registerDataBankScraper(new FandomScraper());
|
||||
ScraperManager.registerDataBankScraper(new YouTubeScraper());
|
||||
|
Reference in New Issue
Block a user