Add video title to YouTube download filename

This commit is contained in:
fluofoxxo 2023-05-08 00:07:16 -04:00
parent b62627058e
commit e8a48c53f2
3 changed files with 135 additions and 5 deletions

View File

@ -1,4 +1,4 @@
import { apiJSON } from "../sub/utils.js";
import { apiJSON, PostInfo } from "../sub/utils.js";
import { errorUnsupported, genericError, brokenLink } from "../sub/errors.js";
import loc from "../../localization/manager.js";
@ -16,6 +16,48 @@ import tumblr from "./services/tumblr.js";
import vimeo from "./services/vimeo.js";
import soundcloud from "./services/soundcloud.js";
export class YouTubeFetchInfo {
/**
* ID of the YouTube video.
*
* @type {string}
*/
id
/**
* Quality of the YouTube video.
*
* @type {string}
*/
quality
/**
* Format of the YouTube video to be downloaded.
*
* @type {string}
*/
format
/**
* Whether only the audio of the YouTube video should be gotten.
*
* @type {boolean}
*/
isAudioOnly
/**
* Whether audio of the YouTube video should be muted.
*
* @type {boolean}
*/
isAudioMuted
/**
* Dub language to use for the video.
*
* @type {boolean | string}
*/
dubLang
}
/**
* @param {PostInfo} obj Post information
*/
export default async function (host, patternMatch, url, lang, obj) {
try {
let r, isAudioOnly = !!obj.isAudioOnly;
@ -44,6 +86,7 @@ export default async function (host, patternMatch, url, lang, obj) {
});
break;
case "youtube":
/** @type {YouTubeFetchInfo} */
let fetchInfo = {
id: patternMatch["id"].slice(0, 11),
quality: obj.vQuality,
@ -113,6 +156,7 @@ export default async function (host, patternMatch, url, lang, obj) {
return matchActionDecider(r, host, obj.ip, obj.aFormat, isAudioOnly, lang, isAudioMuted);
} catch (e) {
console.error(e);
return apiJSON(0, { t: genericError(lang, host) })
}
}

View File

@ -1,5 +1,6 @@
import { Innertube } from 'youtubei.js';
import { maxVideoDuration } from '../../config.js';
import { YouTubeFetchInfo } from '../match.js';
const yt = await Innertube.create();
@ -21,7 +22,30 @@ const c = {
}
}
export default async function(o) {
/**
* Creates a filename to be downloaded for the requested YouTube video.
*
* @param {YouTubeFetchInfo} fi Fetch info to utilize for filename
* @param vi Video info to utilize for filename
* @param format Video format object to pull info from
* @param {string} container Video container type (file extension)
*/
function youtubeFilename(fi, vi, format, container) {
return [
'youtube',
vi.basic_info.title,
fi.id,
format.width + 'x' + format.height,
fi.format + (fi.dubLang ? "_" + fi.dubLang : ""),
].join('_') + ('.' + container);
}
/**
* Core logic for running the YouTube processor.
*
* @param {YouTubeFetchInfo} o Fetch information for YouTube video
*/
export default async function youtube(o) {
let info, isDubbed, quality = o.quality === "max" ? "9000" : o.quality; //set quality 9000(p) to be interpreted as max
try {
info = await yt.getBasicInfo(o.id, 'ANDROID');
@ -59,7 +83,7 @@ export default async function(o) {
type: "render",
isAudioOnly: true,
urls: audio.url,
audioFilename: `youtube_${o.id}_audio${isDubbed ? `_${o.dubLang}`:''}`,
audioFilename: `youtube_${o.id}_audio${isDubbed ? `_${o.dubLang}` : ''}`,
fileMetadata: {
title: info.basic_info.title,
artist: info.basic_info.author.replace("- Topic", "").trim(),
@ -90,7 +114,8 @@ export default async function(o) {
if (video && audio) return {
type: "render",
urls: [video.url, audio.url],
filename: `youtube_${o.id}_${video.width}x${video.height}_${o.format}${isDubbed ? `_${o.dubLang}`:''}.${c[o.format].container}`
filename: youtubeFilename(o, info, video, c[o.format].container),
// filename: `youtube_${o.id}_${video.width}x${video.height}_${o.format}${isDubbed ? `_${o.dubLang}` : ''}.${c[o.format].container}`
};
return { error: 'ErrorYTTryOtherCodec' }

View File

@ -63,7 +63,7 @@ export function msToTime(d) {
}
export function cleanURL(url, host) {
let forbiddenChars = ['}', '{', '(', ')', '\\', '%', '>', '<', '^', '*', '!', '~', ';', ':', ',', '`', '[', ']', '#', '$', '"', "'", "@"]
switch(host) {
switch (host) {
case "vk":
case "youtube":
url = url.split('&')[0];
@ -95,7 +95,68 @@ export function unicodeDecode(str) {
return String.fromCharCode(parseInt(unicode.replace(/\\u/g, ""), 16));
});
}
/**
* Post information for a given media post.
*/
export class PostInfo {
/**
* Codec used by the post's media.
*
* @type {string}
*/
vCodec
/**
* Quality of the post's media.
*
* @type {string}
*/
vQuality
/**
* Format to get of the post's media.
*
* @type {string}
*/
aFormat
/**
* Whether the media should be gotten as audio only.
*
* @type {boolean}
*/
isAudioOnly
/**
* Whether the TikTok watermark should be absent from the gotten media.
*
* @type {boolean}
*/
isNoTTWatermark
/**
* Whether the TikTok media should be gotten with full audio.
*
* @type {boolean}
*/
isTTFullAudio
/**
* Whether the media should be gotten with the audio muted.
*
* @type {boolean}
*/
isAudioMuted
/**
* Language to get the video dubbed in, or not to dub at all. Usually pulled from
* the request's 'Accept-Language' header, but defaults to false.
*
* @type {boolean | string}
*/
dubLang = false
/**
* Whether to get DASH video files from the Vimeo platform.
*
* @type {boolean}
*/
vimeoDash
}
export function checkJSONPost(obj) {
/** @type {PostInfo} */
let def = {
vCodec: "h264",
vQuality: "720",