From 1cbffc2d755e6c24b439ac63e7587d992949f8b8 Mon Sep 17 00:00:00 2001
From: wukko <me@wukko.me>
Date: Sun, 24 Nov 2024 18:13:22 +0600
Subject: [PATCH] api/stream/types: convert metadata in one place

also sanitize values & throw an error if tag isn't supported
---
 api/src/misc/utils.js   | 19 -------------------
 api/src/stream/types.js | 24 +++++++++++++++++++++++-
 2 files changed, 23 insertions(+), 20 deletions(-)

diff --git a/api/src/misc/utils.js b/api/src/misc/utils.js
index 271df1c5..fd497d18 100644
--- a/api/src/misc/utils.js
+++ b/api/src/misc/utils.js
@@ -1,22 +1,3 @@
-export function convertMetadataToFFmpeg(obj) {
-    const keys = Object.keys(obj);
-    const tags = [
-        "album",
-        "copyright",
-        "title",
-        "artist",
-        "track",
-        "date"
-    ]
-    let commands = []
-
-    for (const i in keys) {
-        if (tags.includes(keys[i]))
-            commands.push('-metadata', `${keys[i]}=${obj[keys[i]]}`)
-        }
-    return commands;
-}
-
 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/stream/types.js b/api/src/stream/types.js
index d1e56bf2..98c3b04e 100644
--- a/api/src/stream/types.js
+++ b/api/src/stream/types.js
@@ -5,7 +5,6 @@ import { create as contentDisposition } from "content-disposition-header";
 
 import { env } from "../config.js";
 import { destroyInternalStream } from "./manage.js";
-import { convertMetadataToFFmpeg } from "../misc/utils.js";
 import { hlsExceptions } from "../processing/service-config.js";
 import { getHeaders, closeRequest, closeResponse, pipe } from "./shared.js";
 
@@ -16,6 +15,29 @@ const ffmpegArgs = {
     gif: ["-vf", "scale=-1:-1:flags=lanczos,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse", "-loop", "0"]
 }
 
+const metadataTags = [
+    "album",
+    "copyright",
+    "title",
+    "artist",
+    "track",
+    "date",
+];
+
+const convertMetadataToFFmpeg = (metadata) => {
+    let args = [];
+
+    for (const [ name, value ] of Object.entries(metadata)) {
+        if (metadataTags.includes(name)) {
+            args.push('-metadata', `${name}=${value.replace(/[\u0000-\u0009]/g, "")}`);
+        } else {
+            throw `${name} metadata tag is not supported.`;
+        }
+    }
+
+    return args;
+}
+
 const toRawHeaders = (headers) => {
     return Object.entries(headers)
                  .map(([key, value]) => `${key}: ${value}\r\n`)