moved to new repo

This commit is contained in:
wukko
2022-07-09 00:17:56 +06:00
committed by GitHub
parent 1decab4daf
commit 94acf10e9e
62 changed files with 2187 additions and 4 deletions

72
modules/services/all.json Normal file
View File

@@ -0,0 +1,72 @@
{
"bilibili": {
"alias": "bilibili.com",
"patterns": ["video/:id"],
"quality_match": ["2160", "1440", "1080", "720", "480", "360", "240", "144"],
"enabled": true
},
"reddit": {
"patterns": ["r/:sub/comments/:id/:title"],
"enabled": true
},
"twitter": {
"patterns": [":user/status/:id"],
"quality_match": ["1080", "720", "480", "360", "240", "144"],
"enabled": true,
"api": "api.twitter.com",
"token": "AAAAAAAAAAAAAAAAAAAAAIK1zgAAAAAA2tUWuhGZ2JceoId5GwYWU5GspY4%3DUq7gzFoCZs1QfwGoVdvSac3IniczZEYXIcDyumCauIXpcAPorE",
"apiURLs": {
"activate": "1.1/guest/activate.json",
"status_show": "1.1/statuses/show.json"
}
},
"vk": {
"patterns": ["video-:userId_:videoId"],
"quality_match": {
"2160": 7,
"1440": 6,
"1080": 5,
"720": 3,
"480": 2,
"360": 1,
"240": 0,
"144": 4
},
"quality": {
"1080": "hig",
"720": "mid",
"480": "low"
},
"enabled": true
},
"youtube": {
"patterns": ["watch?v=:id"],
"quality_match": ["2160", "1440", "1080", "720", "480", "360", "240", "144"],
"quality": {
"1080": "hig",
"720": "mid",
"480": "low"
},
"enabled": true
},
"youtube music": {
"patterns": ["watch?v=:id"],
"enabled": true
},
"tumblr": {
"patterns": ["post/:id"],
"enabled": false
},
"facebook": {
"patterns": [":pageid/:type/:postid"],
"enabled": false
},
"instagram": {
"patterns": [":type/:id"],
"enabled": false
},
"tiktok": {
"patterns": [":pageid/:type/:postid", ":id"],
"enabled": false
}
}

View File

@@ -0,0 +1,38 @@
import got from "got";
import loc from "../sub/loc.js";
import { genericUserAgent, maxVideoDuration } from "../config.js";
export default async function(obj) {
try {
let html = await got.get(`https://bilibili.com/video/${obj.id}`, {
headers: { "user-agent": genericUserAgent }
});
html.on('error', (err) => {
return { error: loc('en', 'apiError', 'youtubeFetch') };
});
html = html.body;
if (html.includes('<script>window.__playinfo__=') && html.includes('"video_codecid"')) {
let streamData = JSON.parse(html.split('<script>window.__playinfo__=')[1].split('</script>')[0]);
if (streamData.data.timelength <= maxVideoDuration) {
let video = streamData["data"]["dash"]["video"].filter((v) => {
if (!v["baseUrl"].includes("https://upos-sz-mirrorcosov.bilivideo.com/") && v["height"] != 4320) {
return true;
}
}).sort((a, b) => Number(b.bandwidth) - Number(a.bandwidth));
let audio = streamData["data"]["dash"]["audio"].filter((a) => {
if (!a["baseUrl"].includes("https://upos-sz-mirrorcosov.bilivideo.com/")) {
return true;
}
}).sort((a, b) => Number(b.bandwidth) - Number(a.bandwidth));
return { urls: [video[0]["baseUrl"], audio[0]["baseUrl"]], time: streamData.data.timelength, filename: `bilibili_${obj.id}_${video[0]["width"]}x${video[0]["height"]}.mp4` };
} else {
return { error: loc('en', 'apiError', 'youtubeLimit', maxVideoDuration / 60000) };
}
} else {
return { error: loc('en', 'apiError', 'youtubeFetch') };
}
} catch (e) {
return { error: loc('en', 'apiError', 'youtubeFetch') };
}
}

