From f64cc9747575a1e56f9c4755049b92ee67bba19a Mon Sep 17 00:00:00 2001 From: Tor Wingalen Date: Fri, 15 May 2026 23:36:57 +0200 Subject: [PATCH] Replace yt-search dependency with yt-dlp search --- package-lock.json | 319 ++-------------------- src/backend/package.json | 2 - src/backend/src/shared/youtube.service.ts | 76 +++++- 3 files changed, 97 insertions(+), 300 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4c3ccae..a9947b2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4325,30 +4325,6 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@jsep-plugin/assignment": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@jsep-plugin/assignment/-/assignment-1.3.0.tgz", - "integrity": "sha512-VVgV+CXrhbMI3aSusQyclHkenWSAm95WaiKrMxRFam3JSUiIaQjoMIw2sEs/OX4XifnqeQUN4DYbJjlA8EfktQ==", - "license": "MIT", - "engines": { - "node": ">= 10.16.0" - }, - "peerDependencies": { - "jsep": "^0.4.0||^1.0.0" - } - }, - "node_modules/@jsep-plugin/regex": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@jsep-plugin/regex/-/regex-1.0.4.tgz", - "integrity": "sha512-q7qL4Mgjs1vByCaTnDFcBnV9HS7GVPJX5vyVoCgZHNSC9rjwIlmbXG5sUuorR5ndfHAIlJ8pVStxvjXHbNvtUg==", - "license": "MIT", - "engines": { - "node": ">= 10.16.0" - }, - "peerDependencies": { - "jsep": "^0.4.0||^1.0.0" - } - }, "node_modules/@jsonjoy.com/base64": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@jsonjoy.com/base64/-/base64-1.1.2.tgz", @@ -8079,12 +8055,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@types/yt-search": { - "version": "2.10.3", - "resolved": "https://registry.npmjs.org/@types/yt-search/-/yt-search-2.10.3.tgz", - "integrity": "sha512-kH4Yzs/edH9/s/Wj58WhV73qpiRedWeNy5V202BqpXPd+xUFM8M3ASLdUMYUbzzlUDoGorDm4JpeN6iNx3sOjw==", - "license": "MIT" - }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "6.21.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.21.0.tgz", @@ -8910,94 +8880,6 @@ "node": ">= 4" } }, - "node_modules/async.parallellimit": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/async.parallellimit/-/async.parallellimit-0.5.2.tgz", - "integrity": "sha512-4Di2nFsb3jL7aUIICvRSvtw/oynpMIx0JrwYn5hqJI661Dd+mYBi2ElOukOQgRHihU1SCTapb86Vx/Snva5M1w==", - "license": "MIT", - "dependencies": { - "async.util.eachoflimit": "0.5.2", - "async.util.parallel": "0.5.2" - } - }, - "node_modules/async.util.eachoflimit": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/async.util.eachoflimit/-/async.util.eachoflimit-0.5.2.tgz", - "integrity": "sha512-oZksH0sBW0AEOJKgBCQ79io9DZruoRBLTAea/Ik36pejR7pDpByvtXeuJsoZdPwSVslsrQcsUfucbUaiXYBnAQ==", - "license": "MIT", - "dependencies": { - "async.util.keyiterator": "0.5.2", - "async.util.noop": "0.5.2", - "async.util.once": "0.5.2", - "async.util.onlyonce": "0.5.2" - } - }, - "node_modules/async.util.isarray": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/async.util.isarray/-/async.util.isarray-0.5.2.tgz", - "integrity": "sha512-wbUzlrwON8RUgi+v/rhF0U99Ce8Osjcn+JP/mFNg6ymvShcobAOvE6cvLajSY5dPqKCOE1xfdhefgBif11zZgw==", - "license": "MIT" - }, - "node_modules/async.util.isarraylike": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/async.util.isarraylike/-/async.util.isarraylike-0.5.2.tgz", - "integrity": "sha512-DbFpsz3ZFNkohAW8IpGTlm8gotU32zpqe3Y2XkEA/G3XNO6rmUTKPpo7XgXUruoI+AsGi8+0zWpJHe7t1sLiAg==", - "license": "MIT", - "dependencies": { - "async.util.isarray": "0.5.2" - } - }, - "node_modules/async.util.keyiterator": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/async.util.keyiterator/-/async.util.keyiterator-0.5.2.tgz", - "integrity": "sha512-cktrETawCwgu13y3KZs2uMGFnNHc+IjKPZsavtRaoCjLELkePb2co4zrr+ghPvEqLXZIJPTKqC2HFZgJTssMVw==", - "license": "MIT", - "dependencies": { - "async.util.isarraylike": "0.5.2", - "async.util.keys": "0.5.2" - } - }, - "node_modules/async.util.keys": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/async.util.keys/-/async.util.keys-0.5.2.tgz", - "integrity": "sha512-umCOCRCRYwIC2Ho3fbuhKwIIe7OhQsVoVKGoF5GoQiGJUmjP4TG0Bmmcdpm7yW/znoIGKpnjKzVQz0niH4tfqw==", - "license": "MIT" - }, - "node_modules/async.util.noop": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/async.util.noop/-/async.util.noop-0.5.2.tgz", - "integrity": "sha512-AdwShXwE0KoskgqVJAck8zcM32nIHj3AC8ZN62ZaR5srhrY235Nw18vOJZWxcOfhxdVM0hRVKM8kMx7lcl7cCQ==", - "license": "MIT" - }, - "node_modules/async.util.once": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/async.util.once/-/async.util.once-0.5.2.tgz", - "integrity": "sha512-YQ5WPzDTt2jlblUDkq2I5RV/KiAJErJ4/0cEFhYPaZzqIuF/xDzdGvnEKe7UeuoMszsVPeajzcpKgkbwdb9MUA==", - "license": "MIT" - }, - "node_modules/async.util.onlyonce": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/async.util.onlyonce/-/async.util.onlyonce-0.5.2.tgz", - "integrity": "sha512-UgQvkU9JZ+I0Cm1f56XyGXcII+J3d/5XWUuHpcevlItuA3WFSJcqZrsyAUck2FkRSD8BwYQX1zUTDp3SJMVESg==", - "license": "MIT" - }, - "node_modules/async.util.parallel": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/async.util.parallel/-/async.util.parallel-0.5.2.tgz", - "integrity": "sha512-0bEvwmQ8fxsTYNwacw5iq0i3PvGryRkXxZ01Rvox21izdMdls9IH2rAZjfunbgI8j6nFRyIdCmMINQ9kka99ow==", - "license": "MIT", - "dependencies": { - "async.util.isarraylike": "0.5.2", - "async.util.noop": "0.5.2", - "async.util.restparam": "0.5.2" - } - }, - "node_modules/async.util.restparam": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/async.util.restparam/-/async.util.restparam-0.5.2.tgz", - "integrity": "sha512-Q9Z+zgmtMxFX5i7CnBvNOkgrL5hptztCqwarQluyNudUUk4iCmyjmsQl8MuQEjNh3gGqP5ayvDaextL1VXXgIg==", - "license": "MIT" - }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -9579,14 +9461,9 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true, "license": "ISC" }, - "node_modules/boolstring": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/boolstring/-/boolstring-2.0.1.tgz", - "integrity": "sha512-tpNlEZsRdZzIP7KElpv0GRiRsnkh7+Ko+W2ohZt2DcH3/z/Gya1r+0dlSSNc5GWGSt0zG7c4JV02U7ZCk/1lWw==", - "license": "MIT" - }, "node_modules/boxen": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/boxen/-/boxen-8.0.1.tgz", @@ -10157,6 +10034,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.2.0.tgz", "integrity": "sha512-WDrybc/gKFpTYQutKIK6UvfcuxijIZfMfXaYm8NMsPQxSYvf+13fXUJ4rztGGbJcBQ/GF55gvrZ0Bc0bj/mqvg==", + "dev": true, "license": "MIT", "dependencies": { "cheerio-select": "^2.1.0", @@ -10182,6 +10060,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz", "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==", + "dev": true, "license": "BSD-2-Clause", "dependencies": { "boolbase": "^1.0.0", @@ -10736,6 +10615,7 @@ "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "devOptional": true, "license": "MIT" }, "node_modules/concat-stream": { @@ -11340,6 +11220,7 @@ "version": "5.2.2", "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.2.2.tgz", "integrity": "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==", + "dev": true, "license": "BSD-2-Clause", "dependencies": { "boolbase": "^1.0.0", @@ -11356,6 +11237,7 @@ "version": "6.2.2", "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz", "integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==", + "dev": true, "license": "BSD-2-Clause", "engines": { "node": ">= 6" @@ -11483,12 +11365,6 @@ "node": ">=4" } }, - "node_modules/dasu": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/dasu/-/dasu-0.4.3.tgz", - "integrity": "sha512-AFwspl5k7V8MW8H7tyIGJ0gtOauUg7JC+DgiRFUIXvPNNDFXTMtvnCkZY0macN6JLGqBjNP38WVnQN7Iv3RSlg==", - "license": "MIT" - }, "node_modules/data-uri-to-buffer": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz", @@ -11852,6 +11728,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "dev": true, "license": "MIT", "dependencies": { "domelementtype": "^2.3.0", @@ -11866,6 +11743,7 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true, "funding": [ { "type": "github", @@ -11878,6 +11756,7 @@ "version": "5.0.3", "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "dev": true, "license": "BSD-2-Clause", "dependencies": { "domelementtype": "^2.3.0" @@ -11893,6 +11772,7 @@ "version": "3.2.2", "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz", "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==", + "dev": true, "license": "BSD-2-Clause", "dependencies": { "dom-serializer": "^2.0.0", @@ -12038,6 +11918,7 @@ "version": "0.2.1", "resolved": "https://registry.npmjs.org/encoding-sniffer/-/encoding-sniffer-0.2.1.tgz", "integrity": "sha512-5gvq20T6vfpekVtqrYQsSCFZ1wEg5+wW0/QaZMWkFr6BqD3NfKs0rLCx4rrVlSWJeZb5NBJgVLswK/w2MWU+Gw==", + "dev": true, "license": "MIT", "dependencies": { "iconv-lite": "^0.6.3", @@ -12051,6 +11932,7 @@ "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" @@ -12157,6 +12039,7 @@ "version": "4.5.0", "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, "license": "BSD-2-Clause", "engines": { "node": ">=0.12" @@ -14280,6 +14163,7 @@ "version": "10.1.0", "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-10.1.0.tgz", "integrity": "sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ==", + "dev": true, "funding": [ "https://github.com/fb55/htmlparser2?sponsor=1", { @@ -14299,6 +14183,7 @@ "version": "7.0.1", "resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz", "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==", + "dev": true, "license": "BSD-2-Clause", "engines": { "node": ">=0.12" @@ -14440,12 +14325,6 @@ "node": ">=10.17.0" } }, - "node_modules/human-time": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/human-time/-/human-time-0.0.2.tgz", - "integrity": "sha512-sbYI90YhYmstslPTb70BLGjy6mdESa0lxL7uDR4fIVAx9Iobz8fLEqi7FqF4Q/6vblrzZALg//MsYJlIPBU8SA==", - "license": "MIT" - }, "node_modules/humanize-ms": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", @@ -16061,15 +15940,6 @@ "js-yaml": "bin/js-yaml.js" } }, - "node_modules/jsep": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/jsep/-/jsep-1.4.0.tgz", - "integrity": "sha512-B7qPcEVE3NVkmSJbaYxvv4cHkVW7DQsZz13pUMrfS8z8Q/BuShN+gcTXrUlPiGqM2/t/EEaI030bpxMqY8gMlw==", - "license": "MIT", - "engines": { - "node": ">= 10.16.0" - } - }, "node_modules/jsesc": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", @@ -16167,24 +16037,6 @@ ], "license": "MIT" }, - "node_modules/jsonpath-plus": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/jsonpath-plus/-/jsonpath-plus-10.3.0.tgz", - "integrity": "sha512-8TNmfeTCk2Le33A3vRRwtuworG/L5RrgMvdjhKZxvyShO+mBu2fP50OWUjRLNtvw344DdDarFh9buFAZs5ujeA==", - "license": "MIT", - "dependencies": { - "@jsep-plugin/assignment": "^1.3.0", - "@jsep-plugin/regex": "^1.0.4", - "jsep": "^1.4.0" - }, - "bin": { - "jsonpath": "bin/jsonpath-cli.js", - "jsonpath-plus": "bin/jsonpath-cli.js" - }, - "engines": { - "node": ">=18.0.0" - } - }, "node_modules/karma": { "version": "6.4.4", "resolved": "https://registry.npmjs.org/karma/-/karma-6.4.4.tgz", @@ -16490,12 +16342,6 @@ "node": ">=10" } }, - "node_modules/keypress": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/keypress/-/keypress-0.2.1.tgz", - "integrity": "sha512-HjorDJFNhnM4SicvaUXac0X77NiskggxJdesG72+O5zBKpSqKFCrqmndKVqpu3pFqkla0St6uGk8Ju0sCurrmg==", - "license": "MIT" - }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -17532,6 +17378,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -18157,67 +18004,6 @@ "node": ">= 6.13.0" } }, - "node_modules/node-fzf": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/node-fzf/-/node-fzf-0.14.0.tgz", - "integrity": "sha512-VZU+nuj8zzEEtGzeYGGzKdSmj7W9oHm9xK2A1g1kEPmlyK3726T1iT1e9FCxWiaKKjEn3oqR+p3So7EjU94JaA==", - "license": "MIT", - "dependencies": { - "keypress": "~0.2.1", - "minimist": "~1.2.5", - "picocolors": "~1.1.1", - "redstar": "0.0.2", - "restore-cursor": "~3.1.0", - "string-width": "~2.1.1", - "ttys": "0.0.3" - }, - "bin": { - "nfzf": "bin/cli.js" - } - }, - "node_modules/node-fzf/node_modules/ansi-regex": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz", - "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/node-fzf/node_modules/is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/node-fzf/node_modules/string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "license": "MIT", - "dependencies": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/node-fzf/node_modules/strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/node-gyp": { "version": "11.5.0", "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-11.5.0.tgz", @@ -18554,6 +18340,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, "license": "BSD-2-Clause", "dependencies": { "boolbase": "^1.0.0" @@ -18632,6 +18419,7 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, "license": "MIT", "dependencies": { "mimic-fn": "^2.1.0" @@ -19023,6 +18811,7 @@ "version": "7.3.0", "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", + "dev": true, "license": "MIT", "dependencies": { "entities": "^6.0.0" @@ -19049,6 +18838,7 @@ "version": "7.1.0", "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.1.0.tgz", "integrity": "sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g==", + "dev": true, "license": "MIT", "dependencies": { "domhandler": "^5.0.3", @@ -19062,6 +18852,7 @@ "version": "7.1.2", "resolved": "https://registry.npmjs.org/parse5-parser-stream/-/parse5-parser-stream-7.1.2.tgz", "integrity": "sha512-JyeQc9iwFLn5TbvvqACIF/VXG6abODeB3Fwmv/TGdLk2LfbWkaySGY72at4+Ty7EkPZj854u4CrICqNk2qIbow==", + "dev": true, "license": "MIT", "dependencies": { "parse5": "^7.0.0" @@ -19086,6 +18877,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", + "dev": true, "license": "BSD-2-Clause", "engines": { "node": ">=0.12" @@ -19181,6 +18973,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, "license": "ISC" }, "node_modules/picomatch": { @@ -19956,36 +19749,6 @@ "node": ">=4" } }, - "node_modules/redstar": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/redstar/-/redstar-0.0.2.tgz", - "integrity": "sha512-VNvLaLxMJMYiAasJX5Q/GC+Os7FXL0yPWFDuTodhR7Na9wqzrXsePPWC+EtIv4t3q5DyAK00w423xi5mQN2fqg==", - "license": "MIT", - "dependencies": { - "minimatch": "~3.0.4" - } - }, - "node_modules/redstar/node_modules/brace-expansion": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", - "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/redstar/node_modules/minimatch": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.8.tgz", - "integrity": "sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q==", - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/reflect-metadata": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz", @@ -20803,6 +20566,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, "license": "MIT", "dependencies": { "onetime": "^5.1.0", @@ -20816,6 +20580,7 @@ "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, "license": "ISC" }, "node_modules/retry": { @@ -23506,14 +23271,6 @@ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "license": "0BSD" }, - "node_modules/ttys": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/ttys/-/ttys-0.0.3.tgz", - "integrity": "sha512-UCqXRZS2S7U4aVB7Salj3ChPRSsb57ogJpJ1eMCvyowxFOBGsaHKcRU8bovcDwajX1mRbv0IpUnYkoG7Ieo5Zg==", - "engines": { - "node": ">= 0.6.0" - } - }, "node_modules/tuf-js": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/tuf-js/-/tuf-js-3.1.0.tgz", @@ -25289,6 +25046,7 @@ "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", "deprecated": "Use @exodus/bytes instead for a more spec-conformant and faster implementation", + "dev": true, "license": "MIT", "dependencies": { "iconv-lite": "0.6.3" @@ -25301,6 +25059,7 @@ "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" @@ -25313,6 +25072,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", + "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -25833,27 +25593,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/yt-search": { - "version": "2.13.1", - "resolved": "https://registry.npmjs.org/yt-search/-/yt-search-2.13.1.tgz", - "integrity": "sha512-iUvUpUYyG1Gk5MxwdxUkSeugXR2DcWX+pEq3rJlsNHHNp4+Lka+fCwNYEdoN5ovxltAzAvx0K3/3MbX7FqDdAw==", - "license": "MIT", - "dependencies": { - "async.parallellimit": "~0.5.2", - "boolstring": "~2.0.1", - "cheerio": "^1.0.0-rc.10", - "dasu": "~0.4.3", - "human-time": "0.0.2", - "jsonpath-plus": "~10.3.0", - "minimist": "~1.2.5", - "node-fzf": "~0.14.0" - }, - "bin": { - "yt-search": "bin/cli.js", - "yt-search-audio": "bin/mpv_audio.sh", - "yt-search-video": "bin/mpv_video.sh" - } - }, "node_modules/ytdlp-nodejs": { "version": "3.4.4", "resolved": "https://registry.npmjs.org/ytdlp-nodejs/-/ytdlp-nodejs-3.4.4.tgz", @@ -25887,7 +25626,6 @@ "@nestjs/serve-static": "^4.0.2", "@nestjs/typeorm": "^10.0.2", "@nestjs/websockets": "^10.3.10", - "@types/yt-search": "^2.10.3", "bullmq": "^5.31.2", "isomorphic-unfetch": "^4.0.2", "node-id3": "^0.2.9", @@ -25895,7 +25633,6 @@ "rxjs": "7.8.0", "spotify-url-info": "^3.2.18", "sqlite3": "^5.1.7", - "yt-search": "^2.12.1", "ytdlp-nodejs": "^3.4.4" }, "devDependencies": { diff --git a/src/backend/package.json b/src/backend/package.json index fa71ed0..714ea0f 100644 --- a/src/backend/package.json +++ b/src/backend/package.json @@ -31,7 +31,6 @@ "@nestjs/serve-static": "^4.0.2", "@nestjs/typeorm": "^10.0.2", "@nestjs/websockets": "^10.3.10", - "@types/yt-search": "^2.10.3", "bullmq": "^5.31.2", "isomorphic-unfetch": "^4.0.2", "node-id3": "^0.2.9", @@ -39,7 +38,6 @@ "rxjs": "7.8.0", "spotify-url-info": "^3.2.18", "sqlite3": "^5.1.7", - "yt-search": "^2.12.1", "ytdlp-nodejs": "^3.4.4" }, "devDependencies": { diff --git a/src/backend/src/shared/youtube.service.ts b/src/backend/src/shared/youtube.service.ts index 69d83c2..7b1cf18 100644 --- a/src/backend/src/shared/youtube.service.ts +++ b/src/backend/src/shared/youtube.service.ts @@ -3,7 +3,6 @@ import { TrackEntity } from '../track/track.entity'; import { EnvironmentEnum } from '../environmentEnum'; import { TrackService } from '../track/track.service'; import { ConfigService } from '@nestjs/config'; -import * as yts from 'yt-search'; import * as fs from 'fs'; import { spawn } from 'child_process'; const NodeID3 = require('node-id3'); @@ -63,6 +62,16 @@ interface CandidateScore extends YoutubeMatch { rejected: boolean; } +interface YtDlpSearchVideo { + url?: string; + webpage_url?: string; + id?: string; + title?: string; + uploader?: string; + channel?: string; + duration?: number; +} + @Injectable() export class YoutubeService { private readonly logger = new Logger(TrackService.name); @@ -78,14 +87,14 @@ export class YoutubeService { const query = `${artist} - ${name}`; this.logger.debug(`Searching ${query} on YT`); - const result = await yts(query); + const videos = await this.searchYoutubeVideos(query); const excludedVideoIds = new Set( excludedUrls .map((url) => this.getYoutubeVideoId(url)) .filter((id): id is string => !!id), ); - const candidates = (result.videos || []) + const candidates = videos .filter((video: any) => !!video?.url && !!video?.title) .filter((video: any) => { const videoId = this.getYoutubeVideoId(String(video.url)); @@ -130,6 +139,55 @@ export class YoutubeService { return accepted; } + private async searchYoutubeVideos(query: string): Promise { + const searchTarget = `ytsearch15:${query}`; + const args = [ + '--dump-single-json', + '--flat-playlist', + '--skip-download', + '--no-playlist', + '--no-cache-dir', + '--no-cookies-from-browser', + '--add-header', + `User-Agent:${HEADERS['User-Agent']}`, + searchTarget, + ]; + + const output = await this.runYtDlpForOutput(args); + let parsed: any; + + try { + parsed = JSON.parse(output); + } catch (error) { + throw new Error(`Failed to parse yt-dlp search output: ${(error as Error).message}`); + } + + const entries = Array.isArray(parsed?.entries) ? parsed.entries : []; + return entries + .filter((entry: YtDlpSearchVideo) => !!entry?.title && (!!entry?.url || !!entry?.webpage_url || !!entry?.id)) + .map((entry: YtDlpSearchVideo) => ({ + ...entry, + url: this.normalizeYtDlpVideoUrl(entry), + author: entry.uploader || entry.channel || '', + seconds: typeof entry.duration === 'number' ? entry.duration : undefined, + })); + } + + private normalizeYtDlpVideoUrl(video: YtDlpSearchVideo): string { + const rawUrl = String(video.webpage_url || video.url || ''); + + if (rawUrl.startsWith('http://') || rawUrl.startsWith('https://')) { + return rawUrl; + } + + const id = String(video.id || rawUrl || '').trim(); + if (!id) { + return ''; + } + + return `https://www.youtube.com/watch?v=${id}`; + } + private scoreCandidate( video: any, artist: string, @@ -343,7 +401,7 @@ export class YoutubeService { return tempCookiesFile; } - private runYtDlp(args: string[]): Promise { + private runYtDlpForOutput(args: string[]): Promise { return new Promise((resolvePromise, rejectPromise) => { const child = spawn('yt-dlp', args, { stdio: ['ignore', 'pipe', 'pipe'], @@ -352,11 +410,11 @@ export class YoutubeService { let stdout = ''; let stderr = ''; - child.stdout.on('data', (chunk) => { + child.stdout?.on('data', (chunk) => { stdout += chunk.toString(); }); - child.stderr.on('data', (chunk) => { + child.stderr?.on('data', (chunk) => { stderr += chunk.toString(); }); @@ -366,7 +424,7 @@ export class YoutubeService { child.on('close', (code) => { if (code === 0) { - resolvePromise(); + resolvePromise(stdout); return; } @@ -379,6 +437,10 @@ export class YoutubeService { }); } + private async runYtDlp(args: string[]): Promise { + await this.runYtDlpForOutput(args); + } + async downloadAndFormat(track: TrackEntity, output: string): Promise { this.logger.debug( `Downloading ${track.artist} - ${track.name} (${track.youtubeUrl}) from YT`,