diff --git a/package.json b/package.json index 554a24e..f077255 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "cobalt", "description": "save what you love", - "version": "4.7.4", + "version": "4.8", "author": "wukko", "exports": "./src/cobalt.js", "type": "module", diff --git a/src/config.json b/src/config.json index 2d800fe..4ce8c81 100644 --- a/src/config.json +++ b/src/config.json @@ -6,7 +6,17 @@ "authorInfo": { "name": "wukko", "link": "https://wukko.me/", - "contact": "https://wukko.me/contacts" + "contact": "https://wukko.me/contacts", + "support": { + "twitter": { + "url": "https://twitter.com/justusecobalt", + "handle": "@justusecobalt" + }, + "mastodon": { + "url": "https://wetdry.world/@cobalt", + "handle": "@cobalt@wetdry.world" + } + } }, "internetExplorerRedirect": { "newNT": ["6.1", "6.2", "6.3", "10.0"], diff --git a/src/front/cobalt.css b/src/front/cobalt.css index fabb6ca..eb10b61 100644 --- a/src/front/cobalt.css +++ b/src/front/cobalt.css @@ -5,6 +5,8 @@ --border-10: 0.1rem solid var(--accent); --font-mono: 'Noto Sans Mono', 'Consolas', 'SF Mono', monospace; --red: rgb(255, 0, 61); + --padding-1: 0.75rem; + --line-height: 1.65rem; } @media (prefers-color-scheme: dark) { :root { @@ -75,10 +77,11 @@ a { [type="checkbox"] { -webkit-appearance: none; appearance: none; - margin-right: 1rem; + margin-right: var(--padding-1); z-index: 0; border: 0; height: 15px; + width: 15px; } [type="checkbox"]::before { content: ""; @@ -96,6 +99,7 @@ a { } .checkbox span { margin-top: 0.21rem; + margin-left: 0.4rem; } button { background: none; @@ -112,17 +116,11 @@ input[type="text"], button:hover, .switch:hover, .checkbox:hover, -.text-to-copy:hover { +.text-to-copy:hover, +.collapse-header:hover { background: var(--accent-hover); cursor: pointer; } -.switch.text-backdrop:hover, -.switch.text-backdrop:active, -.text-to-copy.text-backdrop:hover, -.text-to-copy.text-backdrop:active { - background: var(--accent); - color: var(--background); -} button:active, .switch:active, .checkbox:active, @@ -131,6 +129,17 @@ button:active, cursor: pointer; transform: scale(0.95) } +.collapse-header:active { + background: var(--accent-press); + cursor: pointer; +} +.switch.text-backdrop:hover, +.switch.text-backdrop:active, +.text-to-copy.text-backdrop:hover, +.text-to-copy.text-backdrop:active { + background: var(--accent); + color: var(--background); +} .picker-image:active { cursor: pointer; transform: scale(0.95) @@ -242,7 +251,7 @@ input[type="checkbox"] { #cobalt-main-box #bottom, #footer-buttons, #footer-buttons, .footer-pair { - gap: 0.8rem; + gap: 0.6rem; } #footer-buttons, .footer-pair { display: flex; @@ -265,7 +274,17 @@ input[type="checkbox"] { .text-backdrop { background: var(--accent); color: var(--background); - padding: 0 0.1rem; +} +.italic { + font-style: italic; +} +.social-link { + display: flex; + flex-direction: row; + justify-content: flex-start; + gap: 0.3rem; + margin-top: 0.5rem; + user-select: none; } ::-moz-selection { background-color: var(--accent); @@ -312,7 +331,7 @@ input[type="checkbox"] { width: 100%; background-color: var(--accent-button-bg); max-height: 300px; - margin-bottom: 2rem; + margin-bottom: 1.65rem; float: left; } .changelog-img { @@ -332,7 +351,7 @@ input[type="checkbox"] { } #popup-subtitle { font-size: 1.1rem; - padding-bottom: 1rem; + padding-bottom: var(--padding-1); } #popup-desc, #desc-error, @@ -340,7 +359,7 @@ input[type="checkbox"] { width: 100%; text-align: left; float: left; - line-height: 1.7rem; + line-height: var(--line-height); user-select: text; } #popup-title { @@ -359,7 +378,7 @@ input[type="checkbox"] { } .popup-footer-content { font-size: 0.8rem; - line-height: 1.7rem; + line-height: var(--line-height); color: var(--accent-unhover-2); border-top: 0.05rem solid var(--accent-unhover-2); padding-top: 0.4rem; @@ -386,14 +405,8 @@ input[type="checkbox"] { #popup-content.with-footer { margin-bottom: 3rem; } -#popup-close { - cursor: pointer; - float: right; - right: 0; - position: absolute; -} .settings-category { - padding-bottom: 1.2rem; + padding-bottom: 1rem; } .separator { float: left; @@ -408,13 +421,17 @@ input[type="checkbox"] { } .category-title { text-align: left; - line-height: 1.7rem; + line-height: var(--line-height); } .bottom-margin { - margin-bottom: 1rem!important; + margin-bottom: var(--padding-1)!important; } .top-margin { - margin-top: 1rem!important; + margin-top: var(--padding-1)!important; +} +.top-margin-only { + margin-top: var(--padding-1)!important; + margin-bottom: 0!important; } .no-margin { margin: 0!important; @@ -424,10 +441,10 @@ input[type="checkbox"] { align-items: center; flex-direction: row; flex-wrap: nowrap; - align-content: center; padding: 0.55rem 1rem 0.8rem 0.7rem; width: auto; - margin: 0 0.5rem 0.5rem 0; + margin-right: var(--padding-1); + margin-bottom: var(--padding-1); background: var(--accent-button-bg); } .checkbox-label { @@ -439,7 +456,7 @@ input[type="checkbox"] { .subtitle { width: 100%; text-align: left; - line-height: 1.7rem; + line-height: var(--line-height); padding-bottom: 0.4rem; color: var(--accent); } @@ -469,7 +486,7 @@ input[type="checkbox"] { cursor: pointer; } .switch.space-right { - margin-right: 1rem + margin-right: var(--padding-1); } .switch[data-enabled="true"] { color: var(--background); @@ -494,17 +511,23 @@ input[type="checkbox"] { .text-to-copy { user-select: text; border: var(--border-15); - padding: 1rem; + padding: var(--padding-1); overflow: auto; } -#close-bottom { +#close-button { max-width: 2.8rem; - margin-left: 1rem; + margin-left: var(--padding-1); background: var(--background); border: var(--border-15); color: var(--accent); padding: 0.3rem 0.75rem 0.5rem; } +#close-button.up { + float: right; + position: absolute; + right: 0; + height: 2.8rem; +} .popup-tab-content { display: none; } @@ -519,18 +542,7 @@ input[type="checkbox"] { } .emoji { margin-right: 0.4rem; -} -.tooltip { - position: absolute; - margin-top: -6rem; - margin-left: -0.5rem; - line-height: 1.2; - text-align: left; - pointer-events: none; - color: var(--accent-unhover-2)!important; -} -.button:active .tooltip { - display: none; + user-select: none; } .picker-image { object-fit: cover; @@ -540,13 +552,13 @@ input[type="checkbox"] { .picker-image-container { width: 8rem; height: 8rem; - margin-bottom: 1rem; + margin-bottom: var(--padding-1); background-color: var(--accent-button-bg); } .picker-various-container { height: 20rem; width: 25rem; - margin-bottom: 1rem; + margin-bottom: var(--padding-1); background-color: var(--accent-button-bg); position: relative; } @@ -579,7 +591,41 @@ input[type="checkbox"] { } #popup-picker .explanation { margin-top: 0!important; - margin-bottom: 1rem; + margin-bottom: var(--padding-1); +} +.collapse-list { + background: var(--accent-press); + user-select: none; +} +.collapse-header { + padding: var(--padding-1); + font-size: 1rem; + display: flex; + flex-direction: row; + align-items: center; + cursor: pointer; + background: var(--accent-button-bg); +} +.collapse-indicator { + transform: rotate(180deg); +} +.expanded .collapse-indicator { + transform: none; +} +.collapse-title { + width: 100%; + display: flex; + flex-direction: row; + align-items: center; + gap: 0.8rem; +} +.collapse-body { + display: none; + padding: var(--padding-1); + user-select: text; +} +.expanded .collapse-body { + display: block } /* adapt the page according to screen size */ @media screen and (min-width: 2300px) { @@ -655,9 +701,9 @@ input[type="checkbox"] { } } /* mobile page */ -@media screen and (max-width: 949px) { +@media screen and (max-width: 720px) { #cobalt-main-box, #footer { - width: 85%; + width: 90%; } } @media screen and (max-width: 475px) { @@ -699,6 +745,39 @@ input[type="checkbox"] { margin-right: 0; } } +@media screen and (max-width: 720px) { + #cobalt-main-box #bottom { + flex-direction: column; + } + #cobalt-main-box #bottom button { + width: 100%!important; + } + #footer { + bottom: 4%; + transform: translate(-50%, 0%); + } + #footer-buttons { + flex-direction: column; + align-items: stretch; + } + .footer-pair .footer-button { + width: 100%!important; + } + #logo-area { + padding-right: 0; + padding-top: 0; + position: fixed; + line-height: 0; + margin-top: -2rem; + width: 100%; + text-align: center; + } + #cobalt-main-box { + display: flex; + border: none; + padding: 0; + } +} @media screen and (max-width: 949px) { #picker-holder::-webkit-scrollbar { display: none; @@ -715,23 +794,6 @@ input[type="checkbox"] { height: 20rem; max-width: 100%; } - #cobalt-main-box #bottom { - flex-direction: column; - } - #cobalt-main-box #bottom button { - width: 100%!important; - } - #footer { - bottom: 1.7rem; - transform: translate(-50%, 0%); - } - #footer-buttons { - flex-direction: column; - align-items: stretch; - } - .footer-pair .footer-button { - width: 100%!important; - } #popup-header { padding-top: 1.2rem; } @@ -744,24 +806,10 @@ input[type="checkbox"] { line-height: 7rem; } #close-error { - bottom: 5%; + bottom: 3rem; position: absolute; width: var(--without-padding); } - #logo-area { - padding-right: 0; - padding-top: 0; - position: fixed; - line-height: 0; - margin-top: -2rem; - width: 100%; - text-align: center; - } - #cobalt-main-box { - display: flex; - border: none; - padding: 0; - } .popup, .popup.scrollable, .popup.small { border: none; width: 90%; diff --git a/src/front/cobalt.js b/src/front/cobalt.js index 7086ec8..0628d35 100644 --- a/src/front/cobalt.js +++ b/src/front/cobalt.js @@ -1,7 +1,7 @@ let ua = navigator.userAgent.toLowerCase(); let isIOS = ua.match("iphone os"); let isMobile = ua.match("android") || ua.match("iphone os"); -let version = 21; +let version = 22; let regex = new RegExp(/https:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()!@:%_\+.~#?&\/\/=]*)/); let notification = `
` @@ -85,8 +85,8 @@ function clearInput() { function copy(id, data) { let e = document.getElementById(id); e.classList.add("text-backdrop"); - data ? navigator.clipboard.writeText(data) : navigator.clipboard.writeText(e.innerText); setTimeout(() => { e.classList.remove("text-backdrop") }, 600); + data ? navigator.clipboard.writeText(data) : navigator.clipboard.writeText(e.innerText); } function detectColorScheme() { let theme = "auto"; @@ -112,6 +112,11 @@ function changeTab(evnt, tabId, tabClass) { if (tabId === "tab-about-changelog" && sGet("changelogStatus") !== `${version}`) notificationCheck("changelog"); if (tabId === "tab-about-about" && !sGet("seenAbout")) notificationCheck("about"); } +function expandCollapsible(evnt) { + let classlist = evnt.currentTarget.parentNode.classList; + let c = "expanded"; + !classlist.contains(c) ? classlist.add(c) : classlist.remove(c); +} function notificationCheck(type) { let changed = true; switch (type) { @@ -123,7 +128,6 @@ function notificationCheck(type) { break; default: changed = false; - break; } if (changed && sGet("changelogStatus") === `${version}` || type === "disable") { setTimeout(() => { diff --git a/src/front/emoji/bird.svg b/src/front/emoji/bird.svg new file mode 100644 index 0000000..55cf020 --- /dev/null +++ b/src/front/emoji/bird.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/front/emoji/crystal_ball.svg b/src/front/emoji/crystal_ball.svg new file mode 100644 index 0000000..d2a7f67 --- /dev/null +++ b/src/front/emoji/crystal_ball.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/front/emoji/elephant.svg b/src/front/emoji/elephant.svg new file mode 100644 index 0000000..3f96a89 --- /dev/null +++ b/src/front/emoji/elephant.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/front/emoji/octopus.svg b/src/front/emoji/octopus.svg new file mode 100644 index 0000000..b8c6e90 --- /dev/null +++ b/src/front/emoji/octopus.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/front/emoji/red_question_mark.svg b/src/front/emoji/question_mark.svg similarity index 94% rename from src/front/emoji/red_question_mark.svg rename to src/front/emoji/question_mark.svg index 0227702..3c7e887 100644 --- a/src/front/emoji/red_question_mark.svg +++ b/src/front/emoji/question_mark.svg @@ -1,4 +1,4 @@ - - + + diff --git a/src/front/updateBanners/catmakeup.webp b/src/front/updateBanners/catmakeup.webp new file mode 100644 index 0000000..baaf8e0 Binary files /dev/null and b/src/front/updateBanners/catmakeup.webp differ diff --git a/src/localization/languages/en.json b/src/localization/languages/en.json index 57a8a2d..3e70c30 100644 --- a/src/localization/languages/en.json +++ b/src/localization/languages/en.json @@ -1,12 +1,11 @@ { "name": "english", "substrings": { - "ContactLink": "file an issue on github" + "ContactLink": "file an issue on github" }, "strings": { "LinkInput": "paste the link here", "AboutSummary": "{appName} is your go-to place for social media downloads. zero ads, trackers, or any other creepy bullshit. simply paste a share link and you're ready to rock!", - "AboutSupportedServices": "currently supported services:", "EmbedBriefDescription": "save content from social media without annoyances", "MadeWithLove": "made with <3 by wukko", "AccessibilityInputArea": "link input area", @@ -53,7 +52,6 @@ "AccessibilityEnableDownloadPopup": "ask what to do with downloads", "SettingsFormatDescription": "select webm if you want max quality available. webm videos are usually higher bitrate, but ios devices can't play them natively.", "SettingsQualityDescription": "if selected quality isn't available, closest one gets picked instead.\nif you want to post a youtube video on social media, select a combination of mp4 and 720p.", - "LinkGitHubIssues": ">> report issues and check out the source code on github", "LinkGitHubChanges": ">> see previous commits and contribute on github", "NoScriptMessage": "{appName} uses javascript for api requests and interactive interface. you have to allow javascript to use this site. i don't have any ads or trackers, pinky promise.", "DownloadPopupDescriptionIOS": "press and hold the download button, hide the video preview, and then select \"download linked file\" to save.", @@ -88,7 +86,6 @@ "ErrorNoUrlReturned": "server didn't return a download link. this should never happen. reload the page and try again, but if it doesn't help, {ContactLink}.", "ErrorUnknownStatus": "i received a response i can't process. most likely something with status is wrong. this should never happen. reload the page and try again, but if it doesn't help, {ContactLink}.", "PasteFromClipboard": "paste from clipboard", - "FollowTwitter": "follow {appName}'s twitter account for polls, updates, and more: @justusecobalt", "ChangelogOlder": "previous versions", "ChangelogPressToExpand": "press to expand", "Miscellaneous": "miscellaneous", @@ -104,12 +101,20 @@ "ChangelogPressToHide": "press to collapse", "Donate": "donate", "DonateSub": "help me keep it up", - "DonateExplanation": "{appName} does not (and will never) serve ads or sell your data, therefore it's completely free to use. but hey! turns out keeping up a web service used by hundreds of thousands of people is somewhat costly.\n\nif you ever found {appName} useful and want to keep it online, or simply want to thank the developer, consider chipping in! each and every cent helps and is VERY appreciated.", + "DonateExplanation": "{appName} does not (and will never) serve ads or sell your data, therefore it's completely free to use. but turns out keeping up a web service used by thousands of people is somewhat costly.\n\nif you ever found {appName} useful and want to keep it online, or simply want to thank the developer, consider chipping in! each and every cent helps and is VERY appreciated.", "DonateVia": "donate via", - "DonateHireMe": "or, as an alternative, you can hire me.", + "DonateHireMe": "or, as an alternative, you can hire me.", "SettingsVideoMute": "mute audio", "SettingsVideoMuteExplanation": "disables audio in downloaded video when possible. ignored when audio mode is on or service only supports audio.", "SettingsVideoGeneral": "general", - "ErrorSoundCloudNoClientId": "couldn't find client_id that is required to fetch audio data from soundcloud. try again, and if issue persists, {ContactLink}." + "ErrorSoundCloudNoClientId": "couldn't find client_id that is required to fetch audio data from soundcloud. try again, and if issue persists, {ContactLink}.", + "CollapseServices": "supported services", + "CollapseSupport": "support & source code", + "CollapsePrivacy": "privacy policy", + "ServicesNote": "this list is not final and keeps expanding over time, make sure to check it once in a while!", + "FollowSupport": "follow {appName} on mastodon or twitter for support, polls, news, and more:", + "SupportNote": "please note that questions and issues may take a while to respond to, there's only one person managing everything.", + "SourceCode": "report issues, explore source code, star or fork the repo:", + "PrivacyPolicy": "{appName}'s privacy policy is simple: no data about you is collected or stored. zero, zilch, nada, nothing.\nwhat you download is your business, not mine.\n\nsome non-backtraceable data does get temporarily stored when requested download requires live render. it's necessary for that feature to function.\n\nin that case, salted sha256 hash of your ip address and information about requested stream are temporarily stored in server's RAM for 2 minutes. after 2 minutes all previously stored information is permanently removed. hash of your ip address is used for limiting stream access only to you.\nno one (even me) has access to this data, because official cobalt codebase doesn't provide a way to read it outside of processing functions in the first place.\n\nyou can check {appName}'s github repo for yourself and see that indeed nothing is stored permanently." } } diff --git a/src/localization/languages/ru.json b/src/localization/languages/ru.json index b6816d1..e09b016 100644 --- a/src/localization/languages/ru.json +++ b/src/localization/languages/ru.json @@ -1,12 +1,11 @@ { "name": "русский", "substrings": { - "ContactLink": "напиши об этом на github" + "ContactLink": "напиши об этом на github" }, "strings": { "LinkInput": "вставь ссылку сюда", "AboutSummary": "{appName} — твой друг при скачивании контента из соц. сетей. никакой рекламы или трекеров. вставляешь ссылку и получаешь файл. ничего лишнего.", - "AboutSupportedServices": "что поддерживается:", "EmbedBriefDescription": "сохраняй что хочешь, без мороки и вторжения в личное пространство", "MadeWithLove": "сделано с <3 wukko", "AccessibilityInputArea": "зона вставки ссылки", @@ -53,7 +52,6 @@ "AccessibilityEnableDownloadPopup": "спрашивать, что делать с загрузками", "SettingsFormatDescription": "выбирай webm, если хочешь максимальное качество. у webm видео битрейт обычно выше, но устройства на ios не могут проигрывать их без сторонних приложений.", "SettingsQualityDescription": "если выбранное качество недоступно, то выбирается ближайшее к нему.\nесли ты хочешь опубликовать видео с youtube где-то в соц. сетях, то выбирай комбинацию из mp4 и 720p.", - "LinkGitHubIssues": ">> сообщай о проблемах и смотри исходный код на github", "LinkGitHubChanges": ">> смотри предыдущие изменения на github", "NoScriptMessage": "{appName} использует javascript для обработки ссылок и интерактивного интерфейса. ты должен разрешить использование javascript, чтобы пользоваться сайтом. тут нет никаких трекеров или рекламы, обещаю.", "DownloadPopupDescriptionIOS": "зажми кнопку \"скачать\", затем скрой превью видео и выбери \"загрузить файл по ссылке\" в появившемся окне.", @@ -88,7 +86,6 @@ "ErrorNoUrlReturned": "я не получил ссылку для скачивания от сервера. такого происходить не должно. перезагрузи страницу, а если не поможет, то {ContactLink}.", "ErrorUnknownStatus": "сервер ответил мне чем-то непонятным. такого происходить не должно. перезагрузи страницу, а если не поможет, то {ContactLink}.", "PasteFromClipboard": "вставить из буфера обмена", - "FollowTwitter": "а ещё, в твиттере {appName} есть опросы, новости, и многое другое: @justusecobalt", "ChangelogOlder": "предыдущие версии (на английском)", "ChangelogPressToExpand": "нажми, чтобы раскрыть", "Miscellaneous": "разное", @@ -104,12 +101,20 @@ "ChangelogPressToHide": "нажми, чтобы скрыть", "Donate": "донаты", "DonateSub": "ты можешь помочь!", - "DonateExplanation": "{appName} не пихает рекламу тебе в лицо и не продаёт твои личные данные, а значит работает совершенно бесплатно. но оказывается, что хостинг сервиса, которым пользуются сотни тысяч людей, обходится довольно дорого.\n\nесли ты хочешь, чтобы твой любимый загрузчик оставался онлайн, а разработчик не помер с голоду вместе с двумя котами, то подумай над тем, чтобы задонатить. каждый рубль поможет мне, моим котам, и {appName}!", + "DonateExplanation": "{appName} не пихает рекламу тебе в лицо и не продаёт твои личные данные, а значит работает совершенно бесплатно. но оказывается, что хостинг сервиса, которым пользуются тысячи людей, обходится довольно дорого.\n\nесли ты хочешь, чтобы твой любимый загрузчик оставался онлайн, а разработчик не помер с голоду вместе с двумя котами, то подумай над тем, чтобы задонатить. каждый рубль поможет мне, моим котам, и {appName}!", "DonateVia": "открыть", - "DonateHireMe": "или же ты можешь пригласить меня на работу.", + "DonateHireMe": "или же ты можешь пригласить меня на работу.", "SettingsVideoMute": "отключить аудио", "SettingsVideoMuteExplanation": "убирает аудио при загрузке видео, когда это возможно. игнорируется если включен режим аудио или сервис поддерживает только аудио загрузки.", "SettingsVideoGeneral": "основные", - "ErrorSoundCloudNoClientId": "мне не удалось достать client_id, который необходим для получения аудио из soundcloud. попробуй ещё раз, но если так и не получится, {ContactLink}." + "ErrorSoundCloudNoClientId": "мне не удалось достать client_id, который необходим для получения аудио из soundcloud. попробуй ещё раз, но если так и не получится, {ContactLink}.", + "CollapseServices": "что поддерживается?", + "CollapseSupport": "поддержка и исходный код", + "CollapsePrivacy": "политика конфиденциальности", + "ServicesNote": "этот список далеко не финальный и постоянно пополняется. заглядывай сюда почаще, тогда точно будешь знать, что поддерживается!", + "FollowSupport": "подписывайся на аккаунты {appName} на mastodon или twitter для новостей, поддержки, участия в опросах, и многого другого:", + "SupportNote": "помни, что ответ на твой вопрос может занять время, так как только один человек занимается и разработкой и поддержкой.", + "SourceCode": "пиши о проблемах, шарься в исходнике, или же форкай репозиторий:", + "PrivacyPolicy": "политика конфиденциальности {appName} довольно проста: ничего не хранится об истории твоих действий или загрузок. совсем. даже ошибки.\nто, что ты скачиваешь - не моё дело, а только твоё.\n\nв случаях, когда твоей загрузке требуется лайв-рендер, временно хранится неотслеживаемая информация. это необходимо для работы данной функции.\n\nв этом случае, sha256 хэш (с солью) твоего ip адреса и данные о запрошенном стриме хранятся в оперативной памяти сервера в течение 2-х минут. по истечении этого времени всё стирается. хэш твоего ip адреса используется для предоставления доступа к стриму только тебе. ни у кого (даже у меня) нет доступа к временно хранящимся данным, так как код {appName} специально не позволяет читать такие данные снаружи.\n\nты можешь посмотреть исходный код {appName} и убедиться, что всё так, как описано." } } diff --git a/src/localization/manager.js b/src/localization/manager.js index 2db0774..44d80c8 100644 --- a/src/localization/manager.js +++ b/src/localization/manager.js @@ -15,7 +15,7 @@ export function loadLoc() { } loadLoc(); export function replaceBase(s) { - return s.replace(/\n/g, '
').replace(/{appName}/g, appName).replace(/{repo}/g, repo).replace(/{bS}/g, '
').replace(/{bE}/g, '
').replace(/\*;/g, "•"); + return s.replace(/\n/g, '
').replace(/{appName}/g, appName).replace(/{repo}/g, repo).replace(/\*;/g, "•"); } export function replaceAll(lang, str, string, replacement) { let s = replaceBase(str[string]) diff --git a/src/modules/changelog/changelog.json b/src/modules/changelog/changelog.json index f53b7bf..d052879 100644 --- a/src/modules/changelog/changelog.json +++ b/src/modules/changelog/changelog.json @@ -1,20 +1,25 @@ { "current": { + "version": "4.8", + "title": "prettier than ever", + "banner": "catmakeup.webp", + "content": "this version brings many visual improvements and a completely revamped \"about\" tab.\n\nwhat's new in \"about\" tab:\n*; all information is now split into collapsible sections, making it easier to navigate.\n*; added privacy policy to further prove that none of your data is collected.\n*; added emoji to the page title to make it look consistent with other pages.\n*; added mastodon account handle and link.\n*; there are now short notes at the end of each section.\n*; other changes that are too small to describe. just go check it out!\n\nthis tab is not yet finalized and i will post a poll with possible future additions on twitter and mastodon. make sure to vote and discuss!\n\nvisual improvements:\n*; less wasted space: paddings and margins have been reduced and optimized for usability, consistency, and overall beauty.\n*; all links are now in italic. it's much easier to tell them apart from regular highlights.\n*; error popup no longer looks broken and out of place.\n*; download popup now has a proper close button, not something from 2.x era.\n*; emoji are no longer selectable or draggable.\n*; better scalability: desktop layout for home screen is shown if device viewport is wide enough to fit in three action buttons.\n*; page shouldn't look broken on phones in landscape mode (i still highly recommend using cobalt in portrait mode).\n*; removed bulletpoint padding. it was unnecessary.\n*; updated some service names.\n\nas always, you can suggest features or report bugs on any platform listed in the \"support\" section of about tab.\n\nthank you for using cobalt. i hope you have a good day :)" + }, + "history": [{ "version": "4.7", "title": "we're better together! thank you for bug reports.", "banner": "bettertogether.webp", - "content": "this update includes a bunch of improvements, many of which were made thanks to the community :D\n\nservice-related improvements:\n*; private soundcloud links are now supported (#68);\n*; tiktok usernames with dots in them no longer confuse cobalt (#71);\n*; .ogg files no longer wrongfully include a video channel (#67);\n*; fixed an issue that caused cobalt to freak out when user attempted to download an audio from audio-only service with \"mute video\" option enabled.\n\nui improvements:\n*; popup padding has been evened out. popups are now able to fit in more information on scroll, especially on mobile;\n*; all buttons are now of even size and are displayed without any padding issues across all modern browsers and devices;\n*; checkbox is no longer crippled on ios;\n*; many explanation texts have been simplified to get rid of unnecessary bloat (no bullshit, remember?);\n*; moved tiktok section in video settings higher due to higher priority;\n*; fixed unexpectedly displayed scrollbars on switch rows in firefox.\n\nstability improvements:\n*; ffmpeg process now should end upon finishing the render;\n*; ffmpeg should also quit when download is abruptly cut off;\n*; fixed a memory leak that was caused by misconfigured stream information caching (#63).\n\ninternal improvements:\n*; requested streams are now stored in cache for 2 minutes instead of 1000 hours (yes, 1000 hours, i fucked up);\n*; cached data is now reused if user requests same content within 2 minutes;\n*; page render module is now even cleaner than before;\n*; proper support for bullet-points in loc strings.\n\nyou can suggest features or report bugs on github or twitter. both work just fine, use whichever you're more comfortable with.\n\nthank you for using cobalt, and thank you for reading this changelog.\n\nyou're amazing, keep it up :)" - }, - "history": [{ + "content": "this update includes a bunch of improvements, many of which were made thanks to the community :D\n\nservice-related improvements:\n*; private soundcloud links are now supported (#68);\n*; tiktok usernames with dots in them no longer confuse cobalt (#71);\n*; .ogg files no longer wrongfully include a video channel (#67);\n*; fixed an issue that caused cobalt to freak out when user attempted to download an audio from audio-only service with \"mute video\" option enabled.\n\nui improvements:\n*; popup padding has been evened out. popups are now able to fit in more information on scroll, especially on mobile;\n*; all buttons are now of even size and are displayed without any padding issues across all modern browsers and devices;\n*; checkbox is no longer crippled on ios;\n*; many explanation texts have been simplified to get rid of unnecessary bloat (no bullshit, remember?);\n*; moved tiktok section in video settings higher due to higher priority;\n*; fixed unexpectedly displayed scrollbars on switch rows in firefox.\n\nstability improvements:\n*; ffmpeg process now should end upon finishing the render;\n*; ffmpeg should also quit when download is abruptly cut off;\n*; fixed a memory leak that was caused by misconfigured stream information caching (#63).\n\ninternal improvements:\n*; requested streams are now stored in cache for 2 minutes instead of 1000 hours (yes, 1000 hours, i fucked up);\n*; cached data is now reused if user requests same content within 2 minutes;\n*; page render module is now even cleaner than before;\n*; proper support for bullet-points in loc strings.\n\nyou can suggest features or report bugs on github or twitter. both work just fine, use whichever you're more comfortable with.\n\nthank you for using cobalt, and thank you for reading this changelog.\n\nyou're amazing, keep it up :)" + }, { "version": "4.6", "title": "mute videos and proper soundcloud support", "banner": "shutup.png", - "content": "i've been longing to implement both of these things, and here they finally are.\n\nservice-related improvements:\n{bS}*; you now can download videos with no audio! simply enable the \"mute audio\" option in settings > audio.\n*; soundcloud module has been updated, and downloads should no longer break after some time.{bE}\nvisual improvements:\n{bS}*; moved some things around in settings popup, and added separators where separation is needed.\n*; updated some texts in english and russian.\n*; version and commit hash have been joined together, now they're a single unit.{bE}\ninternal improvements:\n{bS}*; updated api documentation to include isAudioMuted.\n*; simplified the startup message.\n*; created render elements for separator and explanation due to high duplication of them in the page.\n*; fully deprecated GET method for API requests.\n*; fixed some code quirks.{bE}\nhere's how soundcloud downloads got fixed:\n\npreviously, client_id was (stupidly) hardcoded. that means cobalt wasn't able to fetch song data if soundcloud web app got updated.\nnow, cobalt tries to find the up-to-date client_id, caches it in memory, and checks if web app version has changed to update the id accordingly. you can see this change for yourself on github." + "content": "i've been longing to implement both of these things, and here they finally are.\n\nservice-related improvements:\n*; you now can download videos with no audio! simply enable the \"mute audio\" option in settings > audio.\n*; soundcloud module has been updated, and downloads should no longer break after some time.\nvisual improvements:\n*; moved some things around in settings popup, and added separators where separation is needed.\n*; updated some texts in english and russian.\n*; version and commit hash have been joined together, now they're a single unit.\ninternal improvements:\n*; updated api documentation to include isAudioMuted.\n*; simplified the startup message.\n*; created render elements for separator and explanation due to high duplication of them in the page.\n*; fully deprecated GET method for API requests.\n*; fixed some code quirks.\nhere's how soundcloud downloads got fixed:\n\npreviously, client_id was (stupidly) hardcoded. that means cobalt wasn't able to fetch song data if soundcloud web app got updated.\nnow, cobalt tries to find the up-to-date client_id, caches it in memory, and checks if web app version has changed to update the id accordingly. you can see this change for yourself on github." }, { "version": "4.5", "title": "better, faster, stronger, stable", "banner": "meowthstrong.webp", - "content": "your favorite social media downloader just got even better! this update includes a ton of imporvements and fixes.\n\nin fact, there are so many changes, i had to split them in sections.\n\nservice-related improvements:\n{bS}*; vimeo module has been revamped, all sorts of videos should now be supported.\n*; vimeo audio downloads! you now can download audios from more recent videos.\n*; {appName} now supports all sorts of tumblr links. (even those scary ones from the mobile app)\n*; vk clips support has been fixed. they rolled back the separation of videos and clips, so i had to do the same.\n*; youtube videos with community warnings should now be possible to download.{bE}\nuser interface improvements:\n{bS}*; list of supported services is now MUCH easier to read.\n*; banners in changelog history should no longer overlap each other.\n*; bullet points! they have a bit of extra padding, so it makes them stand out of the rest of text.{bE}\ninternal improvements:\n{bS}*; cobalt will now match the link to regex when using ?u= query for autopasting it into input area.\n*; better rate limiting: limiting now is done per minute, not per 20 minutes. this ensures less waiting and less attack area for request spammers.\n*; moved to my own fork of ytdl-core, cause main project seems to have been abandoned. go check it out on github or npm!\n*; ALL user inputs are now properly sanitized on the server. that includes variables for POST api method, too.\n*; \"got\" package has been (mostly) replaced by native fetch api. this should greately reduce ram usage.\n*; all unnecessary duplications of module imports have been gotten rid of. no more error passing strings from inside of service modules. you don't make mistakes only if you don't do anything, right?\n*; other code optimizations. there's less clutter overall.{bE}\nhuge update, right? seems like everything's fixed now?\n\nnope, one issue still persists: sometimes youtube server drops packets for an audio file while cobalt's rendering the video for you. this results in abrupt cuts of audio. if you want to help solving this issue, please feel free to do it on github!\n\nthank you for reading this, and thank you for sticking with cobalt and me." + "content": "your favorite social media downloader just got even better! this update includes a ton of imporvements and fixes.\n\nin fact, there are so many changes, i had to split them in sections.\n\nservice-related improvements:\n*; vimeo module has been revamped, all sorts of videos should now be supported.\n*; vimeo audio downloads! you now can download audios from more recent videos.\n*; {appName} now supports all sorts of tumblr links. (even those scary ones from the mobile app)\n*; vk clips support has been fixed. they rolled back the separation of videos and clips, so i had to do the same.\n*; youtube videos with community warnings should now be possible to download.\nuser interface improvements:\n*; list of supported services is now MUCH easier to read.\n*; banners in changelog history should no longer overlap each other.\n*; bullet points! they have a bit of extra padding, so it makes them stand out of the rest of text.\ninternal improvements:\n*; cobalt will now match the link to regex when using ?u= query for autopasting it into input area.\n*; better rate limiting: limiting now is done per minute, not per 20 minutes. this ensures less waiting and less attack area for request spammers.\n*; moved to my own fork of ytdl-core, cause main project seems to have been abandoned. go check it out on github or npm!\n*; ALL user inputs are now properly sanitized on the server. that includes variables for POST api method, too.\n*; \"got\" package has been (mostly) replaced by native fetch api. this should greately reduce ram usage.\n*; all unnecessary duplications of module imports have been gotten rid of. no more error passing strings from inside of service modules. you don't make mistakes only if you don't do anything, right?\n*; other code optimizations. there's less clutter overall.\nhuge update, right? seems like everything's fixed now?\n\nnope, one issue still persists: sometimes youtube server drops packets for an audio file while cobalt's rendering the video for you. this results in abrupt cuts of audio. if you want to help solving this issue, please feel free to do it on github!\n\nthank you for reading this, and thank you for sticking with cobalt and me." }, { "version": "4.4", "title": "over 1 million monthly requests. thank you.", @@ -28,7 +33,7 @@ "version": "4.3", "title": "developers, developers, developers, developers", "banner": "developersdevelopersdevelopers.webp", - "content": "this update features a TON of improvements.\n\ndevelopers, you now can rely on {appName} for getting content from social media. the api has been revamped and documentation is now available. you can read more about API changes down below. go crazy, and have fun :D\n\nif you're not a developer, here's a list of changes that you probably care about:\n- rate limit is now approximately 8 times bigger. no more waiting, even if you want to download entirety of your tiktok \"for you\" page.\n- some updates will now have expressive banners, just like this one.\n- fixed what was causing an error when a youtube video had no description.\n- mp4 format button text should now be displayed properly, no matter if you touched the switcher or not.\n\nnext, the star of this update — improved api!\n- main endpoint now uses POST method instead of GET.\n- internal variables for preferences have been updated to be consistent and easier to understand.\n- ip address is now hashed right upon request, not somewhere deep inside the code.\n- global stream salt variable is no longer unnecessarily passed over a billion functions.\n- url and picker keys are now separate in the json response.\n- {appName} web app now correctly processes responses with \"success\" status.\n\nif you currently have a siri shortcut or some other script that uses the GET method, make sure to update it soon. this method is deprecated, limited, and will be removed entirely in coming updates.\n\nif you ever make something using {appName}'s api, make sure to mention @justusecobalt on twitter, i would absolutely love to see what you made." + "content": "this update features a TON of improvements.\n\ndevelopers, you now can rely on {appName} for getting content from social media. the api has been revamped and documentation is now available. you can read more about API changes down below. go crazy, and have fun :D\n\nif you're not a developer, here's a list of changes that you probably care about:\n- rate limit is now approximately 8 times bigger. no more waiting, even if you want to download entirety of your tiktok \"for you\" page.\n- some updates will now have expressive banners, just like this one.\n- fixed what was causing an error when a youtube video had no description.\n- mp4 format button text should now be displayed properly, no matter if you touched the switcher or not.\n\nnext, the star of this update — improved api!\n- main endpoint now uses POST method instead of GET.\n- internal variables for preferences have been updated to be consistent and easier to understand.\n- ip address is now hashed right upon request, not somewhere deep inside the code.\n- global stream salt variable is no longer unnecessarily passed over a billion functions.\n- url and picker keys are now separate in the json response.\n- {appName} web app now correctly processes responses with \"success\" status.\n\nif you currently have a siri shortcut or some other script that uses the GET method, make sure to update it soon. this method is deprecated, limited, and will be removed entirely in coming updates.\n\nif you ever make something using {appName}'s api, make sure to mention @justusecobalt on twitter, i would absolutely love to see what you made." }, { "version": "4.2", "title": "optimized quality picking and 8k video support", @@ -40,7 +45,7 @@ }, { "version": "4.0", "title": "better and faster than ever", - "content": "this update has a ton of improvements and new features.\n\nchanges you probably care about:\n- {appName} now has support for recorded twitter spaces! download the previous conversation no matter how long it was.\n- download speeds from youtube are at least 10 times better now. you're welcome.\n- both video and audio length limits have been extended to 2 hours.\n- audio downloads from youtube, youtube music, twitter spaces, and soundcloud now have metadata! most often it's just title and artist, but when {appName} is able to get more info, it adds that metadata too.\n- tiktok downloads have been fixed, yet again, and if they ever break in the future, {appName} will fall back to downloading a less annoyingly watermarked video.\n- soundcloud downloads have been fixed, too.\n\nless notable changes:\n- currently experimenting with using mp3 as default audio format. if you set something other than mp3 before, it'll be set to mp3. you can always change it back in settings. let me know what you think about this.\n- \"download audio\" button from image picker no longer stays on the screen after popup was closed.\n- clipboard button now shows up depending on your browser's support for it.\n- you can no longer manually hide the clipboard button, 'cause it's unnecessary.\n- small internal improvements such as separation of changelog version and title.\n- fair bit of internal clean up.\n\nif you want to help me implement covers for downloaded audios, you can do it on github." + "content": "this update has a ton of improvements and new features.\n\nchanges you probably care about:\n- {appName} now has support for recorded twitter spaces! download the previous conversation no matter how long it was.\n- download speeds from youtube are at least 10 times better now. you're welcome.\n- both video and audio length limits have been extended to 2 hours.\n- audio downloads from youtube, youtube music, twitter spaces, and soundcloud now have metadata! most often it's just title and artist, but when {appName} is able to get more info, it adds that metadata too.\n- tiktok downloads have been fixed, yet again, and if they ever break in the future, {appName} will fall back to downloading a less annoyingly watermarked video.\n- soundcloud downloads have been fixed, too.\n\nless notable changes:\n- currently experimenting with using mp3 as default audio format. if you set something other than mp3 before, it'll be set to mp3. you can always change it back in settings. let me know what you think about this.\n- \"download audio\" button from image picker no longer stays on the screen after popup was closed.\n- clipboard button now shows up depending on your browser's support for it.\n- you can no longer manually hide the clipboard button, 'cause it's unnecessary.\n- small internal improvements such as separation of changelog version and title.\n- fair bit of internal clean up.\n\nif you want to help me implement covers for downloaded audios, you can do it on github." }, { "version": "3.7", "title": "support for multi media tweets is here!", @@ -56,7 +61,7 @@ }, { "version": "3.5.4", "title": "tiktok support is back :D", - "content": "you can download videos, sounds, and images from tiktok again!\nhuge thank you to @minzique for finding another api endpoint that works." + "content": "you can download videos, sounds, and images from tiktok again!\nhuge thank you to @minzique for finding another api endpoint that works." }, { "version": "3.5.2", "title": "vk clips support, improved changelog system, and less bugs", diff --git a/src/modules/emoji.js b/src/modules/emoji.js index 8f53bb4..a8ca4a6 100644 --- a/src/modules/emoji.js +++ b/src/modules/emoji.js @@ -3,7 +3,7 @@ const names = { "🎬": "clapper_board", "💰": "money_bag", "🎉": "party_popper", - "❓": "red_question_mark", + "❓": "question_mark", "✨": "sparkles", "🪅": "pinata", "🪄": "magic_wand", @@ -18,17 +18,22 @@ const names = { "🕯️": "candle", "😺": "cat", "🐶": "dog", - "🎂": "cake" + "🎂": "cake", + "🐘": "elephant", + "🐦": "bird", + "🐙": "octopus", + "🔮": "crystal_ball" } let sizing = { 22: 0.4, 30: 0.7, - 48: 0.9 + 48: 0.9, + 64: 0.9 } export default function(emoji, size, disablePadding) { if (!size) size = 22; let padding = size !== 22 ? `margin-right:${sizing[size] ? sizing[size] : "0.4"}rem;` : ``; if (disablePadding) padding = 'margin-right:0!important;'; if (!names[emoji]) emoji = "❓"; - return `${emoji}` + return `${emoji}` } diff --git a/src/modules/pageRender/elements.js b/src/modules/pageRender/elements.js index fd1b6c5..d838725 100644 --- a/src/modules/pageRender/elements.js +++ b/src/modules/pageRender/elements.js @@ -2,26 +2,22 @@ import { celebrations } from "../config.js"; export function switcher(obj) { let items = ``; - switch(obj.name) { - case "download": - items = obj.items; - break; - default: - for (let i = 0; i < obj.items.length; i++) { - let classes = obj.items[i]["classes"] ? obj.items[i]["classes"] : [] - items += `` - } - break; + if (obj.name == "download") { + items = obj.times; + } else { + for (let i = 0; i < obj.items.length; i++) { + let classes = obj.items[i]["classes"] ? obj.items[i]["classes"] : [] + items += `` + } } - return ` -
+ return `
${obj.subtitle ? `
${obj.subtitle}
` : ``}
${items}
${obj.explanation ? `
${obj.explanation}
` : ``}
` } -export function checkbox(action, text, aria, paddingType) { +export function checkbox(action, text, paddingType, aria) { let paddingClass = ` ` switch (paddingType) { case 1: @@ -33,6 +29,8 @@ export function checkbox(action, text, aria, paddingType) { case 3: paddingClass += "no-margin" break; + case 4: + paddingClass += "top-margin-only" } return `