View File

@@ -0,0 +1,17 @@
import got from "got";
import loc from "../sub/loc.js";
import { genericUserAgent, maxVideoDuration } from "../config.js";
export default async function(obj) {
try {
let req = await got.get(`https://www.reddit.com/r/${obj.sub}/comments/${obj.id}/${obj.name}.json`, { headers: { "user-agent": genericUserAgent } });
let data = (JSON.parse(req.body))[0]["data"]["children"][0]["data"];
if ("reddit_video" in data["secure_media"] && data["secure_media"]["reddit_video"]["duration"] * 1000 < maxVideoDuration) {
return { urls: [data["secure_media"]["reddit_video"]["fallback_url"].split('?')[0], `${data["secure_media"]["reddit_video"]["fallback_url"].split('_')[0]}_audio.mp4`], filename: `reddit_${data["secure_media"]["reddit_video"]["fallback_url"].split('/')[3]}.mp4` };
} else {
return { error: loc('en', 'apiError', 'nothingToDownload') };
}
} catch (err) {
return { error: loc("en", "apiError", "nothingToDownload") };
}
}

View File

@@ -0,0 +1,57 @@
import got from "got";
import loc from "../sub/loc.js";
import { services } from "../config.js";
const configSt = services.twitter;
async function fetchTweetInfo(obj) {
let cantConnect = { error: loc('en', 'apiError', 'cantConnectToAPI', 'twitter') }
try {
let _headers = {
"Authorization": `Bearer ${configSt.token}`,
"Host": configSt.api,
"Content-Type": "application/json",
"Content-Length": 0
};
let req_act = await got.post(`https://${configSt.api}/${configSt.apiURLs.activate}`, {
headers: _headers
});
req_act.on('error', (err) => {
return cantConnect
})
_headers["x-guest-token"] = req_act.body["guest_token"];
let req_status = await got.get(`https://${configSt.api}/${configSt.apiURLs.status_show}?id=${obj.id}&tweet_mode=extended`, {
headers: _headers
});
req_status.on('error', (err) => {
return cantConnect
})
return JSON.parse(req_status.body);
} catch (err) {
return { error: cantConnect };
}
}
export default async function (obj) {
let nothing = { error: loc('en', 'apiError', 'nothingToDownload') }
try {
let parsbod = await fetchTweetInfo(obj);
if (!parsbod.error) {
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"]
} else {
return nothing
}
} else {
return nothing
}
} else return parsbod;
} catch (err) {
return { error: loc("en", "apiError", "youtubeBroke") };
}
}

47
modules/services/vk.js Normal file
View File

@@ -0,0 +1,47 @@
import got from "got";
import { xml2json } from "xml-js";
import loc from "../sub/loc.js";
import { genericUserAgent, maxVideoDuration, services } from "../config.js";
import selectQuality from "../stream/select-quality.js";
export default async function(obj) {
try {
let html = await got.get(`https://vk.com/video-${obj.userId}_${obj.videoId}`, { headers: { "user-agent": genericUserAgent } });
html.on('error', (err) => {
return false;
});
html = html.body;
if (html.includes(`{"lang":`)) {
let js = JSON.parse('{"lang":' + html.split(`{"lang":`)[1].split(']);')[0]);
if (js["mvData"]["is_active_live"] == '0') {
if (js["mvData"]["duration"] <= maxVideoDuration / 1000) {
let mpd = JSON.parse(xml2json(js["player"]["params"][0]["manifest"], { compact: true, spaces: 4 }));
let repr = mpd["MPD"]["Period"]["AdaptationSet"]["Representation"];
if (!mpd["MPD"]["Period"]["AdaptationSet"]["Representation"]) {
repr = mpd["MPD"]["Period"]["AdaptationSet"][0]["Representation"];
}
let attr = repr[repr.length - 1]["_attributes"];
let selectedQuality = `url${attr["height"]}`;
let maxQuality = js["player"]["params"][0][selectedQuality].split('type=')[1].slice(0, 1)
let userQuality = selectQuality('vk', obj.quality, Object.entries(services.vk.quality_match).reduce((r, [k, v]) => { r[v] = k; return r;})[maxQuality])
if (selectedQuality in js["player"]["params"][0]) {
return { url: js["player"]["params"][0][selectedQuality].replace(`type=${maxQuality}`, `type=${services.vk.quality_match[userQuality]}`), filename: `vk_${js["player"]["params"][0][selectedQuality].split("id=")[1]}_${attr['width']}x${attr['height']}.mp4` };
} else {
return { error: loc('en', 'apiError', 'nothingToDownload') };
}
} else {
return { error: loc('en', 'apiError', 'youtubeLimit', maxVideoDuration / 60000) };
}
} else {
return { error: loc('en', 'apiError', 'liveVideo') };
}
} else {
return { error: loc('en', 'apiError', 'nothingToDownload') };
}
} catch (err) {
return { error: loc('en', 'apiError', 'youtubeFetch') };
}
}

