mirror of
https://github.com/wukko/cobalt.git
synced 2024-11-06 00:10:02 +00:00
7.12: private traffic stats with plausible and no watermark for tiktok videos by default (#392)
This commit is contained in:
commit
633fc39308
13 changed files with 99 additions and 157 deletions
36
README.md
36
README.md
|
@ -89,3 +89,39 @@ you are allowed to host an ***unmodified*** instance of cobalt with branding, bu
|
||||||
- [Fluent Emoji by Microsoft](https://github.com/microsoft/fluentui-emoji) (used in cobalt) is under [MIT](https://github.com/microsoft/fluentui-emoji/blob/main/LICENSE) license.
|
- [Fluent Emoji by Microsoft](https://github.com/microsoft/fluentui-emoji) (used in cobalt) is under [MIT](https://github.com/microsoft/fluentui-emoji/blob/main/LICENSE) license.
|
||||||
- [Noto Sans Mono](https://fonts.google.com/noto/specimen/Noto+Sans+Mono/) fonts (used in cobalt) are licensed under the [OFL](https://fonts.google.com/noto/specimen/Noto+Sans+Mono/about) license.
|
- [Noto Sans Mono](https://fonts.google.com/noto/specimen/Noto+Sans+Mono/) fonts (used in cobalt) are licensed under the [OFL](https://fonts.google.com/noto/specimen/Noto+Sans+Mono/about) license.
|
||||||
- many update banners were taken from [tenor.com](https://tenor.com/).
|
- many update banners were taken from [tenor.com](https://tenor.com/).
|
||||||
|
|
||||||
|
## acknowledgements
|
||||||
|
### ffmpeg
|
||||||
|
cobalt heavily relies on ffmpeg for converting and merging media files. it's an absolutely amazing piece of software offered for anyone for free, yet doesn't receive as much credit as it should.
|
||||||
|
|
||||||
|
you can [support ffmpeg here](https://ffmpeg.org/donations.html)!
|
||||||
|
|
||||||
|
#### ffmpeg-static
|
||||||
|
we use [ffmpeg-static](https://github.com/eugeneware/ffmpeg-static) to get binaries for ffmpeg depending on the platform.
|
||||||
|
|
||||||
|
you can support the developer via various methods listed on their github page! (linked above)
|
||||||
|
|
||||||
|
### youtube.js
|
||||||
|
cobalt relies on [youtube.js](https://github.com/LuanRT/YouTube.js) for interacting with the innertube api, it wouldn't have been possible.
|
||||||
|
|
||||||
|
you can support the developer via various methods listed on their github page! (linked above)
|
||||||
|
|
||||||
|
### many others
|
||||||
|
cobalt also depends on:
|
||||||
|
|
||||||
|
- [content-disposition-header](https://www.npmjs.com/package/content-disposition-header) to simplify the provision of `content-disposition` headers.
|
||||||
|
- [cors](https://www.npmjs.com/package/cors) to manage cross-origin resource sharing within expressjs.
|
||||||
|
- [dotenv](https://www.npmjs.com/package/dotenv) to load environment variables from the `.env` file.
|
||||||
|
- [esbuild](https://www.npmjs.com/package/esbuild) to minify the frontend files.
|
||||||
|
- [express](https://www.npmjs.com/package/express) as the backbone of cobalt servers.
|
||||||
|
- [express-rate-limit](https://www.npmjs.com/package/express-rate-limit) to rate limit api endpoints.
|
||||||
|
- [hls-parser](https://www.npmjs.com/package/hls-parser) to parse `m3u8` playlists for certain services.
|
||||||
|
- [ipaddr.js](https://www.npmjs.com/package/ipaddr.js) to parse ip addresses (for rate limiting).
|
||||||
|
- [nanoid](https://www.npmjs.com/package/nanoid) to generate unique (temporary) identifiers for each requested stream.
|
||||||
|
- [node-cache](https://www.npmjs.com/package/node-cache) to cache stream info in server ram for a limited amount of time.
|
||||||
|
- [psl](https://www.npmjs.com/package/psl) as the domain name parser.
|
||||||
|
- [set-cookie-parser](https://www.npmjs.com/package/set-cookie-parser) to parse cookies that cobalt receives from certain services.
|
||||||
|
- [undici](https://www.npmjs.com/package/undici) for making http requests
|
||||||
|
- [url-pattern](https://www.npmjs.com/package/url-pattern) to match provided links with supported patterns.
|
||||||
|
|
||||||
|
...and many other packages that these packages rely on.
|
|
@ -27,7 +27,6 @@ Content-Type: application/json
|
||||||
| `aFormat` | `string` | `best / mp3 / ogg / wav / opus` | `mp3` | |
|
| `aFormat` | `string` | `best / mp3 / ogg / wav / opus` | `mp3` | |
|
||||||
| `filenamePattern` | `string` | `classic / pretty / basic / nerdy` | `classic` | changes the way files are named. previews can be seen in the web app. |
|
| `filenamePattern` | `string` | `classic / pretty / basic / nerdy` | `classic` | changes the way files are named. previews can be seen in the web app. |
|
||||||
| `isAudioOnly` | `boolean` | `true / false` | `false` | |
|
| `isAudioOnly` | `boolean` | `true / false` | `false` | |
|
||||||
| `isNoTTWatermark` | `boolean` | `true / false` | `false` | changes whether downloaded tiktok videos have watermarks. |
|
|
||||||
| `isTTFullAudio` | `boolean` | `true / false` | `false` | enables download of original sound used in a tiktok video. |
|
| `isTTFullAudio` | `boolean` | `true / false` | `false` | enables download of original sound used in a tiktok video. |
|
||||||
| `isAudioMuted` | `boolean` | `true / false` | `false` | disables audio track in video downloads. |
|
| `isAudioMuted` | `boolean` | `true / false` | `false` | disables audio track in video downloads. |
|
||||||
| `dubLang` | `boolean` | `true / false` | `false` | backend uses Accept-Language header for youtube video audio tracks when `true`. |
|
| `dubLang` | `boolean` | `true / false` | `false` | backend uses Accept-Language header for youtube video audio tracks when `true`. |
|
||||||
|
|
|
@ -63,10 +63,13 @@ sudo service nscd start
|
||||||
\* the higher the nice value, the lower the priority. [read more here](https://en.wikipedia.org/wiki/Nice_(Unix)).
|
\* the higher the nice value, the lower the priority. [read more here](https://en.wikipedia.org/wiki/Nice_(Unix)).
|
||||||
|
|
||||||
### variables for web
|
### variables for web
|
||||||
| variable name | default | example | description |
|
| variable name | default | example | description |
|
||||||
|:--------------- |:---------------------|:------------------------|:--------------------------------------------------------------------------------------|
|
|:---------------------|:---------------------|:------------------------|:--------------------------------------------------------------------------------------|
|
||||||
| `WEB_PORT` | `9001` | `9001` | changes port from which frontend server is accessible. |
|
| `WEB_PORT` | `9001` | `9001` | changes port from which frontend server is accessible. |
|
||||||
| `WEB_URL` | ➖ | `https://cobalt.tools/` | changes url from which frontend server is accessible. <br> ***REQUIRED TO RUN WEB***. |
|
| `WEB_URL` | ➖ | `https://cobalt.tools/` | changes url from which frontend server is accessible. <br> ***REQUIRED TO RUN WEB***. |
|
||||||
| `API_URL` | `https://co.wuk.sh/` | `https://co.wuk.sh/` | changes url which is used for api requests by frontend clients. |
|
| `API_URL` | `https://co.wuk.sh/` | `https://co.wuk.sh/` | changes url which is used for api requests by frontend clients. |
|
||||||
| `SHOW_SPONSORS` | `0` | `1` | toggles sponsor list in about popup. <br> `0`: disabled. `1`: enabled. |
|
| `SHOW_SPONSORS` | `0` | `1` | toggles sponsor list in about popup. <br> `0`: disabled. `1`: enabled. |
|
||||||
| `IS_BETA` | `0` | `1` | toggles beta tag next to cobalt logo. <br> `0`: disabled. `1`: enabled. |
|
| `IS_BETA` | `0` | `1` | toggles beta tag next to cobalt logo. <br> `0`: disabled. `1`: enabled. |
|
||||||
|
| `PLAUSIBLE_HOSTNAME` | ➖ | `plausible.io`* | enables plausible analytics with provided hostname as receiver backend. |
|
||||||
|
|
||||||
|
\* don't use plausible.io as receiver backend unless you paid for their cloud service. use your own domain when hosting community edition of plausible. refer to their [docs](https://plausible.io/docs) when needed.
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "cobalt",
|
"name": "cobalt",
|
||||||
"description": "save what you love",
|
"description": "save what you love",
|
||||||
"version": "7.11.2",
|
"version": "7.12",
|
||||||
"author": "wukko",
|
"author": "wukko",
|
||||||
"exports": "./src/cobalt.js",
|
"exports": "./src/cobalt.js",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
@ -25,7 +25,6 @@
|
||||||
},
|
},
|
||||||
"homepage": "https://github.com/wukko/cobalt#readme",
|
"homepage": "https://github.com/wukko/cobalt#readme",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"abort-controller": "3.0.0",
|
|
||||||
"content-disposition-header": "0.6.0",
|
"content-disposition-header": "0.6.0",
|
||||||
"cors": "^2.8.5",
|
"cors": "^2.8.5",
|
||||||
"dotenv": "^16.0.1",
|
"dotenv": "^16.0.1",
|
||||||
|
|
|
@ -24,13 +24,13 @@ const checkboxes = [
|
||||||
"alwaysVisibleButton",
|
"alwaysVisibleButton",
|
||||||
"disableChangelog",
|
"disableChangelog",
|
||||||
"downloadPopup",
|
"downloadPopup",
|
||||||
"disableTikTokWatermark",
|
|
||||||
"fullTikTokAudio",
|
"fullTikTokAudio",
|
||||||
"muteAudio",
|
"muteAudio",
|
||||||
"reduceTransparency",
|
"reduceTransparency",
|
||||||
"disableAnimations",
|
"disableAnimations",
|
||||||
"disableMetadata",
|
"disableMetadata",
|
||||||
"twitterGif",
|
"twitterGif",
|
||||||
|
"plausible_ignore"
|
||||||
];
|
];
|
||||||
const exceptions = { // used for mobile devices
|
const exceptions = { // used for mobile devices
|
||||||
"vQuality": "720"
|
"vQuality": "720"
|
||||||
|
@ -369,13 +369,11 @@ async function download(url) {
|
||||||
if (sGet("vimeoDash") === "true") req.vimeoDash = true;
|
if (sGet("vimeoDash") === "true") req.vimeoDash = true;
|
||||||
if (sGet("audioMode") === "true") {
|
if (sGet("audioMode") === "true") {
|
||||||
req.isAudioOnly = true;
|
req.isAudioOnly = true;
|
||||||
req.isNoTTWatermark = true; // video tiktok no watermark
|
|
||||||
if (sGet("fullTikTokAudio") === "true") req.isTTFullAudio = true; // audio tiktok full
|
if (sGet("fullTikTokAudio") === "true") req.isTTFullAudio = true; // audio tiktok full
|
||||||
} else {
|
} else {
|
||||||
req.vQuality = sGet("vQuality").slice(0, 4);
|
req.vQuality = sGet("vQuality").slice(0, 4);
|
||||||
if (sGet("muteAudio") === "true") req.isAudioMuted = true;
|
if (sGet("muteAudio") === "true") req.isAudioMuted = true;
|
||||||
if (url.includes("youtube.com/") || url.includes("/youtu.be/")) req.vCodec = sGet("vCodec").slice(0, 4);
|
if (url.includes("youtube.com/") || url.includes("/youtu.be/")) req.vCodec = sGet("vCodec").slice(0, 4);
|
||||||
if ((url.includes("tiktok.com/") || url.includes("douyin.com/")) && sGet("disableTikTokWatermark") === "true") req.isNoTTWatermark = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sGet("disableMetadata") === "true") req.disableMetadata = true;
|
if (sGet("disableMetadata") === "true") req.disableMetadata = true;
|
||||||
|
@ -566,7 +564,12 @@ function loadSettings() {
|
||||||
eid("cobalt-body").classList.add('no-animation');
|
eid("cobalt-body").classList.add('no-animation');
|
||||||
}
|
}
|
||||||
for (let i = 0; i < checkboxes.length; i++) {
|
for (let i = 0; i < checkboxes.length; i++) {
|
||||||
if (sGet(checkboxes[i]) === "true") eid(checkboxes[i]).checked = true;
|
try {
|
||||||
|
if (sGet(checkboxes[i]) === "true") eid(checkboxes[i]).checked = true;
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
console.error(`checkbox ${checkboxes[i]} failed to initialize`)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for (let i in switchers) {
|
for (let i in switchers) {
|
||||||
changeSwitcher(i, sGet(i))
|
changeSwitcher(i, sGet(i))
|
||||||
|
|
|
@ -62,7 +62,6 @@
|
||||||
"SettingsAudioFormatBest": "best",
|
"SettingsAudioFormatBest": "best",
|
||||||
"SettingsAudioFormatDescription": "when \"best\" format is selected, you get audio the way it is on service's side. it's not re-encoded. everything else will be re-encoded.",
|
"SettingsAudioFormatDescription": "when \"best\" format is selected, you get audio the way it is on service's side. it's not re-encoded. everything else will be re-encoded.",
|
||||||
"Keyphrase": "save what you love",
|
"Keyphrase": "save what you love",
|
||||||
"SettingsRemoveWatermark": "disable watermark",
|
|
||||||
"ErrorPopupCloseButton": "got it",
|
"ErrorPopupCloseButton": "got it",
|
||||||
"ErrorLengthAudioConvert": "i can't convert audio longer than {s} minutes. pick \"best\" format if you want to avoid limitations!",
|
"ErrorLengthAudioConvert": "i can't convert audio longer than {s} minutes. pick \"best\" format if you want to avoid limitations!",
|
||||||
"SettingsAudioFullTikTok": "full audio",
|
"SettingsAudioFullTikTok": "full audio",
|
||||||
|
@ -156,6 +155,10 @@
|
||||||
"SettingsTwitterGifDescription": "converting looping videos to .gif reduces quality and majorly increases file size. if you want best efficiency, keep this setting off.",
|
"SettingsTwitterGifDescription": "converting looping videos to .gif reduces quality and majorly increases file size. if you want best efficiency, keep this setting off.",
|
||||||
"ErrorTweetProtected": "this tweet is from a private account, so i can't see it. try another one!",
|
"ErrorTweetProtected": "this tweet is from a private account, so i can't see it. try another one!",
|
||||||
"ErrorTweetNSFW": "this tweet contains sensitive content, so i can't see it. try another one!",
|
"ErrorTweetNSFW": "this tweet contains sensitive content, so i can't see it. try another one!",
|
||||||
"UpdateEncryption": "encryption and new services"
|
"UpdateEncryption": "encryption and new services",
|
||||||
|
"PrivateAnalytics": "private analytics",
|
||||||
|
"SettingsDisableAnalytics": "opt out of private analytics",
|
||||||
|
"SettingsAnalyticsExplanation": "enable if you don't want to be included in anonymous traffic stats. read more about this in about > privacy policy (tl;dr: nothing about you is ever stored or tracked, no cookies are used).",
|
||||||
|
"AnalyticsDescription": "cobalt uses a self-hosted plausible instance to get an approximate number of how many people use it.\n\nplausible is fully compliant with GDPR, CCPA and PECR, doesn't use cookies, and never stores any identifiable info, not even your ip address.\n\nall data is aggregated and never personalized. nothing about what you download is ever saved anywhere. it's used just for anonymous traffic stats, nothing more.\n\nplausible is fully open source, just like cobalt, and if you want to learn more about it, you can do so <a class=\"text-backdrop link\" href=\"https://plausible.io\" target=\"_blank\">here</a>. if you wish to opt out of traffic stats, you can do it in settings > other."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,7 +62,6 @@
|
||||||
"SettingsAudioFormatBest": "лучший",
|
"SettingsAudioFormatBest": "лучший",
|
||||||
"SettingsAudioFormatDescription": "когда выбран \"лучший\", ты получишь аудио без каких-либо изменений. такое, какое оно есть на стороне сервиса. если же выбрано что-то другое, то аудио будет немного сжато.",
|
"SettingsAudioFormatDescription": "когда выбран \"лучший\", ты получишь аудио без каких-либо изменений. такое, какое оно есть на стороне сервиса. если же выбрано что-то другое, то аудио будет немного сжато.",
|
||||||
"Keyphrase": "сохраняй то, что любишь",
|
"Keyphrase": "сохраняй то, что любишь",
|
||||||
"SettingsRemoveWatermark": "убрать ватермарку",
|
|
||||||
"ErrorPopupCloseButton": "ясно",
|
"ErrorPopupCloseButton": "ясно",
|
||||||
"ErrorLengthAudioConvert": "я не могу конвертировать аудио дольше чем {s} минут(ы). выбери \"лучший\" формат, чтобы обойти ограничения.",
|
"ErrorLengthAudioConvert": "я не могу конвертировать аудио дольше чем {s} минут(ы). выбери \"лучший\" формат, чтобы обойти ограничения.",
|
||||||
"SettingsAudioFullTikTok": "полное аудио",
|
"SettingsAudioFullTikTok": "полное аудио",
|
||||||
|
@ -158,6 +157,10 @@
|
||||||
"SettingsTwitterGifDescription": "конвертирование зацикленного видео в .gif снижает качество и значительно увеличивает размер файла. если важна максимальная эффективность, то не используй эту функцию.",
|
"SettingsTwitterGifDescription": "конвертирование зацикленного видео в .gif снижает качество и значительно увеличивает размер файла. если важна максимальная эффективность, то не используй эту функцию.",
|
||||||
"ErrorTweetProtected": "этот твит из закрытого аккаунта, поэтому я не могу его увидеть. попробуй другой!",
|
"ErrorTweetProtected": "этот твит из закрытого аккаунта, поэтому я не могу его увидеть. попробуй другой!",
|
||||||
"ErrorTweetNSFW": "этот твит содержит деликатный контент, поэтому я не могу его увидеть. попробуй другой!",
|
"ErrorTweetNSFW": "этот твит содержит деликатный контент, поэтому я не могу его увидеть. попробуй другой!",
|
||||||
"UpdateEncryption": "шифрование и новые сервисы"
|
"UpdateEncryption": "шифрование и новые сервисы",
|
||||||
|
"PrivateAnalytics": "приватная аналитика",
|
||||||
|
"SettingsDisableAnalytics": "отключить приватную аналитику",
|
||||||
|
"SettingsAnalyticsExplanation": "включи, если не хочешь быть частью анонимной статистики трафика. подробнее об этом можно прочитать в политике конфиденциальности (tl;dr: ничего о тебе или твоих действиях не хранится и не отслеживается, даже куки нет).",
|
||||||
|
"AnalyticsDescription": "кобальт использует собственный инстанс plausible чтобы иметь приблизительное представление о том, сколько людей им пользуются.\n\nplausible полностью соответствует GDPR, CCPA и PECR, не использует куки и никогда не хранит никакой идентифицируемой информации, даже ip-адрес.\n\nвсе данные агрегируются и никогда не персонализируются. ничего о том, что ты скачиваешь, никогда не сохраняется. это просто анонимная статистика трафика, ничего больше.\n\nplausible также как и кобальт имеет открытый исходный код, и, если ты хочешь узнать о нём больше, то это можно сделать <a class=\"text-backdrop link\" href=\"https://plausible.io\" target=\"_blank\">здесь</a>. а если же ты хочешь исключить себя из статистики, то это можно сделать в настройках > другое."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,6 +74,14 @@ export default function(obj) {
|
||||||
<link rel="preload" href="fonts/notosansmono.css" as="style">
|
<link rel="preload" href="fonts/notosansmono.css" as="style">
|
||||||
<link rel="preload" href="assets/meowbalt/error.png" as="image">
|
<link rel="preload" href="assets/meowbalt/error.png" as="image">
|
||||||
<link rel="preload" href="assets/meowbalt/question.png" as="image">
|
<link rel="preload" href="assets/meowbalt/question.png" as="image">
|
||||||
|
|
||||||
|
${process.env.PLAUSIBLE_HOSTNAME ?
|
||||||
|
`<script
|
||||||
|
defer
|
||||||
|
data-domain="${new URL(process.env.WEB_URL).hostname}"
|
||||||
|
src="https://${process.env.PLAUSIBLE_HOSTNAME}/js/script.js"
|
||||||
|
></script>`
|
||||||
|
: ''}
|
||||||
</head>
|
</head>
|
||||||
<body id="cobalt-body" ${platform === "d" ? 'class="desktop"' : ''}>
|
<body id="cobalt-body" ${platform === "d" ? 'class="desktop"' : ''}>
|
||||||
<noscript>
|
<noscript>
|
||||||
|
@ -160,7 +168,9 @@ export default function(obj) {
|
||||||
}, {
|
}, {
|
||||||
name: "privacy",
|
name: "privacy",
|
||||||
title: `${emoji("🔒")} ${t("CollapsePrivacy")}`,
|
title: `${emoji("🔒")} ${t("CollapsePrivacy")}`,
|
||||||
body: t("PrivacyPolicy")
|
body: t("PrivacyPolicy") + `${
|
||||||
|
process.env.PLAUSIBLE_HOSTNAME ? `<br><br>${t("AnalyticsDescription")}` : ''
|
||||||
|
}`
|
||||||
}, {
|
}, {
|
||||||
name: "legal",
|
name: "legal",
|
||||||
title: `${emoji("📑")} ${t("CollapseLegal")}`,
|
title: `${emoji("📑")} ${t("CollapseLegal")}`,
|
||||||
|
@ -328,15 +338,6 @@ export default function(obj) {
|
||||||
}]
|
}]
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
+ settingsCategory({
|
|
||||||
name: "tiktok-watermark",
|
|
||||||
title: "tiktok",
|
|
||||||
body: checkbox([{
|
|
||||||
action: "disableTikTokWatermark",
|
|
||||||
name: t("SettingsRemoveWatermark"),
|
|
||||||
padding: "no-margin"
|
|
||||||
}])
|
|
||||||
})
|
|
||||||
+ settingsCategory({
|
+ settingsCategory({
|
||||||
name: "twitter",
|
name: "twitter",
|
||||||
title: "twitter",
|
title: "twitter",
|
||||||
|
@ -497,6 +498,21 @@ export default function(obj) {
|
||||||
padding: "no-margin"
|
padding: "no-margin"
|
||||||
}])
|
}])
|
||||||
})
|
})
|
||||||
|
+ (() => {
|
||||||
|
if (process.env.PLAUSIBLE_HOSTNAME) {
|
||||||
|
return settingsCategory({
|
||||||
|
name: "privacy",
|
||||||
|
title: t('PrivateAnalytics'),
|
||||||
|
body: checkbox([{
|
||||||
|
action: "plausible_ignore",
|
||||||
|
name: t("SettingsDisableAnalytics"),
|
||||||
|
padding: "no-margin"
|
||||||
|
}])
|
||||||
|
+ explanation(t('SettingsAnalyticsExplanation'))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return ''
|
||||||
|
})()
|
||||||
+ settingsCategory({
|
+ settingsCategory({
|
||||||
name: "miscellaneous",
|
name: "miscellaneous",
|
||||||
title: t('Miscellaneous'),
|
title: t('Miscellaneous'),
|
||||||
|
|
|
@ -89,7 +89,6 @@ export default async function(host, patternMatch, url, lang, obj) {
|
||||||
host: host,
|
host: host,
|
||||||
postId: patternMatch.postId,
|
postId: patternMatch.postId,
|
||||||
id: patternMatch.id,
|
id: patternMatch.id,
|
||||||
noWatermark: obj.isNoTTWatermark,
|
|
||||||
fullAudio: obj.isTTFullAudio,
|
fullAudio: obj.isTTFullAudio,
|
||||||
isAudioOnly: isAudioOnly
|
isAudioOnly: isAudioOnly
|
||||||
});
|
});
|
||||||
|
|
|
@ -58,7 +58,9 @@ export default async function(obj) {
|
||||||
detail = selector(detail, obj.host, postId);
|
detail = selector(detail, obj.host, postId);
|
||||||
if (!detail) return { error: 'ErrorCouldntFetch' };
|
if (!detail) return { error: 'ErrorCouldntFetch' };
|
||||||
|
|
||||||
let video, videoFilename, audioFilename, isMp3, audio, images, filenameBase = `${obj.host}_${postId}`;
|
let video, videoFilename, audioFilename, isMp3, audio, images,
|
||||||
|
filenameBase = `${obj.host}_${detail.author.unique_id}_${postId}`;
|
||||||
|
|
||||||
if (obj.host === "tiktok") {
|
if (obj.host === "tiktok") {
|
||||||
images = detail.image_post_info ? detail.image_post_info.images : false
|
images = detail.image_post_info ? detail.image_post_info.images : false
|
||||||
} else {
|
} else {
|
||||||
|
@ -66,14 +68,10 @@ export default async function(obj) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!obj.isAudioOnly && !images) {
|
if (!obj.isAudioOnly && !images) {
|
||||||
video = obj.host === "tiktok" ? detail.video.download_addr.url_list[0] : detail.video.play_addr.url_list[2].replace("/play/", "/playwm/");
|
video = detail.video.play_addr.url_list[0];
|
||||||
videoFilename = `${filenameBase}_video.mp4`;
|
videoFilename = `${filenameBase}.mp4`;
|
||||||
if (obj.noWatermark) {
|
|
||||||
video = obj.host === "tiktok" ? detail.video.play_addr.url_list[0] : detail.video.play_addr.url_list[0];
|
|
||||||
videoFilename = `${filenameBase}_video_nw.mp4` // nw - no watermark
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
let fallback = obj.host === "douyin" ? detail.video.play_addr.url_list[0].replace("playwm", "play") : detail.video.play_addr.url_list[0];
|
let fallback = detail.video.play_addr.url_list[0];
|
||||||
audio = fallback;
|
audio = fallback;
|
||||||
audioFilename = `${filenameBase}_audio_fv`; // fv - from video
|
audioFilename = `${filenameBase}_audio_fv`; // fv - from video
|
||||||
if (obj.fullAudio || fallback.includes("music")) {
|
if (obj.fullAudio || fallback.includes("music")) {
|
||||||
|
|
|
@ -4,7 +4,6 @@ import { ffmpegArgs, genericUserAgent } from "../config.js";
|
||||||
import { metadataManager } from "../sub/utils.js";
|
import { metadataManager } from "../sub/utils.js";
|
||||||
import { request } from "undici";
|
import { request } from "undici";
|
||||||
import { create as contentDisposition } from "content-disposition-header";
|
import { create as contentDisposition } from "content-disposition-header";
|
||||||
import { AbortController } from "abort-controller"
|
|
||||||
|
|
||||||
function closeRequest(controller) {
|
function closeRequest(controller) {
|
||||||
try { controller.abort() } catch {}
|
try { controller.abort() } catch {}
|
||||||
|
|
|
@ -9,7 +9,7 @@ const apiVar = {
|
||||||
aFormat: ["best", "mp3", "ogg", "wav", "opus"],
|
aFormat: ["best", "mp3", "ogg", "wav", "opus"],
|
||||||
filenamePattern: ["classic", "pretty", "basic", "nerdy"]
|
filenamePattern: ["classic", "pretty", "basic", "nerdy"]
|
||||||
},
|
},
|
||||||
booleanOnly: ["isAudioOnly", "isNoTTWatermark", "isTTFullAudio", "isAudioMuted", "dubLang", "vimeoDash", "disableMetadata", "twitterGif"]
|
booleanOnly: ["isAudioOnly", "isTTFullAudio", "isAudioMuted", "dubLang", "vimeoDash", "disableMetadata", "twitterGif"]
|
||||||
}
|
}
|
||||||
const forbiddenCharsString = ['}', '{', '%', '>', '<', '^', ';', '`', '$', '"', "@", '='];
|
const forbiddenCharsString = ['}', '{', '%', '>', '<', '^', ';', '`', '$', '"', "@", '='];
|
||||||
|
|
||||||
|
@ -79,7 +79,6 @@ export function checkJSONPost(obj) {
|
||||||
aFormat: "mp3",
|
aFormat: "mp3",
|
||||||
filenamePattern: "classic",
|
filenamePattern: "classic",
|
||||||
isAudioOnly: false,
|
isAudioOnly: false,
|
||||||
isNoTTWatermark: false,
|
|
||||||
isTTFullAudio: false,
|
isTTFullAudio: false,
|
||||||
isAudioMuted: false,
|
isAudioMuted: false,
|
||||||
disableMetadata: false,
|
disableMetadata: false,
|
||||||
|
|
|
@ -562,125 +562,10 @@
|
||||||
"status": "error"
|
"status": "error"
|
||||||
}
|
}
|
||||||
}],
|
}],
|
||||||
"douyin": [{
|
|
||||||
"name": "short link video, with watermark",
|
|
||||||
"url": "https://v.douyin.com/2p4Aya7/",
|
|
||||||
"params": {},
|
|
||||||
"expected": {
|
|
||||||
"code": 200,
|
|
||||||
"status": "stream"
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
"name": "short link video (isNoTTWatermark)",
|
|
||||||
"url": "https://v.douyin.com/2p4Aya7/",
|
|
||||||
"params": {
|
|
||||||
"isNoTTWatermark": true
|
|
||||||
},
|
|
||||||
"expected": {
|
|
||||||
"code": 200,
|
|
||||||
"status": "stream"
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
"name": "short link video (isAudioOnly)",
|
|
||||||
"url": "https://v.douyin.com/2p4Aya7/",
|
|
||||||
"params": {
|
|
||||||
"isAudioOnly": true
|
|
||||||
},
|
|
||||||
"expected": {
|
|
||||||
"code": 200,
|
|
||||||
"status": "stream"
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
"name": "short link video (isAudioOnly, isTTFullAudio)",
|
|
||||||
"url": "https://v.douyin.com/2p4Aya7/",
|
|
||||||
"params": {
|
|
||||||
"isAudioOnly": true,
|
|
||||||
"isTTFullAudio": true
|
|
||||||
},
|
|
||||||
"expected": {
|
|
||||||
"code": 200,
|
|
||||||
"status": "stream"
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
"name": "long link video (isNoTTWatermark)",
|
|
||||||
"url": "https://www.douyin.com/video/7120601033314716968",
|
|
||||||
"params": {
|
|
||||||
"isNoTTWatermark": true
|
|
||||||
},
|
|
||||||
"expected": {
|
|
||||||
"code": 200,
|
|
||||||
"status": "stream"
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
"name": "images",
|
|
||||||
"url": "https://v.douyin.com/MdVwo31/",
|
|
||||||
"params": {},
|
|
||||||
"expected": {
|
|
||||||
"code": 200,
|
|
||||||
"status": "picker"
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
"name": "long link inexistent",
|
|
||||||
"url": "https://www.douyin.com/video/7120851458451417478",
|
|
||||||
"params": {},
|
|
||||||
"expected": {
|
|
||||||
"code": 400,
|
|
||||||
"status": "error"
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
"name": "short link inexistent",
|
|
||||||
"url": "https://v.douyin.com/2p4ewa7/",
|
|
||||||
"params": {},
|
|
||||||
"expected": {
|
|
||||||
"code": 400,
|
|
||||||
"status": "error"
|
|
||||||
}
|
|
||||||
}],
|
|
||||||
"tiktok": [{
|
"tiktok": [{
|
||||||
"name": "short link (vt) video, with watermark",
|
"name": "long link video",
|
||||||
"url": "https://vt.tiktok.com/ZS85U86aa/",
|
|
||||||
"params": {},
|
|
||||||
"expected": {
|
|
||||||
"code": 200,
|
|
||||||
"status": "stream"
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
"name": "short link (vt) video (isNoTTWatermark)",
|
|
||||||
"url": "https://vt.tiktok.com/ZS85U86aa/",
|
|
||||||
"params": {
|
|
||||||
"isNoTTWatermark": true
|
|
||||||
},
|
|
||||||
"expected": {
|
|
||||||
"code": 200,
|
|
||||||
"status": "stream"
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
"name": "short link (vm) video (isAudioOnly)",
|
|
||||||
"url": "https://vm.tiktok.com/ZMYrYAf34/",
|
|
||||||
"params": {
|
|
||||||
"isAudioOnly": true
|
|
||||||
},
|
|
||||||
"expected": {
|
|
||||||
"code": 200,
|
|
||||||
"status": "stream"
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
"name": "short link (vm) video (isAudioOnly, isTTFullAudio)",
|
|
||||||
"url": "https://vm.tiktok.com/ZMYrYAf34/",
|
|
||||||
"params": {
|
|
||||||
"isAudioOnly": true,
|
|
||||||
"isTTFullAudio": true
|
|
||||||
},
|
|
||||||
"expected": {
|
|
||||||
"code": 200,
|
|
||||||
"status": "stream"
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
"name": "long link video (isNoTTWatermark)",
|
|
||||||
"url": "https://www.tiktok.com/@fatfatmillycat/video/7195741644585454894",
|
"url": "https://www.tiktok.com/@fatfatmillycat/video/7195741644585454894",
|
||||||
"params": {
|
"params": {},
|
||||||
"isNoTTWatermark": true
|
|
||||||
},
|
|
||||||
"expected": {
|
"expected": {
|
||||||
"code": 200,
|
"code": 200,
|
||||||
"status": "stream"
|
"status": "stream"
|
||||||
|
|
Loading…
Reference in a new issue