diff --git a/.gitignore b/.gitignore index a21273d6..8af48899 100644 --- a/.gitignore +++ b/.gitignore @@ -24,3 +24,6 @@ docker-compose.yml # cookie file cookies.json + +# opensearch xml build +src/front/opensearch* diff --git a/src/front/cobalt.js b/src/front/cobalt.js index cdf143bc..2bfebb8c 100644 --- a/src/front/cobalt.js +++ b/src/front/cobalt.js @@ -610,6 +610,11 @@ window.onload = () => { detectColorScheme(); popup("migration", 1); } + if (pageQuery.has("opensearchquery")) { + eid("url-input-area").value = pageQuery.get("opensearchquery"); + button(); + eid("download-button").click(); + } window.history.replaceState(null, '', window.location.pathname); notificationCheck(); diff --git a/src/localization/languages/en.json b/src/localization/languages/en.json index 7bc69001..f5904825 100644 --- a/src/localization/languages/en.json +++ b/src/localization/languages/en.json @@ -157,6 +157,9 @@ "SettingsTwitterGifDescription": "converting looping videos to .gif reduces quality and majorly increases file size. if you want best efficiency, keep this setting off.", "UpdateTwitterGif": "twitter gifs and pinterest", "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!", + "ErrorOpenSearch": "", + "OpenSearchTitle": "Cobalt", + "OpenSearchDescription": "Cobalt is your go-to place for downloads from social and media platforms. Zero ads, trackers, or other creepy bullshit. Simply paste a share link and you're ready to rock!" } } diff --git a/src/localization/languages/ru.json b/src/localization/languages/ru.json index 7af3413b..6af788c7 100644 --- a/src/localization/languages/ru.json +++ b/src/localization/languages/ru.json @@ -159,6 +159,9 @@ "SettingsTwitterGifDescription": "конвертирование зацикленного видео в .gif снижает качество и значительно увеличивает размер файла. если важна максимальная эффективность, то не используй эту функцию.", "UpdateTwitterGif": "гифки с твиттера и одноклассники", "ErrorTweetProtected": "этот твит из закрытого аккаунта, поэтому я не могу его увидеть. попробуй другой!", - "ErrorTweetNSFW": "этот твит содержит деликатный контент, поэтому я не могу его увидеть. попробуй другой!" + "ErrorTweetNSFW": "этот твит содержит деликатный контент, поэтому я не могу его увидеть. попробуй другой!", + "ErrorOpenSearch": "", + "OpenSearchTitle": "TODO TRANSLATE ME!! Cobalt", + "OpenSearchDescription": "TODO TRANSLATE ME!! Cobalt is your go-to place for downloads from social and media platforms. Zero ads, trackers, or other creepy bullshit. Simply paste a share link and you're ready to rock!" } } diff --git a/src/modules/build.js b/src/modules/build.js index 887ffb50..342e936b 100644 --- a/src/modules/build.js +++ b/src/modules/build.js @@ -4,6 +4,7 @@ import { loadLoc, languageList } from "../localization/manager.js"; import { cleanHTML } from "./sub/utils.js"; import page from "./pageRender/page.js"; +import buildOpenSearch from "./pageRender/buildOpenSearch.js"; export async function buildFront(commitHash, branch) { try { @@ -31,6 +32,9 @@ export async function buildFront(commitHash, branch) { } fs.writeFileSync(`./build/pc/${i}.html`, cleanHTML(page(params))); + // build opensearch xml + fs.writeFileSync(`./src/front/opensearch-${i}.xml`, cleanHTML(buildOpenSearch(i))); + params["useragent"] = "iphone os"; fs.writeFileSync(`./build/ios/${i}.html`, cleanHTML(page(params))); diff --git a/src/modules/pageRender/buildOpenSearch.js b/src/modules/pageRender/buildOpenSearch.js new file mode 100644 index 00000000..11e4db01 --- /dev/null +++ b/src/modules/pageRender/buildOpenSearch.js @@ -0,0 +1,21 @@ +import loc from "../../localization/manager.js"; + +export default function (lang) { + const t = (str, replace) => { return loc(lang, str, replace) }; + + const strippedURL = process.env.webURL.replace(/^https?:\/\//, '').replace(/\/$/, ''); + + try { + return ` + + ${t('OpenSearchTitle')} + ${t("OpenSearchDescription")} + + ${process.env.webURL}icons/favicon.ico + cobalt download + + ` + } catch (err) { + return `${t('ErrorOpenSearchBuildFail', lang)}`; + } +} \ No newline at end of file diff --git a/src/modules/pageRender/page.js b/src/modules/pageRender/page.js index 81e6d514..cca5dabc 100644 --- a/src/modules/pageRender/page.js +++ b/src/modules/pageRender/page.js @@ -38,6 +38,8 @@ export default function(obj) { audioFormats[0]["text"] = t('SettingsAudioFormatBest'); + const strippedURL = process.env.webURL.replace(/^https?:\/\//, '').replace(/\/$/, ''); + try { return ` @@ -56,6 +58,8 @@ export default function(obj) { + + @@ -100,61 +104,61 @@ export default function(obj) { name: "services", title: `${emoji("🔗")} ${t("CollapseServices")}`, body: `${enabledServices}` - + `
${t("SupportNotAffiliated")}` - + `${obj.lang === "ru" ? `
${t("SupportMetaNoticeRU")}` : ''}` - + `
` - + `${t("ServicesNote")}` + + `
${t("SupportNotAffiliated")}` + + `${obj.lang === "ru" ? `
${t("SupportMetaNoticeRU")}` : ''}` + + `
` + + `${t("ServicesNote")}` }, { name: "keyboard", title: `${emoji("⌨")} ${t("CollapseKeyboard")}`, - body: - `${t("KeyboardShortcutsIntro")} + body: + `${t("KeyboardShortcutsIntro")} ${keyboardShortcuts([{ - items: [{ - combo: "Shift+D", - name: t("PasteFromClipboard") + items: [{ + combo: "Shift+D", + name: t("PasteFromClipboard") + }, { + combo: "Shift+K", + name: t("ModeToggleAuto") + }, { + combo: "Shift+L", + name: t("ModeToggleAudio") + }] }, { - combo: "Shift+K", - name: t("ModeToggleAuto") + items: [{ + combo: "⌘/Ctrl+V", + name: t("KeyboardShortcutQuickPaste") + }, { + combo: "Esc", + name: t("KeyboardShortcutClear") + }, { + combo: "Esc", + name: t("KeyboardShortcutClosePopup") + }] }, { - combo: "Shift+L", - name: t("ModeToggleAudio") - }] - }, { - items: [{ - combo: "⌘/Ctrl+V", - name: t("KeyboardShortcutQuickPaste") - }, { - combo: "Esc", - name: t("KeyboardShortcutClear") - }, { - combo: "Esc", - name: t("KeyboardShortcutClosePopup") - }] - }, { - items: [{ - combo: "Shift+B", - name: t("AboutTab") - }, { - combo: "Shift+N", - name: t("ChangelogTab") - }, { - combo: "Shift+M", - name: t("TitlePopupSettings") - }] - }])}` + items: [{ + combo: "Shift+B", + name: t("AboutTab") + }, { + combo: "Shift+N", + name: t("ChangelogTab") + }, { + combo: "Shift+M", + name: t("TitlePopupSettings") + }] + }])}` }, { name: "support", title: `${emoji("❤️‍🩹")} ${t("CollapseSupport")}`, body: `${t("SupportSelfTroubleshooting")}` - + `${socialLink(emoji("📢"), t("StatusPage"), links.statusPage)}` - + `${socialLink(emoji("🔧"), t("TroubleshootingGuide"), links.troubleshootingGuide)}` - + `
` - + `${t("FollowSupport")}` - + `${socialLinks(obj.lang)}` - + `
` - + `${t("SourceCode")}` - + `${socialLink(emoji("🐙"), repo.replace("https://github.com/", ''), repo)}` + + `${socialLink(emoji("📢"), t("StatusPage"), links.statusPage)}` + + `${socialLink(emoji("🔧"), t("TroubleshootingGuide"), links.troubleshootingGuide)}` + + `
` + + `${t("FollowSupport")}` + + `${socialLinks(obj.lang)}` + + `
` + + `${t("SourceCode")}` + + `${socialLink(emoji("🐙"), repo.replace("https://github.com/", ''), repo)}` }, { name: "privacy", title: `${emoji("🔒")} ${t("CollapsePrivacy")}`, @@ -166,14 +170,14 @@ export default function(obj) { }]) }, ...(process.env.showSponsors ? - [{ - text: t("SponsoredBy"), - classes: ["sponsored-by-text"], - nopadding: true - }, { - text: sponsoredList(), - raw: true - }] : [] + [{ + text: t("SponsoredBy"), + classes: ["sponsored-by-text"], + nopadding: true + }, { + text: sponsoredList(), + raw: true + }] : [] )] }) }, { @@ -194,11 +198,11 @@ export default function(obj) { if (!banner) return ''; return `
+ `src="${banner.url}" ` + + `alt="${banner.alt.replaceAll('"', '"')}" ` + + `width="${banner.width}" ` + + `height="${banner.height}" ` + + `onerror="this.style.opacity=0" loading="lazy">
`; })(), raw: true @@ -252,11 +256,11 @@ export default function(obj) { text: `
+ `src="updateBanners/catsleep.webp" ` + + `alt="${t("DonateImageDescription")}" ` + + `width="480" ` + + `height="270" ` + + `onerror="this.style.opacity=0" loading="lazy">
`, raw: true }, { @@ -326,58 +330,58 @@ export default function(obj) { }] }) }) - + settingsCategory({ - name: "tiktok-watermark", - title: "tiktok", - body: checkbox([{ - action: "disableTikTokWatermark", - name: t("SettingsRemoveWatermark"), - padding: "no-margin" - }]) - }) - + settingsCategory({ - name: "twitter", - title: "twitter", - body: checkbox([{ - action: "twitterGif", - name: t("SettingsTwitterGif"), - padding: "no-margin" - }]) - + explanation(t('SettingsTwitterGifDescription')) - }) - + settingsCategory({ - name: "codec", - title: t('SettingsCodecSubtitle'), - body: switcher({ - name: "vCodec", - explanation: t('SettingsCodecDescription'), - items: [{ - action: "h264", - text: "h264 (mp4)" - }, { - action: "av1", - text: "av1 (mp4)" - }, { - action: "vp9", - text: "vp9 (webm)" - }] + + settingsCategory({ + name: "tiktok-watermark", + title: "tiktok", + body: checkbox([{ + action: "disableTikTokWatermark", + name: t("SettingsRemoveWatermark"), + padding: "no-margin" + }]) }) - }) - + settingsCategory({ - name: "vimeo", - title: t('SettingsVimeoPrefer'), - body: switcher({ - name: "vimeoDash", - explanation: t('SettingsVimeoPreferDescription'), - items: [{ - action: "false", - text: "progressive" - }, { - action: "true", - text: "dash" - }] + + settingsCategory({ + name: "twitter", + title: "twitter", + body: checkbox([{ + action: "twitterGif", + name: t("SettingsTwitterGif"), + padding: "no-margin" + }]) + + explanation(t('SettingsTwitterGifDescription')) + }) + + settingsCategory({ + name: "codec", + title: t('SettingsCodecSubtitle'), + body: switcher({ + name: "vCodec", + explanation: t('SettingsCodecDescription'), + items: [{ + action: "h264", + text: "h264 (mp4)" + }, { + action: "av1", + text: "av1 (mp4)" + }, { + action: "vp9", + text: "vp9 (webm)" + }] + }) + }) + + settingsCategory({ + name: "vimeo", + title: t('SettingsVimeoPrefer'), + body: switcher({ + name: "vimeoDash", + explanation: t('SettingsVimeoPreferDescription'), + items: [{ + action: "false", + text: "progressive" + }, { + action: "true", + text: "dash" + }] + }) }) - }) }, { name: "audio", title: `${emoji("🎶")} ${t('SettingsAudioTab')}`, @@ -389,39 +393,39 @@ export default function(obj) { explanation: t('SettingsAudioFormatDescription'), items: audioFormats }) - + sep(0) - + checkbox([{ - action: "muteAudio", - name: t("SettingsVideoMute"), - padding: "no-margin" - }]) - + explanation(t('SettingsVideoMuteExplanation')) + + sep(0) + + checkbox([{ + action: "muteAudio", + name: t("SettingsVideoMute"), + padding: "no-margin" + }]) + + explanation(t('SettingsVideoMuteExplanation')) }) - + settingsCategory({ - name: "dub", - title: t("SettingsAudioDub"), - body: switcher({ - name: "dubLang", - explanation: t('SettingsAudioDubDescription'), - items: [{ - action: "original", - text: t('SettingsDubDefault') - }, { - action: "auto", - text: t('SettingsDubAuto') - }] + + settingsCategory({ + name: "dub", + title: t("SettingsAudioDub"), + body: switcher({ + name: "dubLang", + explanation: t('SettingsAudioDubDescription'), + items: [{ + action: "original", + text: t('SettingsDubDefault') + }, { + action: "auto", + text: t('SettingsDubAuto') + }] + }) + }) + + settingsCategory({ + name: "tiktok-audio", + title: "tiktok", + body: checkbox([{ + action: "fullTikTokAudio", + name: t("SettingsAudioFullTikTok"), + padding: "no-margin" + }]) + + explanation(t('SettingsAudioFullTikTokDescription')) }) - }) - + settingsCategory({ - name: "tiktok-audio", - title: "tiktok", - body: checkbox([{ - action: "fullTikTokAudio", - name: t("SettingsAudioFullTikTok"), - padding: "no-margin" - }]) - + explanation(t('SettingsAudioFullTikTokDescription')) - }) }, { name: "other", title: `${emoji("🪅")} ${t('SettingsOtherTab')}`, @@ -442,26 +446,26 @@ export default function(obj) { }] }) }) - + settingsCategory({ - name: "filename", - title: t('FilenameTitle'), - body: switcher({ - name: "filenamePattern", - items: [{ - action: "classic", - text: t('FilenamePatternClassic') - }, { - action: "basic", - text: t('FilenamePatternBasic') - }, { - action: "pretty", - text: t('FilenamePatternPretty') - }, { - action: "nerdy", - text: t('FilenamePatternNerdy') - }] - }) - + `
+ + settingsCategory({ + name: "filename", + title: t('FilenameTitle'), + body: switcher({ + name: "filenamePattern", + items: [{ + action: "classic", + text: t('FilenamePatternClassic') + }, { + action: "basic", + text: t('FilenamePatternBasic') + }, { + action: "pretty", + text: t('FilenamePatternPretty') + }, { + action: "nerdy", + text: t('FilenamePatternNerdy') + }] + }) + + `
${emoji('🎞️', 32, 1, 1)}
@@ -477,40 +481,40 @@ export default function(obj) {
` - + explanation(t('FilenameDescription')) - }) - + settingsCategory({ - name: "accessibility", - title: t('Accessibility'), - body: checkbox([{ - action: "alwaysVisibleButton", - name: t("SettingsKeepDownloadButton"), - aria: t("AccessibilityKeepDownloadButton") - }, { - action: "reduceTransparency", - name: t("SettingsReduceTransparency") - }, { - action: "disableAnimations", - name: t("SettingsDisableAnimations"), - padding: "no-margin" - }]) - }) - + settingsCategory({ - name: "miscellaneous", - title: t('Miscellaneous'), - body: checkbox([{ - action: "downloadPopup", - name: t("SettingsEnableDownloadPopup"), - aria: t("AccessibilityEnableDownloadPopup") - }, { - action: "disableMetadata", - name: t("SettingsDisableMetadata") - }, { - action: "disableChangelog", - name: t("SettingsDisableNotifications"), - padding: "no-margin" - }]) - }) + + explanation(t('FilenameDescription')) + }) + + settingsCategory({ + name: "accessibility", + title: t('Accessibility'), + body: checkbox([{ + action: "alwaysVisibleButton", + name: t("SettingsKeepDownloadButton"), + aria: t("AccessibilityKeepDownloadButton") + }, { + action: "reduceTransparency", + name: t("SettingsReduceTransparency") + }, { + action: "disableAnimations", + name: t("SettingsDisableAnimations"), + padding: "no-margin" + }]) + }) + + settingsCategory({ + name: "miscellaneous", + title: t('Miscellaneous'), + body: checkbox([{ + action: "downloadPopup", + name: t("SettingsEnableDownloadPopup"), + aria: t("AccessibilityEnableDownloadPopup") + }, { + action: "disableMetadata", + name: t("SettingsDisableMetadata") + }, { + action: "disableChangelog", + name: t("SettingsDisableNotifications"), + padding: "no-margin" + }]) + }) }] })} ${popupWithBottomButtons({ @@ -525,62 +529,62 @@ export default function(obj) { })}