View File

@@ -0,0 +1,74 @@
import ytdl from "ytdl-core";
import loc from "../sub/loc.js";
import { maxVideoDuration, quality as mq } from "../config.js";
import selectQuality from "../stream/select-quality.js";
export default async function (obj) {
try {
let info = await ytdl.getInfo(obj.id);
if (info) {
info = info.formats;
if (!info[0]["isLive"]) {
if (obj.isAudioOnly) {
obj.format = "webm"
obj.quality = "max"
}
let selectedVideo, videoMatch = [], video = [], audio = info.filter((a) => {
if (!a["isLive"] && !a["isHLS"] && !a["isDashMPD"] && a["hasAudio"] && !a["hasVideo"] && a["container"] == obj.format) {
return true;
}
}).sort((a, b) => Number(b.bitrate) - Number(a.bitrate));
if (!obj.isAudioOnly) {
video = info.filter((a) => {
if (!a["isLive"] && !a["isHLS"] && !a["isDashMPD"] && !a["hasAudio"] && a["hasVideo"] && a["container"] == obj.format && a["height"] != 4320) {
if (obj.quality != "max" && mq[obj.quality] == a["height"]) {
videoMatch.push(a)
}
return true;
}
}).sort((a, b) => Number(b.bitrate) - Number(a.bitrate));
selectedVideo = video[0]
if (obj.quality != "max") {
if (videoMatch.length > 0) {
selectedVideo = videoMatch[0]
} else {
let ss = selectQuality("youtube", obj.quality, video[0]["height"])
selectedVideo = video.filter((a) => {
if (a["height"] == ss) {
return true
}
})
selectedVideo = selectedVideo[0]
}
}
if (obj.quality == "los") {
selectedVideo = video[video.length - 1]
}
}
if (audio[0]["approxDurationMs"] <= maxVideoDuration) {
if (!obj.isAudioOnly && video.length > 0) {
let filename = `youtube_${obj.id}_${selectedVideo["width"]}x${selectedVideo["height"]}.${obj.format}`;
if (video.length > 0 && audio.length > 0) {
return { type: "render", urls: [selectedVideo["url"], audio[0]["url"]], time: video[0]["approxDurationMs"], filename: filename };
} else {
return { error: loc('en', 'apiError', 'youtubeBroke') };
}
} else if (audio.length > 0) {
return { type: "render", isAudioOnly: true, urls: [audio[0]["url"]], filename: `youtube_${obj.id}_${audio[0]["audioBitrate"]}kbps.opus` };
} else {
return { error: loc('en', 'apiError', 'youtubeBroke') };
}
} else {
return { error: loc('en', 'apiError', 'youtubeLimit', maxVideoDuration / 60000) };
}
} else {
return { error: loc('en', 'apiError', 'liveVideo') };
}
} else {
return { error: loc('en', 'apiError', 'youtubeFetch') };
}
} catch (e) {
return { error: loc('en', 'apiError', 'youtubeFetch') };
}
}