From 271167f421b92e635e5f39d4ed9a2728f52b3012 Mon Sep 17 00:00:00 2001 From: wukko Date: Tue, 15 Nov 2022 23:37:33 +0600 Subject: [PATCH] 4.3.2 --- package.json | 2 +- src/front/cobalt.css | 10 ++++-- src/front/cobalt.js | 37 +++++++++++++++-------- src/localization/languages/en.json | 8 ++--- src/localization/languages/ru.json | 8 ++--- src/modules/changelog/changelog.json | 13 +++++--- src/modules/changelog/changelogManager.js | 5 +-- src/modules/pageRender/onDemand.js | 8 +++-- src/modules/pageRender/page.js | 6 ++-- src/modules/services/twitter.js | 24 ++++++++++----- 10 files changed, 77 insertions(+), 44 deletions(-) diff --git a/package.json b/package.json index cf3c47a..05daa2f 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "cobalt", "description": "save what you love", - "version": "4.3.1", + "version": "4.3.2", "author": "wukko", "exports": "./src/cobalt.js", "type": "module", diff --git a/src/front/cobalt.css b/src/front/cobalt.css index 2e0063e..3a3c2fe 100644 --- a/src/front/cobalt.css +++ b/src/front/cobalt.css @@ -387,15 +387,21 @@ input[type="checkbox"] { .settings-category { padding-bottom: 1.2rem; } +.separator { + float: left; +} +.separator, .category-title { width: 100%; - text-align: left; - line-height: 1.7rem; color: var(--accent-unhover-2); border-bottom: 0.05rem solid var(--accent-unhover-2); padding-bottom: 0.25rem; margin-bottom: 1rem; } +.category-title { + text-align: left; + line-height: 1.7rem; +} .bottom-margin { margin-bottom: 1rem!important; } diff --git a/src/front/cobalt.js b/src/front/cobalt.js index 95f76d8..30ba26f 100644 --- a/src/front/cobalt.js +++ b/src/front/cobalt.js @@ -1,10 +1,12 @@ let ua = navigator.userAgent.toLowerCase(); let isIOS = ua.match("iphone os"); let isMobile = ua.match("android") || ua.match("iphone os"); -let version = 16; +let version = 17; 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 = `
` +let store = {} + let switchers = { "theme": ["auto", "light", "dark"], "vFormat": ["mp4", "webm"], @@ -346,7 +348,7 @@ async function download(url) { switch (j.status) { case "redirect": changeDownloadButton(2, '>>>'); - setTimeout(() => { changeButton(1); }, 3000); + setTimeout(() => { changeButton(1); }, 1500); sGet("downloadPopup") === "true" ? popup('download', 1, j.url) : window.open(j.url, '_blank'); break; case "picker": @@ -357,7 +359,7 @@ async function download(url) { if (jp.status === "continue") { changeDownloadButton(2, '>>>'); popup('picker', 1, { audio: j.audio, arr: j.picker, type: j.pickerType }); - setTimeout(() => { changeButton(1) }, 5000); + setTimeout(() => { changeButton(1) }, 2500); } else { changeButton(0, jp.text); } @@ -365,7 +367,7 @@ async function download(url) { } else if (j.picker) { changeDownloadButton(2, '>>>'); popup('picker', 1, { arr: j.picker, type: j.pickerType }); - setTimeout(() => { changeButton(1) }, 5000); + setTimeout(() => { changeButton(1) }, 2500); } else { changeButton(0, loc.noURLReturned); } @@ -376,7 +378,7 @@ async function download(url) { let jp = await res.json(); if (jp.status === "continue") { changeDownloadButton(2, '>>>'); window.location.href = j.url; - setTimeout(() => { changeButton(1) }, 5000); + setTimeout(() => { changeButton(1) }, 2500); } else { changeButton(0, jp.text); } @@ -400,23 +402,34 @@ async function download(url) { }).catch((error) => internetError()); } async function loadOnDemand(elementId, blockId) { - let store = eid(elementId).innerHTML; + store.historyButton = eid(elementId).innerHTML; + let j = {} eid(elementId).innerHTML = "..." - await fetch(`/api/onDemand?blockId=${blockId}`).then(async (r) => { - let j = await r.json(); + try { + if (store.historyContent) { + j = store.historyContent; + } else { + await fetch(`/api/onDemand?blockId=${blockId}`).then(async (r) => { + j = await r.json(); + if (j.status === "success") store.historyContent = j; + }) + } if (j.status === "success" && j.status !== "rate-limit") { if (j.text) { - eid(elementId).innerHTML = j.text; + eid(elementId).innerHTML = `${j.text}`; } else { throw new Error() } } else { throw new Error() } - }).catch((error) => { - eid(elementId).innerHTML = store; + } catch (e) { + eid(elementId).innerHTML = store.historyButton; internetError() - }); + } +} +function restoreUpdateHistory() { + eid("changelog-history").innerHTML = store.historyButton; } window.onload = () => { loadSettings(); diff --git a/src/localization/languages/en.json b/src/localization/languages/en.json index 080ad67..87aed72 100644 --- a/src/localization/languages/en.json +++ b/src/localization/languages/en.json @@ -73,8 +73,7 @@ "SettingsVideoTab": "video", "SettingsAudioTab": "audio", "SettingsOtherTab": "other", - "ChangelogLastCommit": "last commit", - "ChangelogLastMajor": "last update", + "ChangelogLastMajor": "current version & commit", "AccessibilityModeToggle": "toggle download mode", "DonateLinksDescription": "donation links open in a new tab. this is the best way to donate money, if you want me to receive it directly.", "SettingsAudioFormatBest": "best", @@ -95,7 +94,7 @@ "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 updates", + "ChangelogOlder": "previous versions", "ChangelogPressToExpand": "press to load", "Miscellaneous": "miscellaneous", "ModeToggleAuto": "auto mode", @@ -106,6 +105,7 @@ "MediaPickerExplanationPhone": "press or press and hold to download what you want.", "MediaPickerExplanationPhoneIOS": "press and hold, hide the preview, and then select \"download linked file\" to save.", "TwitterSpaceWasntRecorded": "this twitter space wasn't recorded, so there's nothing to download. try another one!", - "ErrorCantProcess": "i couldn't process your request :(\nyou can try again, but if issue persists, please {ContactLink}." + "ErrorCantProcess": "i couldn't process your request :(\nyou can try again, but if issue persists, please {ContactLink}.", + "ChangelogPressToHide": "press to hide" } } diff --git a/src/localization/languages/ru.json b/src/localization/languages/ru.json index a5d7479..8d532de 100644 --- a/src/localization/languages/ru.json +++ b/src/localization/languages/ru.json @@ -73,8 +73,7 @@ "SettingsVideoTab": "видео", "SettingsAudioTab": "аудио", "SettingsOtherTab": "другое", - "ChangelogLastCommit": "последний коммит (на английском)", - "ChangelogLastMajor": "последнее обновление (на английском)", + "ChangelogLastMajor": "текущая версия и коммит (на английском)", "AccessibilityModeToggle": "переключить режим скачивания", "DonateLinksDescription": "ссылки на донаты открываются в новой вкладке. это лучший метод пожертвовать деньги, если ты хочешь, чтобы я получил их лично, а не в виде крипто.", "SettingsAudioFormatBest": "лучший", @@ -95,7 +94,7 @@ "ErrorUnknownStatus": "сервер ответил мне чем-то непонятным. такого происходить не должно. перезагрузи страницу, а если не поможет, то {ContactLink}.", "PasteFromClipboard": "вставить из буфера обмена", "FollowTwitter": "а ещё, в твиттере {appName} есть опросы, новости, и многое другое: @justusecobalt", - "ChangelogOlder": "предыдущие обновления (на английском)", + "ChangelogOlder": "предыдущие версии (на английском)", "ChangelogPressToExpand": "нажми, чтобы загрузить", "Miscellaneous": "разное", "ModeToggleAuto": "авто режим", @@ -106,6 +105,7 @@ "MediaPickerExplanationPhone": "нажми, или нажми и удерживай, чтобы скачать.", "MediaPickerExplanationPhoneIOS": "нажми и удерживай, затем скрой превью, и наконец выбери \"загрузить файл по ссылке\".", "TwitterSpaceWasntRecorded": "этот twitter space не был записан, поэтому я не могу его скачать. попробуй другой!", - "ErrorCantProcess": "я не смог обработать твой запрос :(\nты можешь попробовать ещё раз, но если не поможет, то {ContactLink}." + "ErrorCantProcess": "я не смог обработать твой запрос :(\nты можешь попробовать ещё раз, но если не поможет, то {ContactLink}.", + "ChangelogPressToHide": "нажми, чтобы скрыть" } } diff --git a/src/modules/changelog/changelog.json b/src/modules/changelog/changelog.json index 3b12fad..34fb330 100644 --- a/src/modules/changelog/changelog.json +++ b/src/modules/changelog/changelog.json @@ -1,11 +1,15 @@ { "current": { + "version": "4.3.2", + "title": "twitter improvements & changelog overhaul", + "content": "- you can download explicit content from twitter.\n- direct video links from twitter are properly supported (video/1, video/2, etc.).\n- changelog history got support for banners.\n- changelog categories are not messy anymore.\n- {appName} version in changelogs is now highlighted.\n- changelog history got separators to make text easier to read.\n- changelog history can be collapsed after loading.\n- download button takes less time to change back to pressable state.\n\nif you're a developer and would like to play around with cobalt's api, then read more about it in older changelogs below!" + }, + "history": [{ "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." - }, - "history": [{ + }, { "version": "4.2", "title": "optimized quality picking and 8k video support", "content": "- this update fixes quality picking that was accidentally broken in 4.0 update.\n- you now can download videos in 8k from youtube. why would you that? no idea. but i'm more than happy to give you this option.\n- default video quality for downloads from pc is now 1440p, and 720p for phones.\n- default video format is now mp4 for everyone.\n- default audio format is now mp3 for everyone.\n\nyou can always change new defaults back to whatever you prefer in settings.\n\nother changes:\n- added more clarity to quality picker description.\n- youtube video codecs are now right in the picker.\n- setup script is now easier to understand." @@ -16,9 +20,8 @@ }, { "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.\n\nfun fact: average {appName} user is 10 times cooler than a regular person." - }], - "olderHistory": [{ + "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!", "content": "{appName} now lets you save any of the videos or gifs in a tweet. even if there are many of them.\n\nsimply paste a link like you'd usually do and {appName} will ask what exactly you want to save.\n\nFIREFOX USERS: if you have strict tracking protection on, you might wanna turn it off for {appName}, or else twitter video previews won't load. firefox filters out twitter image cdn as if it was a tracker, which it's not. it's a false-positive.\n\nhowever, you can leave it on if you're fine with blank squares and video numbers. i have thought of that in prior, you're welcome.\n\nother changes:\n- repurposed ex tiktok-only image picker to be dynamic and adapt depending on content to pick. that's exactly how twitter multi media downloads work.\n- {appName} is now properly viewable on phones with tiny screens, such as first gen iphone se.\n- scrollbars now should be visible only where they're needed.\n- brought back proper twitter api, because other one doesn't have multi media stuff (at least yet).\n- cleaned up some internal files, including main frontend js file.\n- reorganized some files in project directory, now you won't get lost when contributing or just looking through {appName}'s code." diff --git a/src/modules/changelog/changelogManager.js b/src/modules/changelog/changelogManager.js index 6f6a812..306c6e1 100644 --- a/src/modules/changelog/changelogManager.js +++ b/src/modules/changelog/changelogManager.js @@ -7,7 +7,7 @@ export default function(string) { try { switch (string) { case "title": - return `${replaceBase(changelog["current"]["title"])} (${changelog["current"]["version"]})`; + return `${changelog["current"]["version"]}: ${replaceBase(changelog["current"]["title"])}`; case "banner": return changelog["current"]["banner"] ? `updateBanners/${changelog["current"]["banner"]}` : false; case "content": @@ -15,9 +15,10 @@ export default function(string) { case "history": return changelog["history"].map((i) => { return { - title: replaceBase(i["title"]), + title: `${i["version"]}: ${replaceBase(i["title"])}`, content: replaceBase(i["content"]), version: i["version"], + banner: i["banner"] ? `updateBanners/${i["banner"]}` : false, } }); default: diff --git a/src/modules/pageRender/onDemand.js b/src/modules/pageRender/onDemand.js index e431ce5..7ab1373 100644 --- a/src/modules/pageRender/onDemand.js +++ b/src/modules/pageRender/onDemand.js @@ -3,9 +3,11 @@ import changelogManager from "../changelog/changelogManager.js" export function changelogHistory() { // blockId 0 let history = changelogManager("history"); let render = ``; - + + let historyLen = history.length for (let i in history) { - render += `` + let separator = (i != 0 && i != historyLen) ? '
' : '' + render += `${separator}${history[i]["banner"] ? `
` : ''}` } return render; -} \ No newline at end of file +} diff --git a/src/modules/pageRender/page.js b/src/modules/pageRender/page.js index 6fb498e..4c39f0b 100644 --- a/src/modules/pageRender/page.js +++ b/src/modules/pageRender/page.js @@ -111,10 +111,7 @@ export default function(obj) { }, { text: changelogManager("content") }, { - text: `
${loc(obj.lang, 'ChangelogLastCommit')}
`, - raw: true - }, { - text: `${com[0]} (${obj.hash})`, + text: `
${obj.hash}: ${com[0]}`, classes: ["changelog-subtitle"], nopadding: true }, { @@ -330,6 +327,7 @@ export default function(obj) { noInternet: ` + "`" + loc(obj.lang, 'ErrorNoInternet') + "`" + `, noURLReturned: ` + "`" + loc(obj.lang, 'ErrorNoUrlReturned') + "`" + `, unknownStatus: ` + "`" + loc(obj.lang, 'ErrorUnknownStatus') + "`" + `, + collapseHistory: ` + "`" + loc(obj.lang, 'ChangelogPressToHide') + "`" + `, toggleDefault: '${emoji("✨")} ${loc(obj.lang, "ModeToggleAuto")}', toggleAudio: '${emoji("🎶")} ${loc(obj.lang, "ModeToggleAudio")}', pickerDefault: ` + "`" + loc(obj.lang, 'MediaPickerTitle') + "`" + `, diff --git a/src/modules/services/twitter.js b/src/modules/services/twitter.js index e9ae0be..23b0270 100644 --- a/src/modules/services/twitter.js +++ b/src/modules/services/twitter.js @@ -16,17 +16,27 @@ export default async function(obj) { "Content-Type": "application/json", "Content-Length": 0 }; - let req_act = await got.post(`${apiURL}/guest/activate.json`, { - headers: _headers - }); + let req_act = await got.post(`${apiURL}/guest/activate.json`, { headers: _headers }); req_act = JSON.parse(req_act.body) _headers["x-guest-token"] = req_act["guest_token"]; + let showURL = `${apiURL}/statuses/show/${obj.id}.json?tweet_mode=extended&include_user_entities=0&trim_user=1&include_entities=0&cards_platform=Web-12&include_cards=1` if (!obj.spaceId) { - let req_status = await got.get( - `${apiURL}/statuses/show/${obj.id}.json?tweet_mode=extended&include_user_entities=0&trim_user=1&include_entities=0&cards_platform=Web-12&include_cards=1`, - { headers: _headers } - ); + // kind of wonky but it works :D + let req_status = {} + try { + req_status = await got.get(showURL, { headers: _headers }); + } catch (e) { + try { + _headers.Authorization = "Bearer AAAAAAAAAAAAAAAAAAAAAPYXBAAAAAAACLXUNDekMxqa8h%2F40K4moUkGsoc%3DTYfbDKbT3jJPCEVnMYqilB28NHfOPqkca3qaAxGfsyKCs0wRbw"; + delete _headers["x-guest-token"] + req_act = await got.post(`${apiURL}/guest/activate.json`, { headers: _headers }); + req_act = JSON.parse(req_act.body) + _headers["x-guest-token"] = req_act["guest_token"]; + req_status = await got.get(showURL, { headers: _headers }); + } catch(e) {} + } req_status = JSON.parse(req_status.body); + if (req_status == {}) return { error: loc(obj.lang, 'ErrorCouldntFetch') } if (req_status["extended_entities"] && req_status["extended_entities"]["media"]) { let single, multiple = [], media = req_status["extended_entities"]["media"]; media = media.filter((i) => { if (i["type"] === "video" || i["type"] === "animated_gif") return true })