From 2fae43d8903aa04ed1314200f87b1d0c9bfc96d7 Mon Sep 17 00:00:00 2001 From: wukko Date: Sat, 6 Aug 2022 21:21:48 +0600 Subject: [PATCH] fixes - fixed neighbor quality picking for youtube videos - webm is now default for youtube downloads for all platforms except for ios - even more readme changes - a tiny bit of clean up - preparing stuff for next major update --- README.md | 14 ++++++++------ package.json | 4 ++-- src/config.json | 4 +++- src/front/cobalt.js | 11 ++++++++--- src/modules/match.js | 2 +- src/modules/services/twitter.js | 6 +----- src/modules/services/youtube.js | 4 ++-- src/modules/stream/types.js | 12 +++++++----- 8 files changed, 32 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index 7b59578..fc236e0 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,14 @@ # cobalt -Sleek and easy to use social media downloader built with JavaScript. +Best way to save content you love. -Try it now: [co.wukko.me](https://co.wukko.me/) +[co.wukko.me](https://co.wukko.me/) ![cobalt logo](https://raw.githubusercontent.com/wukko/cobalt/current/src/front/icons/wide.png "cobalt logo") ## What's cobalt? -cobalt aims to be the ultimate social media downloader, that is efficient, pretty, and doesn't bother you with ads or privacy invasion agreement popups. It also doesn't remux anything, so you get media in best quality possible (unless you change that in settings). +cobalt is social media downloader with zero bullshit. It's efficient, easy to use, and doesn't bother you with ads or privacy invasion "consent" popups. + +It preserves original media quality so you get best downloads possible (unless you change that in settings). ## Supported services @@ -17,8 +19,7 @@ cobalt aims to be the ultimate social media downloader, that is efficient, prett - TikTok - Tumblr - Twitter -- YouTube -- YouTube Music +- YouTube (with HDR support) - VK ### Audio @@ -51,8 +52,9 @@ Take English or Russian localization from [this directory](https://github.com/wu - [ ] niconico support - [ ] Instagram support - [ ] SoundCloud support -- [ ] Add an option to save Twitter GIFs as `.gif` instead of `.mp4` - [ ] Quality switching for bilibili +- [ ] Find a way to get TikTok videos without a watermark +- [ ] Add an option to keep watermark on TikTok videos ### Other - [ ] Language picker in settings diff --git a/package.json b/package.json index e5d1d03..e202ee4 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "cobalt", - "description": "probably the friendliest social media downloader yet", - "version": "2.2.8", + "description": "save what you love", + "version": "2.2.9", "author": "wukko", "exports": "./src/cobalt.js", "type": "module", diff --git a/src/config.json b/src/config.json index c6cab14..88bbdf7 100644 --- a/src/config.json +++ b/src/config.json @@ -26,6 +26,8 @@ }, "ffmpegArgs": { "webm": ["-c:v", "copy", "-c:a", "copy"], - "mp4": ["-c:v", "copy", "-c:a", "copy", "-movflags", "frag_keyframe+empty_moov"] + "mp4": ["-c:v", "copy", "-c:a", "copy", "-movflags", "frag_keyframe+empty_moov"], + "bst": ["-c:a", "copy"], + "mp3": ["-ar", "48000", "-ac", "2", "-b:a", "320k"] } } diff --git a/src/front/cobalt.js b/src/front/cobalt.js index edf165c..f6dff56 100644 --- a/src/front/cobalt.js +++ b/src/front/cobalt.js @@ -1,9 +1,12 @@ let isIOS = navigator.userAgent.toLowerCase().match("iphone os"); let switchers = { "theme": ["auto", "light", "dark"], - "youtubeFormat": ["mp4", "webm", "audio"], + "youtubeFormat": ["webm", "mp4", "audio"], "quality": ["max", "hig", "mid", "low"] } +let exceptions = { + "youtubeFormat": "mp4" +} function eid(id) { return document.getElementById(id) @@ -98,9 +101,11 @@ function changeSwitcher(li, b, u) { } if (li == "theme") detectColorScheme(); } else { - localStorage.setItem(li, switchers[li][0]); + let pref = switchers[li][0]; + if (isIOS && exceptions[li]) pref = exceptions[li]; + localStorage.setItem(li, pref); for (i in switchers[li]) { - (switchers[li][i] == switchers[li][0]) ? enable(`${li}-${switchers[li][0]}`) : disable(`${li}-${switchers[li][i]}`) + (switchers[li][i] == pref) ? enable(`${li}-${pref}`) : disable(`${li}-${switchers[li][i]}`) } } } diff --git a/src/modules/match.js b/src/modules/match.js index e183621..16665ea 100644 --- a/src/modules/match.js +++ b/src/modules/match.js @@ -24,7 +24,7 @@ export default async function (host, patternMatch, url, ip, lang, format, qualit id: patternMatch["id"], lang: lang }); - return (!r.error) ? apiJSON(1, { u: r.split('?')[0] }) : apiJSON(0, { t: r.error }); + return (!r.error) ? apiJSON(1, { u: r }) : apiJSON(0, { t: r.error }); case "vk": r = await vk({ diff --git a/src/modules/services/twitter.js b/src/modules/services/twitter.js index 23b6d51..6637993 100644 --- a/src/modules/services/twitter.js +++ b/src/modules/services/twitter.js @@ -39,11 +39,7 @@ export default async function (obj) { if (parsbod.hasOwnProperty("extended_entities") && parsbod["extended_entities"].hasOwnProperty("media")) { if (parsbod["extended_entities"]["media"][0]["type"] === "video" || parsbod["extended_entities"]["media"][0]["type"] === "animated_gif") { let variants = parsbod["extended_entities"]["media"][0]["video_info"]["variants"] - return variants.filter((v) => { - if (v["content_type"] == "video/mp4") { - return true - } - }).sort((a, b) => Number(b.bitrate) - Number(a.bitrate))[0]["url"] + return variants.filter((v) => { if (v["content_type"] == "video/mp4") return true; }).sort((a, b) => Number(b.bitrate) - Number(a.bitrate))[0]["url"].split('?')[0]; } else { return nothing } diff --git a/src/modules/services/youtube.js b/src/modules/services/youtube.js index 07edd41..3cca5a6 100644 --- a/src/modules/services/youtube.js +++ b/src/modules/services/youtube.js @@ -27,9 +27,9 @@ export default async function (obj) { }).sort((a, b) => Number(b.bitrate) - Number(a.bitrate)); if (obj.quality != "max") { if (videoMatch.length == 0) { - let ss = selectQuality("youtube", obj.quality, video[0]["height"]) + let ss = selectQuality("youtube", obj.quality, video[0]["qualityLabel"].slice(0, 5).replace('p', '').trim()) videoMatch = video.filter((a) => { - if (a["height"] == ss) return true; + if (a["qualityLabel"].slice(0, 5).replace('p', '').trim() == ss) return true; }) } else if (fullVideoMatch.length > 0) { videoMatch = [fullVideoMatch[0]] diff --git a/src/modules/stream/types.js b/src/modules/stream/types.js index 976e7e7..8ac96c7 100644 --- a/src/modules/stream/types.js +++ b/src/modules/stream/types.js @@ -82,14 +82,16 @@ export async function streamAudioOnly(streamInfo, res) { headers = { "user-agent": genericUserAgent }; } const audio = got.get(streamInfo.urls, { isStream: true, headers: headers }); - const ffmpegProcess = spawn(ffmpeg, [ + let format = streamInfo.filename.split('.')[streamInfo.filename.split('.').length - 1], args = [ '-loglevel', '-8', '-i', 'pipe:3', '-vn', - '-c:a', 'copy', - '-f', `${streamInfo.filename.split('.')[streamInfo.filename.split('.').length - 1]}`, - 'pipe:4', - ], { + ]; + args = args.concat(ffmpegArgs[format]) + if (streamInfo.time) args.push('-t', msToTime(streamInfo.time)); + args.push('-f', format, 'pipe:4'); + + const ffmpegProcess = spawn(ffmpeg, args, { windowsHide: true, stdio: [ 'inherit', 'inherit', 'inherit',