From 67707381168e60d600b268885f1ddbabd89f0250 Mon Sep 17 00:00:00 2001 From: wukko Date: Sun, 24 Nov 2024 18:12:21 +0600 Subject: [PATCH] api/create-filename: build & sanitize filenames in one place --- api/src/misc/utils.js | 10 ---------- api/src/processing/create-filename.js | 12 +++++++++++- api/src/processing/services/ok.js | 5 ++--- api/src/processing/services/rutube.js | 6 ++---- api/src/processing/services/soundcloud.js | 5 ++--- api/src/processing/services/twitch.js | 5 ++--- api/src/processing/services/vimeo.js | 6 ++---- api/src/processing/services/vk.js | 5 ++--- api/src/processing/services/youtube.js | 5 ++--- 9 files changed, 25 insertions(+), 34 deletions(-) diff --git a/api/src/misc/utils.js b/api/src/misc/utils.js index cf4fefe6..271df1c5 100644 --- a/api/src/misc/utils.js +++ b/api/src/misc/utils.js @@ -1,5 +1,3 @@ -const forbiddenCharsString = ['}', '{', '%', '>', '<', '^', ';', ':', '`', '$', '"', "@", '=', '?', '|', '*']; - export function convertMetadataToFFmpeg(obj) { const keys = Object.keys(obj); const tags = [ @@ -19,14 +17,6 @@ export function convertMetadataToFFmpeg(obj) { return commands; } -export function cleanString(string) { - for (const i in forbiddenCharsString) { - string = string.replaceAll("/", "_").replaceAll("\\", "_") - .replaceAll(forbiddenCharsString[i], '') - } - return string; -} - export function getRedirectingURL(url) { return fetch(url, { redirect: 'manual' }).then((r) => { if ([301, 302, 303].includes(r.status) && r.headers.has('location')) diff --git a/api/src/processing/create-filename.js b/api/src/processing/create-filename.js index 216b15a4..cc985d51 100644 --- a/api/src/processing/create-filename.js +++ b/api/src/processing/create-filename.js @@ -1,3 +1,13 @@ +const illegalCharacters = ['}', '{', '%', '>', '<', '^', ';', ':', '`', '$', '"', "@", '=', '?', '|', '*']; + +const sanitizeString = (string) => { + for (const i in illegalCharacters) { + string = string.replaceAll("/", "_").replaceAll("\\", "_") + .replaceAll(illegalCharacters[i], '') + } + return string; +} + export default (f, style, isAudioOnly, isAudioMuted) => { let filename = ''; @@ -5,7 +15,7 @@ export default (f, style, isAudioOnly, isAudioMuted) => { let classicTags = [...infoBase]; let basicTags = []; - const title = `${f.title} - ${f.author}`; + const title = `${sanitizeString(f.title)} - ${sanitizeString(f.author)}`; if (f.resolution) { classicTags.push(f.resolution); diff --git a/api/src/processing/services/ok.js b/api/src/processing/services/ok.js index 2fb6082d..10fb785b 100644 --- a/api/src/processing/services/ok.js +++ b/api/src/processing/services/ok.js @@ -1,5 +1,4 @@ import { genericUserAgent, env } from "../../config.js"; -import { cleanString } from "../../misc/utils.js"; const resolutions = { "ultra": "2160", @@ -44,8 +43,8 @@ export default async function(o) { let bestVideo = videos.find(v => resolutions[v.name] === quality) || videos[videos.length - 1]; let fileMetadata = { - title: cleanString(videoData.movie.title.trim()), - author: cleanString((videoData.author?.name || videoData.compilationTitle).trim()), + title: videoData.movie.title.trim(), + author: (videoData.author?.name || videoData.compilationTitle).trim(), } if (bestVideo) return { diff --git a/api/src/processing/services/rutube.js b/api/src/processing/services/rutube.js index 67609ffc..ed8c58da 100644 --- a/api/src/processing/services/rutube.js +++ b/api/src/processing/services/rutube.js @@ -1,7 +1,5 @@ import HLS from "hls-parser"; - import { env } from "../../config.js"; -import { cleanString } from "../../misc/utils.js"; async function requestJSON(url) { try { @@ -59,8 +57,8 @@ export default async function(obj) { }); const fileMetadata = { - title: cleanString(play.title.trim()), - artist: cleanString(play.author.name.trim()), + title: play.title.trim(), + artist: play.author.name.trim(), } return { diff --git a/api/src/processing/services/soundcloud.js b/api/src/processing/services/soundcloud.js index 394f7dfe..d78cedda 100644 --- a/api/src/processing/services/soundcloud.js +++ b/api/src/processing/services/soundcloud.js @@ -1,5 +1,4 @@ import { env } from "../../config.js"; -import { cleanString } from "../../misc/utils.js"; const cachedID = { version: '', @@ -91,8 +90,8 @@ export default async function(obj) { if (!file) return { error: "fetch.empty" }; let fileMetadata = { - title: cleanString(json.title.trim()), - artist: cleanString(json.user.username.trim()), + title: json.title.trim(), + artist: json.user.username.trim(), } return { diff --git a/api/src/processing/services/twitch.js b/api/src/processing/services/twitch.js index ac85fbcf..4b9d4551 100644 --- a/api/src/processing/services/twitch.js +++ b/api/src/processing/services/twitch.js @@ -1,5 +1,4 @@ import { env } from "../../config.js"; -import { cleanString } from '../../misc/utils.js'; const gqlURL = "https://gql.twitch.tv/gql"; const clientIdHead = { "client-id": "kimne78kx3ncx6brgo4mv6wki5h1ko" }; @@ -73,13 +72,13 @@ export default async function (obj) { token: req_token[0].data.clip.playbackAccessToken.value })}`, fileMetadata: { - title: cleanString(clipMetadata.title.trim()), + title: clipMetadata.title.trim(), artist: `Twitch Clip by @${clipMetadata.broadcaster.login}, clipped by @${clipMetadata.curator.login}`, }, filenameAttributes: { service: "twitch", id: clipMetadata.id, - title: cleanString(clipMetadata.title.trim()), + title: clipMetadata.title.trim(), author: `${clipMetadata.broadcaster.login}, clipped by ${clipMetadata.curator.login}`, qualityLabel: `${format.quality}p`, extension: 'mp4' diff --git a/api/src/processing/services/vimeo.js b/api/src/processing/services/vimeo.js index 0268e1ec..45a52db7 100644 --- a/api/src/processing/services/vimeo.js +++ b/api/src/processing/services/vimeo.js @@ -1,7 +1,5 @@ import HLS from "hls-parser"; - import { env } from "../../config.js"; -import { cleanString, merge } from '../../misc/utils.js'; const resolutionMatch = { "3840": 2160, @@ -152,8 +150,8 @@ export default async function(obj) { } const fileMetadata = { - title: cleanString(info.name), - artist: cleanString(info.user.name), + title: info.name, + artist: info.user.name, }; return merge( diff --git a/api/src/processing/services/vk.js b/api/src/processing/services/vk.js index e3c18e47..6f5f2ea2 100644 --- a/api/src/processing/services/vk.js +++ b/api/src/processing/services/vk.js @@ -1,4 +1,3 @@ -import { cleanString } from "../../misc/utils.js"; import { genericUserAgent, env } from "../../config.js"; const resolutions = ["2160", "1440", "1080", "720", "480", "360", "240"]; @@ -43,8 +42,8 @@ export default async function(o) { url = js.player.params[0][`url${quality}`]; let fileMetadata = { - title: cleanString(js.player.params[0].md_title.trim()), - author: cleanString(js.player.params[0].md_author.trim()), + title: js.player.params[0].md_title.trim(), + author: js.player.params[0].md_author.trim(), } if (url) return { diff --git a/api/src/processing/services/youtube.js b/api/src/processing/services/youtube.js index 9e99d62f..3af6ba94 100644 --- a/api/src/processing/services/youtube.js +++ b/api/src/processing/services/youtube.js @@ -4,7 +4,6 @@ import { fetch } from "undici"; import { Innertube, Session } from "youtubei.js"; import { env } from "../../config.js"; -import { cleanString } from "../../misc/utils.js"; import { getCookie, updateCookieValues } from "../cookie/manager.js"; const PLAYER_REFRESH_PERIOD = 1000 * 60 * 15; // ms @@ -403,8 +402,8 @@ export default async function(o) { } const fileMetadata = { - title: cleanString(basicInfo.title.trim()), - artist: cleanString(basicInfo.author.replace("- Topic", "").trim()) + title: basicInfo.title.trim(), + artist: basicInfo.author.replace("- Topic", "").trim() } if (basicInfo?.short_description?.startsWith("Provided to YouTube by")) {