it's all about you and your native language!
- finally cleaned up localisation (now i18n) - made localisation strings easier to read and understand - removed static selected language in service modules - added support for russian language (привет-привет) - it's now extremely easy to add support for more languages. just copy en folder in i18n and start translating strings. pull requests for adding languages are more than welcome.
This commit is contained in:
parent
299fe6336b
commit
d08af58b11
20 changed files with 139 additions and 62 deletions
|
@ -17,10 +17,11 @@ cobalt doesn't remux any videos, so you get videos of max quality available (unl
|
||||||
|
|
||||||
## What still has to be done
|
## What still has to be done
|
||||||
- [ ] Quality switching for bilibili and Twitter
|
- [ ] Quality switching for bilibili and Twitter
|
||||||
- [ ] Clean up the mess that localisation is right now
|
- [ ] Language picker in settings
|
||||||
- [ ] Sort contents of .json files
|
- [x] Clean up the mess that localisation is right now
|
||||||
- [ ] Rename each entry key to be less linked to specific service (entries like youtubeBroke are awful, I'm sorry)
|
- [x] Sort contents of .json files
|
||||||
- [ ] Add support for more languages when localisation clean up is done
|
- [x] Rename each entry key to be less linked to specific service (entries like youtubeBroke are awful, I'm sorry)
|
||||||
|
- [x] Add support for more languages when localisation clean up is done
|
||||||
- [ ] Use esmbuild to minify frontend css and js
|
- [ ] Use esmbuild to minify frontend css and js
|
||||||
- [ ] Make switch buttons in settings selectable with keyboard
|
- [ ] Make switch buttons in settings selectable with keyboard
|
||||||
- [ ] Do something about changelog because the way it is right now is not really great
|
- [ ] Do something about changelog because the way it is right now is not really great
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
"maxVideoDuration": 1920000,
|
"maxVideoDuration": 1920000,
|
||||||
"genericUserAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36",
|
"genericUserAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36",
|
||||||
"repo": "https://github.com/wukko/cobalt",
|
"repo": "https://github.com/wukko/cobalt",
|
||||||
"supportedLanguages": ["en"],
|
"supportedLanguages": ["en", "ru"],
|
||||||
"authorInfo": {
|
"authorInfo": {
|
||||||
"name": "wukko",
|
"name": "wukko",
|
||||||
"link": "https://wukko.me/",
|
"link": "https://wukko.me/",
|
||||||
|
|
|
@ -1,21 +1,18 @@
|
||||||
{
|
{
|
||||||
"generic": "something went wrong and i couldn't get the video. you can try again,",
|
"generic": "something went wrong and i couldn't get anything for you. you can try again, but if issue persists, please <a class=\"text-backdrop nowrap\" href=\"{repo}\">let me know</a>.",
|
||||||
"notSupported": "it seems like this service is not supported yet or your link is invalid.",
|
"notSupported": "it seems like this service is not supported yet or your link is invalid.",
|
||||||
"brokenLink": "{s} is supported, but something is wrong with your link.",
|
"brokenLink": "{s} is supported, but something is wrong with your link. maybe you didn't copy it fully?",
|
||||||
"noURL": "i can't guess what you want to download! please give me a link.",
|
"noLink": "i can't guess what you want to download! please give me a link.",
|
||||||
"tryAgain": "\ncheck the link and try again.",
|
"noRender": "something went wrong and page couldn't render. if you want me to fix this, please <a href=\"https://wukko.me/contacts\">contact me</a>. it'd be useful if you provided the commit hash ({s}) along with recreation steps. thank you :D",
|
||||||
"letMeKnow": "but if issue persists, please <a class=\"text-backdrop nowrap\" href=\"{repo}\">let me know</a>.",
|
|
||||||
"fatal": "something went wrong and page couldn't render. if you want me to fix this, please <a href=\"https://wukko.me/contacts\">contact me</a>. it'd be useful if you provided the commit hash ({s}) along with recreation steps. thank you :D",
|
|
||||||
"rateLimit": "you're making way too many requests. calm down and try again in a few minutes.",
|
"rateLimit": "you're making way too many requests. calm down and try again in a few minutes.",
|
||||||
"youtubeFetch": "couldn't fetch metadata. check if your link is correct and try again.",
|
"noFetch": "couldn't fetch metadata. check if your link is correct and try again.",
|
||||||
"youtubeLimit": "current length limit is {s} minutes. what you tried to download was longer than that. pick something else to download!",
|
"lengthLimit": "current length limit is {s} minutes. what you tried to download was longer than that. pick something else to download!",
|
||||||
"youtubeBroke": "something went wrong with info fetching. you can try a different format and resoltuion or just try again later.",
|
"errorFetch": "something went wrong with info fetching. you can try a different format and resoltuion or just try again later.",
|
||||||
"corruptedVideo": "oddly enough the requested video is corrupted on its origin server. youtube does this sometimes because it's a hot pile of mess.",
|
"corruptedStream": "it seems like this download is corrupted. try again or try a different format and resolution.",
|
||||||
"corruptedAudio": "oddly enough the requested audio is corrupted on its origin server. youtube does this sometimes because it's a hot pile of mess.",
|
|
||||||
"noInternet": "it seems like there's no internet or {appName} api is down. check your connection and try again.",
|
"noInternet": "it seems like there's no internet or {appName} api is down. check your connection and try again.",
|
||||||
"liveVideo": "i can't download a live video. wait for stream to finish and try again.",
|
|
||||||
"nothingToDownload": "it seems like there's nothing to download. try another link!",
|
|
||||||
"cantConnectToAPI": "i couldn't connect to {s} api. seems like either {s} is down or {appName} server ip got blocked. try again later.",
|
"cantConnectToAPI": "i couldn't connect to {s} api. seems like either {s} is down or {appName} server ip got blocked. try again later.",
|
||||||
"noStreamID": "there's no such stream id.",
|
"nothingToDownload": "it seems like there's nothing to download. try another link!",
|
||||||
|
"liveVideo": "i can't download a live video. wait for stream to finish and try again.",
|
||||||
|
"noStreamID": "there's no such streamId.",
|
||||||
"noType": "there's no such expected response type."
|
"noType": "there's no such expected response type."
|
||||||
}
|
}
|
|
@ -16,6 +16,7 @@
|
||||||
"qmid": "medium\n",
|
"qmid": "medium\n",
|
||||||
"qlow": "low\n",
|
"qlow": "low\n",
|
||||||
"qlos": "lowest",
|
"qlos": "lowest",
|
||||||
"qualityDesc": "all resolutions listed here are max values. if there's no video of preferred quality, closest one gets picked instead.",
|
"qualityDesc": "if selected resolution isn't available, closest one gets picked instead.",
|
||||||
"extra": "extra"
|
"extra": "extra",
|
||||||
|
"audioOnly": "audio only"
|
||||||
}
|
}
|
|
@ -11,7 +11,7 @@
|
||||||
"donateDm": ">> let me know if currency you want to donate isn't listed",
|
"donateDm": ">> let me know if currency you want to donate isn't listed",
|
||||||
"clickToCopy": "click to copy",
|
"clickToCopy": "click to copy",
|
||||||
"iosDownload": "you have to press and hold the download button and then select \"download video\" in appeared popup to save the video. this is required because you have an ios device.",
|
"iosDownload": "you have to press and hold the download button and then select \"download video\" in appeared popup to save the video. this is required because you have an ios device.",
|
||||||
"normalDownload": "download button opens a new tab with requested video. you can disable this popup in settings.",
|
"normalDownload": "download button opens a new tab with requested file. you can disable this popup in settings.",
|
||||||
"download": "download",
|
"download": "download",
|
||||||
"copy": "copy url",
|
"copy": "copy url",
|
||||||
"open": "open",
|
"open": "open",
|
11
src/i18n/ru/accessibility.json
Normal file
11
src/i18n/ru/accessibility.json
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
{
|
||||||
|
"about": "Что за {appName}?",
|
||||||
|
"settings": "Открыть настройки",
|
||||||
|
"input": "Вставь ссылку сюда",
|
||||||
|
"download": "Кнопка скачивания",
|
||||||
|
"changelog": "Посмотреть последние изменения (на английском)",
|
||||||
|
"close": "Закрыть окно",
|
||||||
|
"alwaysVisibleButton": "Всегда оставлять кнопку скачивания на экране",
|
||||||
|
"downloadPopup": "Спрашивать что делать с загрузками",
|
||||||
|
"donate": "Пожертвования"
|
||||||
|
}
|
18
src/i18n/ru/apiError.json
Normal file
18
src/i18n/ru/apiError.json
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
{
|
||||||
|
"generic": "что-то пошло совсем не так и у меня не получилось ничего для тебя достать. ты можешь попробовать ещё раз, но если так и не получится, <a class=\"text-backdrop nowrap\" href=\"{repo}\">напиши об этом</a>.",
|
||||||
|
"notSupported": "этот сервис ещё не поддерживается или с твоей ссылкой что-то не так.",
|
||||||
|
"brokenLink": "{s} поддерживается, но с твоей ссылкой что-то не так. может быть ты её не полностью скопировал?",
|
||||||
|
"noLink": "я не могу угадать что ты хочешь скачать. попробуй в следующий раз вставить ссылку.",
|
||||||
|
"noRender": "что-то пошло не так и у меня не получилось срендерить страницу. если это что-то критичное, пожалуйста, <a href=\"https://wukko.me/contacts\">напиши мне об этом</a>. приложи хэш текущего коммита ({s}) с действиями для получения ошибки. можно на русском языке. спасибо :)",
|
||||||
|
"rateLimit": "ты делаешь слишком много запросов. успокойся и попробуй ещё раз через несколько минут.",
|
||||||
|
"noFetch": "мне не удалось получить информацию о твоей ссылке. проверь её и попробуй ещё раз.",
|
||||||
|
"lengthLimit": "твоё видео было длиннее чем {s} минуты. это превышает текущий лимит. скачай что-нибудь покороче, а не войну и мир.",
|
||||||
|
"errorFetch": "что-то пошло не так с получением данных о твоей ссылке. попробуй другой формат и разрешение. если не получится, то попробуй ещё раз чуть позже.",
|
||||||
|
"corruptedStream": "эта загрузка повреждена. попробуй ещё раз. если не получится, то попробуй другой формат и разрешение.",
|
||||||
|
"noInternet": "кажется нет подключения к интернету. а возможно лежу я, а не твой интернет. в любом случае, проверь подключение к интернету и попробуй ещё раз.",
|
||||||
|
"cantConnectToAPI": "не получилось подключится к серверу {s}. {s} либо лежит, либо меня добавили в чёрный список. попробуй ещё раз чуть позже.",
|
||||||
|
"nothingToDownload": "мне нечего скачать. попробуй другую ссылку!",
|
||||||
|
"liveVideo": "я не могу скачать прямой эфир. дождись окончания трансляции и попробуй ещё раз.",
|
||||||
|
"noStreamID": "нет такого streamId.",
|
||||||
|
"noType": "нет такого формата ответа от сервера."
|
||||||
|
}
|
22
src/i18n/ru/settings.json
Normal file
22
src/i18n/ru/settings.json
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
{
|
||||||
|
"appearance": "внешний вид",
|
||||||
|
"alwaysVisibleButton": "оставлять >> на экране",
|
||||||
|
"downloadPopupButton": "спрашивать что делать с загрузками",
|
||||||
|
"format": "формат загрузок",
|
||||||
|
"formatInfo": "выбирай webm если хочешь максимальное качество. webm обычно лучше чем mp4 в плане качества, но устройства на ios не могут их проигрывать без сторонних приложений. все загрузки \"только аудио\" всегда максимального качества.",
|
||||||
|
"theme": "тема",
|
||||||
|
"themeAuto": "авто",
|
||||||
|
"themeLight": "светлая",
|
||||||
|
"themeDark": "тёмная",
|
||||||
|
"misc": "ещё",
|
||||||
|
"general": "загрузки",
|
||||||
|
"quality": "качество",
|
||||||
|
"qmax": "макс",
|
||||||
|
"qhig": "высокое\n",
|
||||||
|
"qmid": "среднее\n",
|
||||||
|
"qlow": "низкое\n",
|
||||||
|
"qlos": "ужасное",
|
||||||
|
"qualityDesc": "если выбранное разрешение недоступно, то выбирается ближайшее.",
|
||||||
|
"extra": "ещё",
|
||||||
|
"audioOnly": "только аудио"
|
||||||
|
}
|
18
src/i18n/ru/strings.json
Normal file
18
src/i18n/ru/strings.json
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
{
|
||||||
|
"input": "вставь ссылку сюда",
|
||||||
|
"aboutSummary": "{appName} — твой друг при скачивании видео с соц.сетей. никакой рекламы или трекеров. просто вставь ссылку и ты прекрасен.",
|
||||||
|
"embed": "сохраняй что хочешь без мороки и вторжения в личное пространство",
|
||||||
|
"supportedServices": "что поддерживается:",
|
||||||
|
"sourceCode": ">> сообщай о проблемах на github",
|
||||||
|
"popupBottom": "сделано с <3 ~ wukko",
|
||||||
|
"noScript": "{appName} использует javascript для обработки ссылок и интерактивного интерфейса. ты должен разрешить использование javascript чтобы пользоваться сайтом. тут нет никаких трекеров или рекламы, обещаю.",
|
||||||
|
"donationsSub": "сейчас намного сложнее платить за хостинг",
|
||||||
|
"donations": "я ненавижу крипто, но у меня нет возможности платить любым другим способом.",
|
||||||
|
"donateDm": ">> если нет подходящей валюты, или же ты из россии, то напиши мне",
|
||||||
|
"clickToCopy": "нажми чтобы скопировать",
|
||||||
|
"iosDownload": "так как у тебя устройство на ios, тебе нужно зажать кнопку \"скачать\" и выбрать что-то похожее на \"сохранить в галерею\" в появившемся окне.",
|
||||||
|
"normalDownload": "кнопка скачивания открывает новое окно с файлом. ты можешь отключить метод сохранения файла в настройках.",
|
||||||
|
"download": "скачать",
|
||||||
|
"copy": "скопировать ссылку",
|
||||||
|
"github": ">> посмотреть предыдущие изменения на github"
|
||||||
|
}
|
9
src/i18n/ru/title.json
Normal file
9
src/i18n/ru/title.json
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
{
|
||||||
|
"about": "что за {appName}?",
|
||||||
|
"settings": "настройки",
|
||||||
|
"error": "о нет",
|
||||||
|
"changelog": "что нового?",
|
||||||
|
"donate": "поддержи {appName}",
|
||||||
|
"download": "скачивание",
|
||||||
|
"pickDownload": "как сохранить?"
|
||||||
|
}
|
|
@ -30,6 +30,6 @@ export async function getJSON(originalURL, ip, lang, format, quality) {
|
||||||
return apiJSON(0, { t: errorUnsupported(lang) } )
|
return apiJSON(0, { t: errorUnsupported(lang) } )
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return apiJSON(0, { t: loc(lang, 'apiError', 'generic') + loc(lang, 'apiError', 'letMeKnow') });
|
return apiJSON(0, { t: loc(lang, 'apiError', 'generic') });
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -34,7 +34,7 @@ export default async function (host, patternMatch, url, ip, lang, format, qualit
|
||||||
lang: lang
|
lang: lang
|
||||||
});
|
});
|
||||||
return (!r.error) ? apiJSON(2, {
|
return (!r.error) ? apiJSON(2, {
|
||||||
type: "render", urls: r.urls,
|
type: "render", urls: r.urls, lang: lang,
|
||||||
service: host, ip: ip,
|
service: host, ip: ip,
|
||||||
filename: r.filename,
|
filename: r.filename,
|
||||||
salt: process.env.streamSalt, time: r.time
|
salt: process.env.streamSalt, time: r.time
|
||||||
|
@ -73,7 +73,7 @@ export default async function (host, patternMatch, url, ip, lang, format, qualit
|
||||||
let r = await reddit({
|
let r = await reddit({
|
||||||
sub: patternMatch["sub"],
|
sub: patternMatch["sub"],
|
||||||
id: patternMatch["id"],
|
id: patternMatch["id"],
|
||||||
title: patternMatch["title"]
|
title: patternMatch["title"], lang: lang,
|
||||||
});
|
});
|
||||||
return (!r.error) ? apiJSON(2, {
|
return (!r.error) ? apiJSON(2, {
|
||||||
type: "render", urls: r.urls,
|
type: "render", urls: r.urls,
|
||||||
|
|
|
@ -17,7 +17,7 @@ let enabledServices = Object.keys(s).filter((p) => {
|
||||||
|
|
||||||
let donate = ``
|
let donate = ``
|
||||||
for (let i in donations) {
|
for (let i in donations) {
|
||||||
donate += `<div class="subtitle">${i} (${loc("en", 'desc', 'clickToCopy').trim()})</div><div id="don-${i}" class="text-to-copy" onClick="copy('don-${i}')">${donations[i]}</div>`
|
donate += `<div class="subtitle">${i} (REPLACEME)</div><div id="don-${i}" class="text-to-copy" onClick="copy('don-${i}')">${donations[i]}</div>`
|
||||||
}
|
}
|
||||||
|
|
||||||
let com = getCommitInfo();
|
let com = getCommitInfo();
|
||||||
|
@ -34,10 +34,10 @@ export default function(obj) {
|
||||||
|
|
||||||
<meta property="og:url" content="${process.env.selfURL}" />
|
<meta property="og:url" content="${process.env.selfURL}" />
|
||||||
<meta property="og:title" content="${appName}" />
|
<meta property="og:title" content="${appName}" />
|
||||||
<meta property="og:description" content="${loc(obj.lang, 'desc', 'embed')}" />
|
<meta property="og:description" content="${loc(obj.lang, 'strings', 'embed')}" />
|
||||||
<meta property="og:image" content="${process.env.selfURL}icons/generic.png" />
|
<meta property="og:image" content="${process.env.selfURL}icons/generic.png" />
|
||||||
<meta name="title" content="${appName}" />
|
<meta name="title" content="${appName}" />
|
||||||
<meta name="description" content="${loc(obj.lang, 'desc', 'embed')}" />
|
<meta name="description" content="${loc(obj.lang, 'strings', 'embed')}" />
|
||||||
<meta name="theme-color" content="#000000" />
|
<meta name="theme-color" content="#000000" />
|
||||||
<meta name="twitter:card" content="summary" />
|
<meta name="twitter:card" content="summary" />
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@ export default function(obj) {
|
||||||
<link rel="stylesheet" href="cobalt.css" />
|
<link rel="stylesheet" href="cobalt.css" />
|
||||||
<link rel="stylesheet" href="fonts/notosansmono/notosansmono.css" />
|
<link rel="stylesheet" href="fonts/notosansmono/notosansmono.css" />
|
||||||
|
|
||||||
<noscript><div style="margin: 2rem;">${loc(obj.lang, 'desc', 'noScript')}</div></noscript>
|
<noscript><div style="margin: 2rem;">${loc(obj.lang, 'strings', 'noScript')}</div></noscript>
|
||||||
</head>
|
</head>
|
||||||
<body id="cobalt-body">
|
<body id="cobalt-body">
|
||||||
<div id="popup-download" class="popup center box" style="visibility: hidden;">
|
<div id="popup-download" class="popup center box" style="visibility: hidden;">
|
||||||
|
@ -62,11 +62,11 @@ export default function(obj) {
|
||||||
<div id="theme-switcher" class="switch-container small-padding">
|
<div id="theme-switcher" class="switch-container small-padding">
|
||||||
<div class="subtitle">${loc(obj.lang, 'title', 'pickDownload')}</div>
|
<div class="subtitle">${loc(obj.lang, 'title', 'pickDownload')}</div>
|
||||||
<div class="switches">
|
<div class="switches">
|
||||||
<a id="pd-download" class="switch full space-right" target="_blank"">${loc(obj.lang, 'desc', 'download')}</a>
|
<a id="pd-download" class="switch full space-right" target="_blank"">${loc(obj.lang, 'strings', 'download')}</a>
|
||||||
<div id="pd-copy" class="switch full">${loc(obj.lang, 'desc', 'copy')}</div>
|
<div id="pd-copy" class="switch full">${loc(obj.lang, 'strings', 'copy')}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="desc" class="explanation about-padding">${isIOS ? loc(obj.lang, 'desc', 'iosDownload') : loc(obj.lang, 'desc', 'normalDownload')}</div>
|
<div id="desc" class="explanation about-padding">${isIOS ? loc(obj.lang, 'strings', 'iosDownload') : loc(obj.lang, 'strings', 'normalDownload')}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="popup-about" class="popup center box" style="visibility: hidden;">
|
<div id="popup-about" class="popup center box" style="visibility: hidden;">
|
||||||
|
@ -75,12 +75,12 @@ export default function(obj) {
|
||||||
<div id="title" class="popup-title">${loc(obj.lang, 'title', 'about')}</div>
|
<div id="title" class="popup-title">${loc(obj.lang, 'title', 'about')}</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="content" class="popup-content with-footer">
|
<div id="content" class="popup-content with-footer">
|
||||||
<div id="desc" class="popup-desc about-padding">${loc(obj.lang, 'desc', 'aboutSummary')}</div>
|
<div id="desc" class="popup-desc about-padding">${loc(obj.lang, 'strings', 'aboutSummary')}</div>
|
||||||
<div id="desc" class="popup-desc about-padding">${loc(obj.lang, 'desc', 'supportedServices')} ${enabledServices}.</div>
|
<div id="desc" class="popup-desc about-padding">${loc(obj.lang, 'strings', 'supportedServices')} ${enabledServices}.</div>
|
||||||
<div id="desc" class="popup-desc"><a class="text-backdrop" href="${repo}">${loc(obj.lang, 'desc', 'sourceCode')}</a></div>
|
<div id="desc" class="popup-desc"><a class="text-backdrop" href="${repo}">${loc(obj.lang, 'strings', 'sourceCode')}</a></div>
|
||||||
</div>
|
</div>
|
||||||
<div id="popup-footer" class="popup-footer">
|
<div id="popup-footer" class="popup-footer">
|
||||||
<a id="popup-bottom" class="popup-footer-content" href="${authorInfo.link}">${loc(obj.lang, 'desc', 'popupBottom')}</a>
|
<a id="popup-bottom" class="popup-footer-content" href="${authorInfo.link}">${loc(obj.lang, 'strings', 'popupBottom')}</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="popup-changelog" class="popup center box" style="visibility: hidden;">
|
<div id="popup-changelog" class="popup center box" style="visibility: hidden;">
|
||||||
|
@ -91,19 +91,19 @@ export default function(obj) {
|
||||||
</div>
|
</div>
|
||||||
<div id="content" class="popup-content">
|
<div id="content" class="popup-content">
|
||||||
<div id="desc" class="popup-desc about-padding">${com[1]}</div>
|
<div id="desc" class="popup-desc about-padding">${com[1]}</div>
|
||||||
<div id="desc" class="popup-desc"><a class="text-backdrop" href="${repo}/commits">${loc(obj.lang, 'desc', 'github')}</a></div>
|
<div id="desc" class="popup-desc"><a class="text-backdrop" href="${repo}/commits">${loc(obj.lang, 'strings', 'github')}</a></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="popup-donate" class="popup scrollable center box" style="visibility: hidden;">
|
<div id="popup-donate" class="popup scrollable center box" style="visibility: hidden;">
|
||||||
<div id="popup-header" class="popup-header">
|
<div id="popup-header" class="popup-header">
|
||||||
<button id="close" class="button mono" onclick="popup('donate', 0)" aria-label="${loc(obj.lang, 'accessibility', 'close')}">x</button>
|
<button id="close" class="button mono" onclick="popup('donate', 0)" aria-label="${loc(obj.lang, 'accessibility', 'close')}">x</button>
|
||||||
<div id="title" class="popup-title">${loc(obj.lang, 'title', 'donate')}</div>
|
<div id="title" class="popup-title">${loc(obj.lang, 'title', 'donate')}</div>
|
||||||
<div id="desc" class="little-subtitle">${loc(obj.lang, 'desc', 'donationsSub')}</div>
|
<div id="desc" class="little-subtitle">${loc(obj.lang, 'strings', 'donationsSub')}</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="content" class="popup-content">
|
<div id="content" class="popup-content">
|
||||||
${donate}
|
${donate.replace(/REPLACEME/g, loc(obj.lang, 'strings', 'clickToCopy').trim())}
|
||||||
<div id="desc" class="explanation about-padding">${loc(obj.lang, 'desc', 'donations')}</div>
|
<div id="desc" class="explanation about-padding">${loc(obj.lang, 'strings', 'donations')}</div>
|
||||||
<div id="desc" class="popup-desc"><a class="text-backdrop" href="${authorInfo.contact}">${loc(obj.lang, 'desc', 'donateDm')}</a></div>
|
<div id="desc" class="popup-desc"><a class="text-backdrop" href="${authorInfo.contact}">${loc(obj.lang, 'strings', 'donateDm')}</a></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="popup-settings" class="popup scrollable center box" style="visibility: hidden;">
|
<div id="popup-settings" class="popup scrollable center box" style="visibility: hidden;">
|
||||||
|
@ -159,7 +159,7 @@ export default function(obj) {
|
||||||
<div class="switches">
|
<div class="switches">
|
||||||
<div id="youtubeFormat-mp4" class="switch full" onclick="changeSwitcher('youtubeFormat', 'mp4', 1)">mp4</div>
|
<div id="youtubeFormat-mp4" class="switch full" onclick="changeSwitcher('youtubeFormat', 'mp4', 1)">mp4</div>
|
||||||
<div id="youtubeFormat-webm" class="switch" onclick="changeSwitcher('youtubeFormat', 'webm', 1)">webm</div>
|
<div id="youtubeFormat-webm" class="switch" onclick="changeSwitcher('youtubeFormat', 'webm', 1)">webm</div>
|
||||||
<div id="youtubeFormat-audio" class="switch full" onclick="changeSwitcher('youtubeFormat', 'audio', 1)">audio only</div>
|
<div id="youtubeFormat-audio" class="switch full" onclick="changeSwitcher('youtubeFormat', 'audio', 1)">${loc(obj.lang, 'settings', 'audioOnly')}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="explanation">${loc(obj.lang, 'settings', 'formatInfo')}</div>
|
<div class="explanation">${loc(obj.lang, 'settings', 'formatInfo')}</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -180,7 +180,7 @@ export default function(obj) {
|
||||||
<div id="cobalt-main-box" class="center box" style="visibility: hidden;">
|
<div id="cobalt-main-box" class="center box" style="visibility: hidden;">
|
||||||
<div id="logo-area">${appName}</div>
|
<div id="logo-area">${appName}</div>
|
||||||
<div id="download-area" class="mobile-center">
|
<div id="download-area" class="mobile-center">
|
||||||
<input id="url-input-area" class="mono" type="text" autocorrect="off" maxlength="110" autocapitalize="off" placeholder="${loc(obj.lang, 'desc', 'input')}" aria-label="${loc(obj.lang, 'accessibility', 'input')}" oninput="button()">
|
<input id="url-input-area" class="mono" type="text" autocorrect="off" maxlength="110" autocapitalize="off" placeholder="${loc(obj.lang, 'strings', 'input')}" aria-label="${loc(obj.lang, 'accessibility', 'input')}" oninput="button()">
|
||||||
<input id="download-button" class="mono dontRead" onclick="download(document.getElementById('url-input-area').value)" type="submit" value="" disabled=true aria-label="${loc(obj.lang, 'accessibility', 'download')}">
|
<input id="download-button" class="mono dontRead" onclick="download(document.getElementById('url-input-area').value)" type="submit" value="" disabled=true aria-label="${loc(obj.lang, 'accessibility', 'download')}">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -197,6 +197,6 @@ export default function(obj) {
|
||||||
<script type="text/javascript" src="cobalt.js"></script>
|
<script type="text/javascript" src="cobalt.js"></script>
|
||||||
</html>`;
|
</html>`;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
return `${loc('en', 'apiError', 'fatal', obj.hash)}`;
|
return `${loc('en', 'apiError', 'noRender', obj.hash)}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -8,7 +8,7 @@ export default async function(obj) {
|
||||||
headers: { "user-agent": genericUserAgent }
|
headers: { "user-agent": genericUserAgent }
|
||||||
});
|
});
|
||||||
html.on('error', (err) => {
|
html.on('error', (err) => {
|
||||||
return { error: loc('en', 'apiError', 'youtubeFetch') };
|
return { error: loc(obj.lang, 'apiError', 'cantConnectToAPI', 'bilibili') };
|
||||||
});
|
});
|
||||||
html = html.body;
|
html = html.body;
|
||||||
if (html.includes('<script>window.__playinfo__=') && html.includes('"video_codecid"')) {
|
if (html.includes('<script>window.__playinfo__=') && html.includes('"video_codecid"')) {
|
||||||
|
@ -22,13 +22,13 @@ export default async function(obj) {
|
||||||
}).sort((a, b) => Number(b.bandwidth) - Number(a.bandwidth));
|
}).sort((a, b) => Number(b.bandwidth) - Number(a.bandwidth));
|
||||||
return { urls: [video[0]["baseUrl"], audio[0]["baseUrl"]], time: streamData.data.timelength, filename: `bilibili_${obj.id}_${video[0]["width"]}x${video[0]["height"]}.mp4` };
|
return { urls: [video[0]["baseUrl"], audio[0]["baseUrl"]], time: streamData.data.timelength, filename: `bilibili_${obj.id}_${video[0]["width"]}x${video[0]["height"]}.mp4` };
|
||||||
} else {
|
} else {
|
||||||
return { error: loc('en', 'apiError', 'youtubeLimit', maxVideoDuration / 60000) };
|
return { error: loc(obj.lang, 'apiError', 'lengthLimit', maxVideoDuration / 60000) };
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return { error: loc('en', 'apiError', 'youtubeFetch') };
|
return { error: loc(obj.lang, 'apiError', 'nothingToDownload') };
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return { error: loc('en', 'apiError', 'youtubeFetch') };
|
return { error: loc(obj.lang, 'apiError', 'noFetch') };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,9 +9,9 @@ export default async function(obj) {
|
||||||
if ("reddit_video" in data["secure_media"] && data["secure_media"]["reddit_video"]["duration"] * 1000 < maxVideoDuration) {
|
if ("reddit_video" in data["secure_media"] && data["secure_media"]["reddit_video"]["duration"] * 1000 < maxVideoDuration) {
|
||||||
return { urls: [data["secure_media"]["reddit_video"]["fallback_url"].split('?')[0], `${data["secure_media"]["reddit_video"]["fallback_url"].split('_')[0]}_audio.mp4`], filename: `reddit_${data["secure_media"]["reddit_video"]["fallback_url"].split('/')[3]}.mp4` };
|
return { urls: [data["secure_media"]["reddit_video"]["fallback_url"].split('?')[0], `${data["secure_media"]["reddit_video"]["fallback_url"].split('_')[0]}_audio.mp4`], filename: `reddit_${data["secure_media"]["reddit_video"]["fallback_url"].split('/')[3]}.mp4` };
|
||||||
} else {
|
} else {
|
||||||
return { error: loc('en', 'apiError', 'nothingToDownload') };
|
return { error: loc(obj.lang, 'apiError', 'nothingToDownload') };
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
return { error: loc("en", "apiError", "nothingToDownload") };
|
return { error: loc(obj.lang, 'apiError', 'noFetch') };
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -52,6 +52,6 @@ export default async function (obj) {
|
||||||
}
|
}
|
||||||
} else return parsbod;
|
} else return parsbod;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
return { error: loc("en", "apiError", "youtubeBroke") };
|
return { error: loc("en", "apiError", "errorFetch") };
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -30,18 +30,18 @@ export default async function(obj) {
|
||||||
if (selectedQuality in js["player"]["params"][0]) {
|
if (selectedQuality in js["player"]["params"][0]) {
|
||||||
return { url: js["player"]["params"][0][selectedQuality].replace(`type=${maxQuality}`, `type=${services.vk.quality_match[userQuality]}`), filename: `vk_${js["player"]["params"][0][selectedQuality].split("id=")[1]}_${attr['width']}x${attr['height']}.mp4` };
|
return { url: js["player"]["params"][0][selectedQuality].replace(`type=${maxQuality}`, `type=${services.vk.quality_match[userQuality]}`), filename: `vk_${js["player"]["params"][0][selectedQuality].split("id=")[1]}_${attr['width']}x${attr['height']}.mp4` };
|
||||||
} else {
|
} else {
|
||||||
return { error: loc('en', 'apiError', 'nothingToDownload') };
|
return { error: loc(obj.lang, 'apiError', 'nothingToDownload') };
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return { error: loc('en', 'apiError', 'youtubeLimit', maxVideoDuration / 60000) };
|
return { error: loc(obj.lang, 'apiError', 'lengthLimit', maxVideoDuration / 60000) };
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return { error: loc('en', 'apiError', 'liveVideo') };
|
return { error: loc(obj.lang, 'apiError', 'liveVideo') };
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return { error: loc('en', 'apiError', 'nothingToDownload') };
|
return { error: loc(obj.lang, 'apiError', 'nothingToDownload') };
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
return { error: loc('en', 'apiError', 'youtubeFetch') };
|
return { error: loc(obj.lang, 'apiError', 'errorFetch') };
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -48,7 +48,7 @@ export default async function (obj) {
|
||||||
filename: `youtube_${obj.id}_${videoMatch[0]["width"]}x${videoMatch[0]["height"]}.${obj.format}` };
|
filename: `youtube_${obj.id}_${videoMatch[0]["width"]}x${videoMatch[0]["height"]}.${obj.format}` };
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return { error: loc('en', 'apiError', 'youtubeBroke') };
|
return { error: loc('en', 'apiError', 'errorFetch') };
|
||||||
}
|
}
|
||||||
} else if (!obj.isAudioOnly) {
|
} else if (!obj.isAudioOnly) {
|
||||||
return { type: "render", urls: [video[0]["url"], audio[0]["url"]], time: video[0]["approxDurationMs"],
|
return { type: "render", urls: [video[0]["url"], audio[0]["url"]], time: video[0]["approxDurationMs"],
|
||||||
|
@ -56,10 +56,10 @@ export default async function (obj) {
|
||||||
} else if (audio.length > 0) {
|
} else if (audio.length > 0) {
|
||||||
return { type: "render", isAudioOnly: true, urls: [audio[0]["url"]], filename: `youtube_${obj.id}_${audio[0]["audioBitrate"]}kbps.opus` };
|
return { type: "render", isAudioOnly: true, urls: [audio[0]["url"]], filename: `youtube_${obj.id}_${audio[0]["audioBitrate"]}kbps.opus` };
|
||||||
} else {
|
} else {
|
||||||
return { error: loc('en', 'apiError', 'youtubeBroke') };
|
return { error: loc('en', 'apiError', 'errorFetch') };
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return { error: loc('en', 'apiError', 'youtubeLimit', maxVideoDuration / 60000) };
|
return { error: loc('en', 'apiError', 'lengthLimit', maxVideoDuration / 60000) };
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return { error: loc('en', 'apiError', 'liveVideo') };
|
return { error: loc('en', 'apiError', 'liveVideo') };
|
||||||
|
|
|
@ -68,7 +68,7 @@ export async function streamLiveRender(streamInfo, res) {
|
||||||
ffmpegProcess.kill();
|
ffmpegProcess.kill();
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
res.status(400).json({ status: "error", text: loc('en', 'apiError', 'corruptedVideo') });
|
res.status(400).json({ status: "error", text: loc('en', 'apiError', 'corruptedStream') });
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
internalError(res);
|
internalError(res);
|
||||||
|
|
|
@ -4,8 +4,8 @@ export function internalError(res) {
|
||||||
res.status(501).json({ status: "error", text: "Internal Server Error" });
|
res.status(501).json({ status: "error", text: "Internal Server Error" });
|
||||||
}
|
}
|
||||||
export function errorUnsupported(lang) {
|
export function errorUnsupported(lang) {
|
||||||
return loc(lang, 'apiError', 'notSupported') + loc(lang, 'apiError', 'letMeKnow');
|
return loc(lang, 'apiError', 'notSupported');
|
||||||
}
|
}
|
||||||
export function genericError(lang, host) {
|
export function genericError(lang, host) {
|
||||||
return loc(lang, 'apiError', 'brokenLink', host) + loc(lang, 'apiError', 'letMeKnow');
|
return loc(lang, 'apiError', 'brokenLink', host);
|
||||||
}
|
}
|
Loading…
Reference in a new issue