8k and quality picker revamp
This commit is contained in:
parent
e24a3d84d6
commit
378fecd849
14 changed files with 64 additions and 49 deletions
|
@ -17,7 +17,7 @@ It preserves original media quality so you get best downloads possible (unless y
|
||||||
| -------- | :---: | :---: | :----- |
|
| -------- | :---: | :---: | :----- |
|
||||||
| Twitter | ✅ | ✅ | Ability to save multiple videos/GIFs from a single tweet. |
|
| Twitter | ✅ | ✅ | Ability to save multiple videos/GIFs from a single tweet. |
|
||||||
| Twitter Spaces | ❌️ | ✅ | Audio metadata. |
|
| Twitter Spaces | ❌️ | ✅ | Audio metadata. |
|
||||||
| YouTube & Shorts | ✅ | ✅ | Support for 4K, HDR and high FPS videos. |
|
| YouTube & Shorts | ✅ | ✅ | Support for 8K, 4K, HDR, and high FPS videos. |
|
||||||
| YouTube Music | ❌ | ✅ | Audio metadata. |
|
| YouTube Music | ❌ | ✅ | Audio metadata. |
|
||||||
| Reddit | ✅ | ✅ | |
|
| Reddit | ✅ | ✅ | |
|
||||||
| TikTok & douyin | ✅ | ✅ | Video downloads with or without watermark; image slideshow downloads without watermarks. |
|
| TikTok & douyin | ✅ | ✅ | Video downloads with or without watermark; image slideshow downloads without watermarks. |
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "cobalt",
|
"name": "cobalt",
|
||||||
"description": "save what you love",
|
"description": "save what you love",
|
||||||
"version": "4.1.1",
|
"version": "4.2",
|
||||||
"author": "wukko",
|
"author": "wukko",
|
||||||
"exports": "./src/cobalt.js",
|
"exports": "./src/cobalt.js",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|
|
@ -64,9 +64,9 @@ if (fs.existsSync('./.env') && process.env.selfURL && process.env.streamSalt &&
|
||||||
if (req.query.url && req.query.url.length < 150) {
|
if (req.query.url && req.query.url.length < 150) {
|
||||||
let j = await getJSON(req.query.url.trim(), languageCode(req), {
|
let j = await getJSON(req.query.url.trim(), languageCode(req), {
|
||||||
ip: req.header('x-forwarded-for') ? req.header('x-forwarded-for') : req.ip,
|
ip: req.header('x-forwarded-for') ? req.header('x-forwarded-for') : req.ip,
|
||||||
format: req.query.format ? req.query.format.slice(0, 5) : "webm",
|
format: req.query.format ? req.query.format.slice(0, 5) : "mp4",
|
||||||
quality: req.query.quality ? req.query.quality.slice(0, 3) : "max",
|
quality: req.query.quality ? req.query.quality.slice(0, 3) : "mid",
|
||||||
audioFormat: req.query.audioFormat ? req.query.audioFormat.slice(0, 4) : false,
|
audioFormat: req.query.audioFormat ? req.query.audioFormat.slice(0, 4) : "mp3",
|
||||||
isAudioOnly: !!req.query.audio,
|
isAudioOnly: !!req.query.audio,
|
||||||
noWatermark: !!req.query.nw,
|
noWatermark: !!req.query.nw,
|
||||||
fullAudio: !!req.query.ttfull,
|
fullAudio: !!req.query.ttfull,
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"quality": {
|
"quality": {
|
||||||
"hig": "1080",
|
"hig": "1440",
|
||||||
"mid": "720",
|
"mid": "720",
|
||||||
"low": "480"
|
"low": "480"
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,18 +1,19 @@
|
||||||
let isIOS = navigator.userAgent.toLowerCase().match("iphone os");
|
let ua = navigator.userAgent.toLowerCase();
|
||||||
|
let isIOS = ua.match("iphone os");
|
||||||
|
let isMobile = ua.match("android") || ua.match("iphone os");
|
||||||
let version = 14;
|
let version = 14;
|
||||||
let regex = new RegExp(/https:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()!@:%_\+.~#?&\/\/=]*)/);
|
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 = `<div class="notification-dot"></div>`
|
let notification = `<div class="notification-dot"></div>`
|
||||||
|
|
||||||
let switchers = {
|
let switchers = {
|
||||||
"theme": ["auto", "light", "dark"],
|
"theme": ["auto", "light", "dark"],
|
||||||
"ytFormat": ["webm", "mp4"],
|
"vFormat": ["mp4", "webm"],
|
||||||
"quality": ["max", "hig", "mid", "low"],
|
"vQuality": ["hig", "max", "mid", "low"],
|
||||||
"defaultAudioFormat": ["mp3", "best", "ogg", "wav", "opus"]
|
"aFormat": ["mp3", "best", "ogg", "wav", "opus"]
|
||||||
}
|
}
|
||||||
let checkboxes = ["disableTikTokWatermark", "fullTikTokAudio"];
|
let checkboxes = ["disableTikTokWatermark", "fullTikTokAudio"];
|
||||||
let exceptions = { // used solely for ios devices
|
let exceptions = { // used for mobile devices
|
||||||
"ytFormat": "mp4",
|
"vQuality": "mid"
|
||||||
"defaultAudioFormat": "mp3"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function eid(id) {
|
function eid(id) {
|
||||||
|
@ -208,6 +209,9 @@ function popup(type, action, text) {
|
||||||
eid("popup-backdrop").style.visibility = vis(action);
|
eid("popup-backdrop").style.visibility = vis(action);
|
||||||
eid(`popup-${type}`).style.visibility = vis(action);
|
eid(`popup-${type}`).style.visibility = vis(action);
|
||||||
}
|
}
|
||||||
|
function updateMP4Text() {
|
||||||
|
eid("vFormat-mp4").innerHTML = sGet("vQuality") === "mid" ? "mp4 (h264/av1)" : "mp4 (av1)";
|
||||||
|
}
|
||||||
function changeSwitcher(li, b) {
|
function changeSwitcher(li, b) {
|
||||||
if (b) {
|
if (b) {
|
||||||
sSet(li, b);
|
sSet(li, b);
|
||||||
|
@ -215,9 +219,10 @@ function changeSwitcher(li, b) {
|
||||||
(switchers[li][i] === b) ? enable(`${li}-${b}`) : disable(`${li}-${switchers[li][i]}`)
|
(switchers[li][i] === b) ? enable(`${li}-${b}`) : disable(`${li}-${switchers[li][i]}`)
|
||||||
}
|
}
|
||||||
if (li === "theme") detectColorScheme();
|
if (li === "theme") detectColorScheme();
|
||||||
|
if (li === "vQuality") updateMP4Text();
|
||||||
} else {
|
} else {
|
||||||
let pref = switchers[li][0];
|
let pref = switchers[li][0];
|
||||||
if (isIOS && exceptions[li]) pref = exceptions[li];
|
if (isMobile && exceptions[li]) pref = exceptions[li];
|
||||||
sSet(li, pref);
|
sSet(li, pref);
|
||||||
for (let i in switchers[li]) {
|
for (let i in switchers[li]) {
|
||||||
(switchers[li][i] === pref) ? enable(`${li}-${pref}`) : disable(`${li}-${switchers[li][i]}`)
|
(switchers[li][i] === pref) ? enable(`${li}-${pref}`) : disable(`${li}-${switchers[li][i]}`)
|
||||||
|
@ -299,6 +304,10 @@ function changeButton(type, text) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
function resetSettings() {
|
||||||
|
localStorage.clear();
|
||||||
|
window.location.reload();
|
||||||
|
}
|
||||||
async function pasteClipboard() {
|
async function pasteClipboard() {
|
||||||
let t = await navigator.clipboard.readText();
|
let t = await navigator.clipboard.readText();
|
||||||
if (regex.test(t)) {
|
if (regex.test(t)) {
|
||||||
|
@ -314,7 +323,7 @@ async function download(url) {
|
||||||
let format = ``;
|
let format = ``;
|
||||||
if (audioMode === "false") {
|
if (audioMode === "false") {
|
||||||
if (url.includes("youtube.com/") || url.includes("/youtu.be/")) {
|
if (url.includes("youtube.com/") || url.includes("/youtu.be/")) {
|
||||||
format = `&format=${sGet("ytFormat")}`
|
format = `&format=${sGet("vFormat")}`
|
||||||
} else if ((url.includes("tiktok.com/") || url.includes("douyin.com/")) && sGet("disableTikTokWatermark") === "true") {
|
} else if ((url.includes("tiktok.com/") || url.includes("douyin.com/")) && sGet("disableTikTokWatermark") === "true") {
|
||||||
format = `&nw=true`
|
format = `&nw=true`
|
||||||
}
|
}
|
||||||
|
@ -322,8 +331,8 @@ async function download(url) {
|
||||||
format = `&nw=true`
|
format = `&nw=true`
|
||||||
if (sGet("fullTikTokAudio") === "true") format += `&ttfull=true`
|
if (sGet("fullTikTokAudio") === "true") format += `&ttfull=true`
|
||||||
}
|
}
|
||||||
let mode = (sGet("audioMode") === "true") ? `audio=true` : `quality=${sGet("quality")}`
|
let mode = (sGet("audioMode") === "true") ? `audio=true` : `quality=${sGet("vQuality")}`
|
||||||
await fetch(`/api/json?audioFormat=${sGet("defaultAudioFormat")}&${mode}${format}&url=${encodeURIComponent(url)}`).then(async (r) => {
|
await fetch(`/api/json?audioFormat=${sGet("aFormat")}&${mode}${format}&url=${encodeURIComponent(url)}`).then(async (r) => {
|
||||||
let j = await r.json();
|
let j = await r.json();
|
||||||
if (j.status !== "error" && j.status !== "rate-limit") {
|
if (j.status !== "error" && j.status !== "rate-limit") {
|
||||||
if (j.url) {
|
if (j.url) {
|
||||||
|
|
|
@ -53,8 +53,8 @@
|
||||||
"AccessibilityKeepDownloadButton": "keep the download button always visible",
|
"AccessibilityKeepDownloadButton": "keep the download button always visible",
|
||||||
"SettingsEnableDownloadPopup": "ask for a way to save",
|
"SettingsEnableDownloadPopup": "ask for a way to save",
|
||||||
"AccessibilityEnableDownloadPopup": "ask what to do with downloads",
|
"AccessibilityEnableDownloadPopup": "ask what to do with downloads",
|
||||||
"SettingsFormatDescription": "select webm if you want max quality available. webm videos are usually higher quality but ios devices can't play them natively.",
|
"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 resolution isn't available, closest one gets picked instead. if you want to post a youtube video on twitter, then select a combination of mp4 and 720p. twitter likes videos like that way more.",
|
"SettingsQualityDescription": "if selected quality isn't available, closest one gets picked instead.\nif you want to post a youtube video on social media, then select a combination of mp4 and 720p. those videos are usually not in av1 codec, so they should play just fine basically everywhere.",
|
||||||
"DonateSubtitle": "help me pay for hosting",
|
"DonateSubtitle": "help me pay for hosting",
|
||||||
"DonateDescription": "i don't really like crypto in its current state, but it's the only reliable way for me to receive money and pay for anything abroad.",
|
"DonateDescription": "i don't really like crypto in its current state, but it's the only reliable way for me to receive money and pay for anything abroad.",
|
||||||
"LinkGitHubIssues": ">> report issues and check out the source code on github",
|
"LinkGitHubIssues": ">> report issues and check out the source code on github",
|
||||||
|
|
|
@ -53,8 +53,8 @@
|
||||||
"AccessibilityKeepDownloadButton": "оставлять кнопку скачивания на экране",
|
"AccessibilityKeepDownloadButton": "оставлять кнопку скачивания на экране",
|
||||||
"SettingsEnableDownloadPopup": "спрашивать, что делать при скачивании",
|
"SettingsEnableDownloadPopup": "спрашивать, что делать при скачивании",
|
||||||
"AccessibilityEnableDownloadPopup": "спрашивать, что делать с загрузками",
|
"AccessibilityEnableDownloadPopup": "спрашивать, что делать с загрузками",
|
||||||
"SettingsFormatDescription": "выбирай webm, если хочешь максимальное качество. webm обычно лучше по качеству, но устройства на ios не могут проигрывать их без сторонних приложений.",
|
"SettingsFormatDescription": "выбирай webm, если хочешь максимальное качество. у webm видео битрейт обычно выше, но устройства на ios не могут проигрывать их без сторонних приложений.",
|
||||||
"SettingsQualityDescription": "если выбранное разрешение недоступно, то выбирается ближайшее к нему. если ты хочешь твитнуть загруженное видео, то выбирай комбинацию из mp4 и 720p. твиттер такие видео обычно воспринимает намного лучше.",
|
"SettingsQualityDescription": "если выбранное качество недоступно, то выбирается ближайшее к нему.\nесли ты хочешь опубликовать видео с youtube где-то в соц. сетях, то выбирай комбинацию из mp4 и 720p. у таких видео кодек обычно не av1, поэтому они должны работать практически везде.",
|
||||||
"DonateSubtitle": "помоги мне платить за хостинг",
|
"DonateSubtitle": "помоги мне платить за хостинг",
|
||||||
"DonateDescription": "я не люблю крипто в его текущем состоянии, но у меня нет другого надёжного способа оплаты хостинга.",
|
"DonateDescription": "я не люблю крипто в его текущем состоянии, но у меня нет другого надёжного способа оплаты хостинга.",
|
||||||
"LinkGitHubIssues": ">> сообщай о проблемах и смотри исходный код на гитхабе",
|
"LinkGitHubIssues": ">> сообщай о проблемах и смотри исходный код на гитхабе",
|
||||||
|
|
|
@ -1,10 +1,14 @@
|
||||||
{
|
{
|
||||||
"current": {
|
"current": {
|
||||||
|
"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."
|
||||||
|
},
|
||||||
|
"history": [{
|
||||||
"version": "4.1",
|
"version": "4.1",
|
||||||
"title": "better tiktok image downloads",
|
"title": "better tiktok image downloads",
|
||||||
"content": "here's what's up:\n- tiktok images are saved as .jpeg instead of .webp (finally, i know).\n- added support for image downloads from douyin.\n- fixed tiktok audio downloads from the image picker.\n- emoji in about button now changes on special occasions. be it halloween or christmas, {appName} will change just a tiny bit to fit in :D\n\nif you're not caught up with new stuff in {appName} 4.x yet, check out the previous changelog down below. there's a ton of stuff to like."
|
"content": "here's what's up:\n- tiktok images are saved as .jpeg instead of .webp (finally, i know).\n- added support for image downloads from douyin.\n- fixed tiktok audio downloads from the image picker.\n- emoji in about button now changes on special occasions. be it halloween or christmas, {appName} will change just a tiny bit to fit in :D\n\nif you're not caught up with new stuff in {appName} 4.x yet, check out the previous changelog down below. there's a ton of stuff to like."
|
||||||
},
|
}, {
|
||||||
"history": [{
|
|
||||||
"version": "4.0",
|
"version": "4.0",
|
||||||
"title": "better and faster than ever",
|
"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, <a class=\"text-backdrop\" href=\"https://github.com/wukko/cobalt\" target=\"_blank\">you can do it on github</a>.\n\nfun fact: average {appName} user is 10 times cooler than a regular person."
|
"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, <a class=\"text-backdrop\" href=\"https://github.com/wukko/cobalt\" target=\"_blank\">you can do it on github</a>.\n\nfun fact: average {appName} user is 10 times cooler than a regular person."
|
||||||
|
|
|
@ -172,12 +172,12 @@ export default function(obj) {
|
||||||
name: "downloads",
|
name: "downloads",
|
||||||
title: loc(obj.lang, 'SettingsDownloadsSubtitle'),
|
title: loc(obj.lang, 'SettingsDownloadsSubtitle'),
|
||||||
body: switcher({
|
body: switcher({
|
||||||
name: "quality",
|
name: "vQuality",
|
||||||
subtitle: loc(obj.lang, 'SettingsQualitySubtitle'),
|
subtitle: loc(obj.lang, 'SettingsQualitySubtitle'),
|
||||||
explanation: loc(obj.lang, 'SettingsQualityDescription'),
|
explanation: loc(obj.lang, 'SettingsQualityDescription'),
|
||||||
items: [{
|
items: [{
|
||||||
"action": "max",
|
"action": "max",
|
||||||
"text": loc(obj.lang, 'SettingsQualitySwitchMax')
|
"text": `${loc(obj.lang, 'SettingsQualitySwitchMax')}<br/>(2160p+)`
|
||||||
}, {
|
}, {
|
||||||
"action": "hig",
|
"action": "hig",
|
||||||
"text": `${loc(obj.lang, 'SettingsQualitySwitchHigh')}<br/>(${quality.hig}p)`
|
"text": `${loc(obj.lang, 'SettingsQualitySwitchHigh')}<br/>(${quality.hig}p)`
|
||||||
|
@ -193,13 +193,15 @@ export default function(obj) {
|
||||||
+ settingsCategory({
|
+ settingsCategory({
|
||||||
name: "youtube",
|
name: "youtube",
|
||||||
body: switcher({
|
body: switcher({
|
||||||
name: "ytFormat",
|
name: "vFormat",
|
||||||
subtitle: loc(obj.lang, 'SettingsFormatSubtitle'),
|
subtitle: loc(obj.lang, 'SettingsFormatSubtitle'),
|
||||||
explanation: loc(obj.lang, 'SettingsFormatDescription'),
|
explanation: loc(obj.lang, 'SettingsFormatDescription'),
|
||||||
items: [{
|
items: [{
|
||||||
"action": "mp4"
|
"action": "mp4",
|
||||||
|
"text": "mp4 (av1)"
|
||||||
}, {
|
}, {
|
||||||
"action": "webm"
|
"action": "webm",
|
||||||
|
"text": "webm (vp9)"
|
||||||
}]
|
}]
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -215,7 +217,7 @@ export default function(obj) {
|
||||||
name: "general",
|
name: "general",
|
||||||
title: loc(obj.lang, 'SettingsAudioTab'),
|
title: loc(obj.lang, 'SettingsAudioTab'),
|
||||||
body: switcher({
|
body: switcher({
|
||||||
name: "defaultAudioFormat",
|
name: "aFormat",
|
||||||
subtitle: loc(obj.lang, 'SettingsFormatSubtitle'),
|
subtitle: loc(obj.lang, 'SettingsFormatSubtitle'),
|
||||||
explanation: loc(obj.lang, 'SettingsAudioFormatDescription'),
|
explanation: loc(obj.lang, 'SettingsAudioFormatDescription'),
|
||||||
items: audioFormats
|
items: audioFormats
|
||||||
|
|
|
@ -15,7 +15,7 @@ export default async function(obj) {
|
||||||
let streamData = JSON.parse(html.split('<script>window.__playinfo__=')[1].split('</script>')[0]);
|
let streamData = JSON.parse(html.split('<script>window.__playinfo__=')[1].split('</script>')[0]);
|
||||||
if (streamData.data.timelength <= maxVideoDuration) {
|
if (streamData.data.timelength <= maxVideoDuration) {
|
||||||
let video = streamData["data"]["dash"]["video"].filter((v) => {
|
let video = streamData["data"]["dash"]["video"].filter((v) => {
|
||||||
if (!v["baseUrl"].includes("https://upos-sz-mirrorcosov.bilivideo.com/") && v["height"] !== 4320) return true;
|
if (!v["baseUrl"].includes("https://upos-sz-mirrorcosov.bilivideo.com/")) return true;
|
||||||
}).sort((a, b) => Number(b.bandwidth) - Number(a.bandwidth));
|
}).sort((a, b) => Number(b.bandwidth) - Number(a.bandwidth));
|
||||||
let audio = streamData["data"]["dash"]["audio"].filter((a) => {
|
let audio = streamData["data"]["dash"]["audio"].filter((a) => {
|
||||||
if (!a["baseUrl"].includes("https://upos-sz-mirrorcosov.bilivideo.com/")) return true;
|
if (!a["baseUrl"].includes("https://upos-sz-mirrorcosov.bilivideo.com/")) return true;
|
||||||
|
|
|
@ -15,7 +15,7 @@ export default async function(obj) {
|
||||||
let all = api["request"]["files"]["progressive"].sort((a, b) => Number(b.width) - Number(a.width));
|
let all = api["request"]["files"]["progressive"].sort((a, b) => Number(b.width) - Number(a.width));
|
||||||
let best = all[0]
|
let best = all[0]
|
||||||
try {
|
try {
|
||||||
if (obj.quality !== "max") {
|
if (obj.quality != "max") {
|
||||||
let pref = parseInt(quality[obj.quality], 10)
|
let pref = parseInt(quality[obj.quality], 10)
|
||||||
for (let i in all) {
|
for (let i in all) {
|
||||||
let currQuality = parseInt(all[i]["quality"].replace('p', ''), 10)
|
let currQuality = parseInt(all[i]["quality"].replace('p', ''), 10)
|
||||||
|
|
|
@ -10,32 +10,32 @@ export default async function(obj) {
|
||||||
let info = infoInitial.formats;
|
let info = infoInitial.formats;
|
||||||
if (!info[0]["isLive"]) {
|
if (!info[0]["isLive"]) {
|
||||||
let videoMatch = [], fullVideoMatch = [], video = [], audio = info.filter((a) => {
|
let videoMatch = [], fullVideoMatch = [], video = [], audio = info.filter((a) => {
|
||||||
if (!a["isHLS"] && !a["isDashMPD"] && a["hasAudio"] && !a["hasVideo"] && a["container"] === obj.format) return true;
|
if (!a["isHLS"] && !a["isDashMPD"] && a["hasAudio"] && !a["hasVideo"] && a["container"] == obj.format) return true;
|
||||||
}).sort((a, b) => Number(b.bitrate) - Number(a.bitrate));
|
}).sort((a, b) => Number(b.bitrate) - Number(a.bitrate));
|
||||||
if (!obj.isAudioOnly) {
|
if (!obj.isAudioOnly) {
|
||||||
video = info.filter((a) => {
|
video = info.filter((a) => {
|
||||||
if (!a["isHLS"] && !a["isDashMPD"] && a["hasVideo"] && a["container"] === obj.format && a["height"] !== 4320) {
|
if (!a["isHLS"] && !a["isDashMPD"] && a["hasVideo"] && a["container"] == obj.format) {
|
||||||
if (obj.quality !== "max") {
|
if (obj.quality != "max") {
|
||||||
if (a["hasAudio"] && mq[obj.quality] === a["height"]) {
|
if (a["hasAudio"] && mq[obj.quality] == a["height"]) {
|
||||||
fullVideoMatch.push(a)
|
fullVideoMatch.push(a)
|
||||||
} else if (!a["hasAudio"] && mq[obj.quality] === a["height"]) {
|
} else if (!a["hasAudio"] && mq[obj.quality] == a["height"]) {
|
||||||
videoMatch.push(a);
|
videoMatch.push(a);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}).sort((a, b) => Number(b.bitrate) - Number(a.bitrate));
|
}).sort((a, b) => Number(b.bitrate) - Number(a.bitrate));
|
||||||
if (obj.quality !== "max") {
|
if (obj.quality != "max") {
|
||||||
if (videoMatch.length === 0) {
|
if (videoMatch.length == 0) {
|
||||||
let ss = selectQuality("youtube", obj.quality, video[0]["qualityLabel"].slice(0, 5).replace('p', '').trim())
|
let ss = selectQuality("youtube", obj.quality, video[0]["qualityLabel"].slice(0, 5).replace('p', '').trim())
|
||||||
videoMatch = video.filter((a) => {
|
videoMatch = video.filter((a) => {
|
||||||
if (a["qualityLabel"].slice(0, 5).replace('p', '').trim() === ss) return true;
|
if (a["qualityLabel"].slice(0, 5).replace('p', '').trim() == ss) return true;
|
||||||
})
|
})
|
||||||
} else if (fullVideoMatch.length > 0) {
|
} else if (fullVideoMatch.length > 0) {
|
||||||
videoMatch = [fullVideoMatch[0]]
|
videoMatch = [fullVideoMatch[0]]
|
||||||
}
|
}
|
||||||
} else videoMatch = [video[0]];
|
} else videoMatch = [video[0]];
|
||||||
if (obj.quality === "los") videoMatch = [video[video.length - 1]];
|
if (obj.quality == "los") videoMatch = [video[video.length - 1]];
|
||||||
}
|
}
|
||||||
let generalMeta = {
|
let generalMeta = {
|
||||||
title: infoInitial.videoDetails.title,
|
title: infoInitial.videoDetails.title,
|
||||||
|
|
|
@ -16,20 +16,20 @@ let final = () => {
|
||||||
for (let i in ob) {
|
for (let i in ob) {
|
||||||
appendFileSync(envPath, `${i}=${ob[i]}\n`)
|
appendFileSync(envPath, `${i}=${ob[i]}\n`)
|
||||||
}
|
}
|
||||||
console.log(Bright("\nI've created a .env file with selfURL, port, and stream salt."))
|
console.log(Bright("\nAwesome! I've created a fresh .env file for you."))
|
||||||
console.log(`${Bright("Now I'll run")} ${Cyan("npm install")} ${Bright("to install all dependencies. It shouldn't take long.\n\n")}`)
|
console.log(`${Bright("Now I'll run")} ${Cyan("npm install")} ${Bright("to install all dependencies. It shouldn't take long.\n\n")}`)
|
||||||
execSync('npm install', { stdio: [0, 1, 2] });
|
execSync('npm install', { stdio: [0, 1, 2] });
|
||||||
console.log(`\n\n${Green("All done!\n")}`)
|
console.log(`\n\n${Cyan("All done!\n")}`)
|
||||||
console.log("You can re-run this script any time to update the configuration.")
|
console.log(Bright("You can re-run this script at any time to update the configuration."))
|
||||||
console.log("\nYou're now ready to start the main project.\nHave fun!")
|
console.log(Bright("\nYou're now ready to start cobalt. Simply run ") + Cyan("npm start") + Bright('!\nHave fun :)'))
|
||||||
rl.close()
|
rl.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(
|
console.log(
|
||||||
`${Cyan("Welcome to cobalt!")}\n${Bright("We'll get you up and running in no time.\nLet's start by creating a ")}${Cyan(".env")}${Bright(" file. You can always change it later.")}`
|
`${Cyan("Welcome to cobalt!")}\n${Bright("Let's start by creating a new ")}${Cyan(".env")}${Bright(" file. You can always change it later.")}`
|
||||||
)
|
)
|
||||||
console.log(
|
console.log(
|
||||||
Bright("\nWhat's the selfURL we'll be running on? (localhost)")
|
Bright("\nWhat's the domain this instance will be running on? (localhost)\nExample: co.wukko.me")
|
||||||
)
|
)
|
||||||
|
|
||||||
rl.question(q, r1 => {
|
rl.question(q, r1 => {
|
||||||
|
@ -38,7 +38,7 @@ rl.question(q, r1 => {
|
||||||
} else {
|
} else {
|
||||||
ob['selfURL'] = `http://localhost`
|
ob['selfURL'] = `http://localhost`
|
||||||
}
|
}
|
||||||
console.log(Bright("\nGreat! Now, what's the port we'll be running on? (9000)"))
|
console.log(Bright("\nGreat! Now, what's the port it'll be running on? (9000)"))
|
||||||
rl.question(q, r2 => {
|
rl.question(q, r2 => {
|
||||||
if (!r1 && !r2) {
|
if (!r1 && !r2) {
|
||||||
ob['selfURL'] = `http://localhost:9000/`
|
ob['selfURL'] = `http://localhost:9000/`
|
||||||
|
|
|
@ -7,12 +7,12 @@ function closest(goal, array) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function(service, quality, maxQuality) {
|
export default function(service, quality, maxQuality) {
|
||||||
if (quality === "max") return maxQuality;
|
if (quality == "max") return maxQuality;
|
||||||
|
|
||||||
quality = parseInt(mq[quality], 10)
|
quality = parseInt(mq[quality], 10)
|
||||||
maxQuality = parseInt(maxQuality, 10)
|
maxQuality = parseInt(maxQuality, 10)
|
||||||
|
|
||||||
if (quality >= maxQuality || quality === maxQuality) return maxQuality;
|
if (quality >= maxQuality || quality == maxQuality) return maxQuality;
|
||||||
|
|
||||||
if (quality < maxQuality) {
|
if (quality < maxQuality) {
|
||||||
if (services[service]["quality"][quality]) {
|
if (services[service]["quality"][quality]) {
|
||||||
|
|
Loading…
Reference in a new issue