cobalt/src/modules/pageRender/page.js

661 lines
29 KiB
JavaScript
Raw Normal View History

import { checkbox, collapsibleList, explanation, footerButtons, multiPagePopup, popup, popupWithBottomButtons, sep, settingsCategory, switcher, socialLink, socialLinks, urgentNotice, keyboardShortcuts, webLoc, sponsoredList, betaTag, linkSVG } from "./elements.js";
import { services as s, authorInfo, version, repo, donations, supportedAudio, links } from "../config.js";
import { getCommitInfo } from "../sub/currentCommit.js";
import loc from "../../localization/manager.js";
import emoji from "../emoji.js";
2022-09-11 16:04:06 +01:00
import changelogManager from "../changelog/changelogManager.js";
let com = getCommitInfo();
2023-08-22 20:03:31 +01:00
let enabledServices = Object.keys(s).filter(p => s[p].enabled).sort().map((p) => {
2022-12-06 19:21:07 +00:00
return `<br>&bull; ${s[p].alias ? s[p].alias : p}`
}).join('').substring(4)
let donate = ``
let donateLinks = ``
let audioFormats = supportedAudio.map((p) => {
2022-08-16 08:14:19 +01:00
return { "action": p }
})
audioFormats.unshift({ "action": "best" })
for (let i in donations["links"]) {
donateLinks += `<a id="don-${i}" class="switch autowidth" href="${donations["links"][i]}" target="_blank">REPLACEME ${i}</a>`
}
let extr = ''
for (let i in donations["crypto"]) {
donate += `<div class="subtitle${extr}">${i} (REPLACEME)</div><div id="don-${i}" class="text-to-copy" onClick="copy('don-${i}')">${donations["crypto"][i]}</div>`
2022-09-28 13:21:36 +01:00
extr = ' top-margin'
}
export default function(obj) {
const t = (str, replace) => { return loc(obj.lang, str, replace) };
2023-08-04 19:43:12 +01:00
2022-09-08 17:02:55 +01:00
let ua = obj.useragent.toLowerCase();
let isIOS = ua.match("iphone os");
let isMobile = ua.match("android") || ua.match("iphone os");
2023-09-08 11:01:54 +01:00
let platform = isMobile ? "m" : "d";
if (isMobile && isIOS) platform = "i";
audioFormats[0]["text"] = t('SettingsAudioFormatBest');
try {
2023-08-04 19:43:12 +01:00
return `
<!DOCTYPE html>
<html lang="${obj.lang}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="viewport-fit=cover, width=device-width, height=device-height, initial-scale=1, maximum-scale=${isIOS ? `1` : `5`}">
2023-08-04 19:43:12 +01:00
<title>${t("AppTitleCobalt")}</title>
<meta property="og:url" content="${process.env.webURL}">
<meta property="og:title" content="${t("AppTitleCobalt")}">
<meta property="og:description" content="${t('EmbedBriefDescription')}">
<meta property="og:image" content="${process.env.webURL}icons/generic.png">
<meta name="title" content="${t("AppTitleCobalt")}">
<meta name="description" content="${t('AboutSummary')}">
<meta name="theme-color" content="#000000">
<meta name="twitter:card" content="summary">
2023-08-04 19:43:12 +01:00
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="apple-mobile-web-app-title" content="${t("AppTitleCobalt")}">
<link rel="icon" type="image/x-icon" href="icons/favicon.ico">
<link rel="icon" type="image/png" sizes="32x32" href="icons/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="icons/favicon-16x16.png">
2023-08-04 19:43:12 +01:00
<link rel="apple-touch-icon" sizes="180x180" href="icons/apple-touch-icon.png">
<link rel="manifest" href="manifest.webmanifest">
2024-01-12 23:44:30 +00:00
<link rel="preload" href="fonts/notosansmono.css" as="style">
<link rel="stylesheet" href="fonts/notosansmono.css">
<link rel="stylesheet" href="cobalt.css">
</head>
2024-01-17 12:04:02 +00:00
<body id="cobalt-body" ${platform === "d" ? 'class="desktop"' : ''}>
<noscript>
<div style="margin: 2rem;">${t('NoScriptMessage')}</div>
</noscript>
${multiPagePopup({
name: "about",
2023-08-04 19:43:12 +01:00
closeAria: t('AccessibilityGoBack'),
tabs: [{
name: "about",
title: `${emoji("🐲")} ${t('AboutTab')}`,
content: popup({
name: "about",
header: {
aboveTitle: {
text: t('MadeWithLove'),
url: authorInfo.link
},
2023-08-04 19:43:12 +01:00
closeAria: t('AccessibilityGoBack'),
title: `${emoji("🔮", 30)} ${t('TitlePopupAbout')}`
},
body: [{
text: t('AboutSummary')
}, {
text: collapsibleList([{
2023-08-04 19:43:12 +01:00
name: "services",
title: `${emoji("🔗")} ${t("CollapseServices")}`,
body: `${enabledServices}`
+ `<div class="explanation embedded">${t("SupportNotAffiliated")}`
+ `${obj.lang === "ru" ? `<br>${t("SupportMetaNoticeRU")}` : ''}`
+ `</div>`
+ `${t("ServicesNote")}`
}, {
name: "keyboard",
title: `${emoji("⌨")} ${t("CollapseKeyboard")}`,
body:
`${t("KeyboardShortcutsIntro")}
${keyboardShortcuts([{
items: [{
combo: "Shift+D",
name: t("PasteFromClipboard")
}, {
combo: "Shift+K",
name: t("ModeToggleAuto")
}, {
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")
}]
}])}`
}, {
2023-08-04 19:43:12 +01:00
name: "support",
title: `${emoji("❤️‍🩹")} ${t("CollapseSupport")}`,
body: `${t("SupportSelfTroubleshooting")}`
+ `${socialLink(emoji("📢"), t("StatusPage"), links.statusPage)}`
+ `${socialLink(emoji("🔧"), t("TroubleshootingGuide"), links.troubleshootingGuide)}`
+ `<br>`
+ `${t("FollowSupport")}`
+ `${socialLinks(obj.lang)}`
+ `<br>`
+ `${t("SourceCode")}`
+ `${socialLink(emoji("🐙"), repo.replace("https://github.com/", ''), repo)}`
}, {
2023-08-04 19:43:12 +01:00
name: "privacy",
title: `${emoji("🔒")} ${t("CollapsePrivacy")}`,
2023-08-04 19:43:12 +01:00
body: t("PrivacyPolicy")
}, {
name: "legal",
title: `${emoji("📑")} ${t("CollapseLegal")}`,
body: t("FairUse")
}])
},
...(process.env.showSponsors ?
[{
text: t("SponsoredBy"),
classes: ["sponsored-by-text"],
nopadding: true
}, {
text: sponsoredList(),
raw: true
}] : []
)]
})
}, {
name: "changelog",
title: `${emoji("🎉")} ${t('ChangelogTab')}`,
content: popup({
name: "changelog",
header: {
2023-08-04 19:43:12 +01:00
closeAria: t('AccessibilityGoBack'),
title: `${emoji("🪄", 30)} ${t('TitlePopupChangelog')}`
},
body: [{
text: `<div class="category-title">${t('ChangelogLastMajor')}</div>`,
raw: true
}, {
2024-01-14 23:53:06 +00:00
text: (() => {
const banner = changelogManager('banner');
if (!banner) return '';
return `<div class="changelog-banner">
<img class="changelog-img" ` +
`src="${banner.url}" ` +
`alt="${banner.alt.replaceAll('"', '&quot;')}" ` +
`width="${banner.width}" ` +
`height="${banner.height}" ` +
`onerror="this.style.opacity=0" loading="lazy">
</div>`;
})(),
raw: true
2023-08-04 19:43:12 +01:00
}, {
text: changelogManager("version"),
classes: ["changelog-tags"],
nopadding: true
}, {
2022-09-11 16:04:06 +01:00
text: changelogManager("title"),
classes: ["changelog-subtitle"],
nopadding: true
}, {
2022-10-02 15:13:33 +01:00
text: changelogManager("content")
}, {
2023-08-04 19:43:12 +01:00
text: sep(),
raw: true
},{
text: `<a class="text-backdrop changelog-tag-version" href="${repo}/commit/${obj.hash}">#${obj.hash}</a>`,
classes: ["changelog-tags"],
nopadding: true
}, {
text: com[0],
classes: ["changelog-subtitle"],
nopadding: true
}, {
text: com[1]
2022-09-11 16:04:06 +01:00
}, {
text: `<div class="category-title">${t('ChangelogOlder')}</div>`,
2022-09-11 16:04:06 +01:00
raw: true
}, {
2023-08-04 19:43:12 +01:00
text: `
<div id="changelog-history">
<button class="switch bottom-margin" onclick="loadOnDemand('changelog-history', '0')">${t("ChangelogPressToExpand")}</button>
</div>`,
2022-09-11 16:04:06 +01:00
raw: true
}]
})
}, {
name: "donate",
2023-05-17 17:50:11 +01:00
title: `${emoji("💖")} ${t('DonationsTab')}`,
content: popup({
name: "donate",
header: {
2023-08-04 19:43:12 +01:00
closeAria: t('AccessibilityGoBack'),
title: emoji("💸", 30) + t('TitlePopupDonate')
},
body: [{
text: `<div class="category-title">${t('DonateSub')}</div>`,
raw: true
}, {
text: `
<div class="changelog-banner">
<img class="changelog-img" ` +
`src="updateBanners/catsleep.webp" ` +
`alt="${t("DonateImageDescription")}" ` +
`width="480" ` +
`height="270" ` +
`onerror="this.style.opacity=0" loading="lazy">
2023-08-04 19:43:12 +01:00
</div>`,
raw: true
}, {
text: t('DonateExplanation')
}, {
text: donateLinks.replace(/REPLACEME/g, t('DonateVia')),
raw: true
}, {
text: t('DonateLinksDescription'),
classes: ["explanation"]
}, {
text: sep(),
raw: true
}, {
text: donate.replace(/REPLACEME/g, t('ClickToCopy')),
classes: ["desc-padding"]
}, {
text: sep(),
raw: true
}, {
text: t('DonateHireMe', authorInfo.link),
classes: ["desc-padding"]
}]
})
}],
})}
${multiPagePopup({
name: "settings",
2023-08-04 19:43:12 +01:00
closeAria: t('AccessibilityGoBack'),
header: {
aboveTitle: {
text: `v.${version}-${obj.hash}${platform} (${obj.branch})`,
url: `${repo}/commit/${obj.hash}`
},
title: `${emoji("⚙️", 30)} ${t('TitlePopupSettings')}`
},
tabs: [{
name: "video",
title: `${emoji("🎬")} ${t('SettingsVideoTab')}`,
content: settingsCategory({
name: "downloads",
2023-02-26 16:49:25 +00:00
title: t('SettingsQualitySubtitle'),
body: switcher({
2022-11-04 08:49:58 +00:00
name: "vQuality",
explanation: t('SettingsQualityDescription'),
items: [{
2023-08-04 19:43:12 +01:00
action: "max",
text: "8k+"
}, {
2023-08-04 19:43:12 +01:00
action: "2160",
text: "4k"
}, {
2023-08-04 19:43:12 +01:00
action: "1440",
text: "1440p"
}, {
2023-08-04 19:43:12 +01:00
action: "1080",
text: "1080p"
2023-02-26 16:49:25 +00:00
}, {
2023-08-04 19:43:12 +01:00
action: "720",
text: "720p"
2023-02-26 16:49:25 +00:00
}, {
2023-08-04 19:43:12 +01:00
action: "480",
text: "480p"
2023-02-26 16:49:25 +00:00
}, {
2023-08-04 19:43:12 +01:00
action: "360",
text: "360p"
}]
})
})
+ settingsCategory({
name: "tiktok-watermark",
title: "tiktok",
2023-08-04 19:43:12 +01:00
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({
2023-02-26 16:49:25 +00:00
name: "vCodec",
explanation: t('SettingsCodecDescription'),
items: [{
2023-08-04 19:43:12 +01:00
action: "h264",
text: "h264 (mp4)"
2023-02-26 16:49:25 +00:00
}, {
2023-08-04 19:43:12 +01:00
action: "av1",
text: "av1 (mp4)"
}, {
2023-08-04 19:43:12 +01:00
action: "vp9",
text: "vp9 (webm)"
}]
2022-08-16 11:31:41 +01:00
})
})
+ settingsCategory({
name: "vimeo",
title: t('SettingsVimeoPrefer'),
body: switcher({
name: "vimeoDash",
explanation: t('SettingsVimeoPreferDescription'),
items: [{
2023-08-04 19:43:12 +01:00
action: "false",
text: "progressive"
}, {
2023-08-04 19:43:12 +01:00
action: "true",
text: "dash"
}]
})
})
}, {
name: "audio",
title: `${emoji("🎶")} ${t('SettingsAudioTab')}`,
content: settingsCategory({
name: "general",
2023-02-26 16:49:25 +00:00
title: t('SettingsFormatSubtitle'),
2023-08-04 19:43:12 +01:00
body: switcher({
name: "aFormat",
explanation: t('SettingsAudioFormatDescription'),
items: audioFormats
})
+ 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: "tiktok-audio",
2023-08-04 19:43:12 +01:00
title: "tiktok",
body: checkbox([{
action: "fullTikTokAudio",
name: t("SettingsAudioFullTikTok"),
padding: "no-margin"
}])
+ explanation(t('SettingsAudioFullTikTokDescription'))
})
}, {
name: "other",
title: `${emoji("🪅")} ${t('SettingsOtherTab')}`,
content: settingsCategory({
name: "appearance",
title: t('SettingsAppearanceSubtitle'),
body: switcher({
name: "theme",
items: [{
2023-08-04 19:43:12 +01:00
action: "auto",
text: t('SettingsThemeAuto')
2022-08-16 08:14:19 +01:00
}, {
2023-08-04 19:43:12 +01:00
action: "dark",
text: t('SettingsThemeDark')
2022-08-16 08:14:19 +01:00
}, {
2023-08-04 19:43:12 +01:00
action: "light",
text: t('SettingsThemeLight')
}]
2023-08-04 19:43:12 +01:00
})
})
+ settingsCategory({
name: "filename",
2023-10-14 17:51:53 +01:00
title: t('FilenameTitle'),
body: switcher({
name: "filenamePattern",
items: [{
action: "classic",
text: t('FilenamePatternClassic')
}, {
action: "basic",
text: t('FilenamePatternBasic')
2023-10-14 17:51:53 +01:00
}, {
action: "pretty",
text: t('FilenamePatternPretty')
}, {
action: "nerdy",
text: t('FilenamePatternNerdy')
}]
})
2023-10-14 17:51:53 +01:00
+ `<div id="filename-preview">
<div id="video-filename" class="filename-item line">
${emoji('🎞️', 32, 1, 1)}
<div class="filename-container">
<div class="filename-label">${t('Preview')}</div>
<div id="video-filename-text"></div>
</div>
</div>
<div id="audio-filename" class="filename-item">
${emoji('🎧', 32, 1, 1)}
<div class="filename-container">
<div class="filename-label">${t('Preview')}</div>
<div id="audio-filename-text"></div>
</div>
</div>
</div>`
+ explanation(t('FilenameDescription'))
})
2023-08-04 19:43:12 +01:00
+ 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({
2022-09-28 13:21:36 +01:00
name: "miscellaneous",
title: t('Miscellaneous'),
2023-08-04 19:43:12 +01:00
body: checkbox([{
action: "downloadPopup",
name: t("SettingsEnableDownloadPopup"),
aria: t("AccessibilityEnableDownloadPopup")
}, {
action: "disableMetadata",
2023-09-06 15:01:17 +01:00
name: t("SettingsDisableMetadata")
}, {
action: "disableChangelog",
name: t("SettingsDisableNotifications"),
padding: "no-margin"
2023-08-04 19:43:12 +01:00
}])
2022-09-08 17:02:55 +01:00
})
}]
})}
${popupWithBottomButtons({
name: "picker",
2023-08-04 19:43:12 +01:00
closeAria: t('AccessibilityGoBack'),
header: {
title: `${emoji("🧮", 30)} <div id="picker-title"></div>`,
explanation: `<div id="picker-subtitle"></div>`,
},
buttons: [`<a id="picker-download" class="switch" target="_blank" href="/">${t('ImagePickerDownloadAudio')}</a>`],
content: '<div id="picker-holder"></div>'
})}
2023-08-04 19:43:12 +01:00
<div id="popup-download-container" class="popup-from-bottom">
${popup({
name: "download",
2023-08-04 19:43:12 +01:00
standalone: true,
buttonOnly: true,
classes: ["small"],
2023-08-04 19:43:12 +01:00
header: {
closeAria: t('AccessibilityGoBack'),
emoji: emoji("🐱", 78, 1, 1),
title: t('TitlePopupDownload')
},
body: switcher({
name: "download",
explanation: `${!isIOS ? t('DownloadPopupDescription') : t('DownloadPopupDescriptionIOS')}`,
items: `<a id="pd-download" class="switch full" target="_blank" href="/"><span>${t('Download')}</span></a>
<div id="pd-share" class="switch full">${t('ShareURL')}</div>
<div id="pd-copy" class="switch full">${t('CopyURL')}</div>`
}),
buttonText: t('PopupCloseDone')
})}
</div>
<div id="popup-error-container" class="popup-from-bottom">
${popup({
name: "error",
standalone: true,
buttonOnly: true,
classes: ["small"],
2023-08-04 19:43:12 +01:00
header: {
title: t('TitlePopupError'),
emoji: emoji("😿", 78, 1, 1),
},
body: `<div id="desc-error" class="desc-padding subtext desc-error"></div>`,
buttonText: t('ErrorPopupCloseButton')
})}
</div>
<div id="popup-migration-container" class="popup-from-bottom">
${popup({
name: "migration",
standalone: true,
buttonOnly: true,
classes: ["small"],
header: {
title: t('NewDomainWelcomeTitle'),
emoji: emoji("😸", 78, 1, 1),
},
body: `<div id="desc-migration" class="desc-padding subtext desc-error">${t('NewDomainWelcome')}</div>`,
2023-08-04 19:43:12 +01:00
buttonText: t('ErrorPopupCloseButton')
})}
<div id="popup-backdrop-message" onclick="popup('message', 0)"></div>
2023-08-04 19:43:12 +01:00
</div>
<div id="popup-backdrop" onclick="hideAllPopups()"></div>
<div id="home" style="visibility:hidden">
${urgentNotice({
emoji: "🫧",
text: t("UpdateNewYears"),
visible: true,
action: "popup('about', 1, 'changelog')"
})}
<div id="cobalt-main-box" class="center">
2023-10-28 13:51:20 +01:00
<div id="logo">${t("AppTitleCobalt")}${betaTag()}</div>
2023-08-04 19:43:12 +01:00
<div id="download-area">
<div id="top">
<div id="link-icon">${linkSVG}</div>
<input id="url-input-area" class="mono" type="text" autocomplete="off" spellcheck="false" maxlength="256" autocapitalize="off" placeholder="${t('LinkInput')}" aria-label="${t('AccessibilityInputArea')}" oninput="button()">
2023-08-04 19:43:12 +01:00
<button id="url-clear" onclick="clearInput()" style="display:none;">x</button>
<input id="download-button" class="mono dontRead" onclick="download(document.getElementById('url-input-area').value)" type="submit" value="" disabled aria-label="${t('AccessibilityDownloadButton')}">
2023-08-04 19:43:12 +01:00
</div>
<div id="bottom">
<button id="paste" class="switch" onclick="pasteClipboard()" aria-label="${t('PasteFromClipboard')}">${emoji("📋", 22)} ${t('PasteFromClipboard')}</button>
${switcher({
name: "audioMode",
noParent: true,
items: [{
action: "false",
text: `${emoji("✨")} ${t("ModeToggleAuto")}`
}, {
action: "true",
text: `${emoji("🎶")} ${t("ModeToggleAudio")}`
}]
})}
</div>
2022-09-28 13:21:36 +01:00
</div>
</div>
<footer id="footer">
2023-08-04 19:43:12 +01:00
${footerButtons([{
name: "about",
type: "popup",
text: `${emoji("🐲" , 22)} ${t('AboutTab')}`,
aria: t('AccessibilityOpenAbout')
}, {
name: "about",
type: "popup",
context: "donate",
text: `${emoji("💖", 22)} ${t('Donate')}`,
aria: t('AccessibilityOpenDonate')
}, {
name: "settings",
type: "popup",
text: `${emoji("⚙️", 22)} ${t('TitlePopupSettings')}`,
aria: t('AccessibilityOpenSettings')
}])}
</footer>
</div>
<script>
2024-01-14 16:40:41 +00:00
let defaultApiUrl = '${process.env.apiURL ? process.env.apiURL : ''}';
const loc = ${webLoc(t,
[
'ErrorNoInternet',
'ErrorNoUrlReturned',
'ErrorUnknownStatus',
'ChangelogPressToHide',
'MediaPickerTitle',
'MediaPickerExplanationPhone',
'MediaPickerExplanationPC',
'ImagePickerTitle',
'ImagePickerExplanationPhone',
'ImagePickerExplanationPC',
'FeatureErrorGeneric',
'ClipboardErrorNoPermission',
'ClipboardErrorFirefox',
'DataTransferSuccess',
'DataTransferError',
'FilenamePreviewVideoTitle',
'FilenamePreviewAudioTitle',
'FilenamePreviewAudioAuthor'
])}
</script>
<script src="cobalt.js"></script>
</body>
2023-08-04 19:43:12 +01:00
</html>
`
} catch (err) {
return `${t('ErrorPageRenderFail', obj.hash)}`;
}
}