tiktok images and crowdin

This commit is contained in:
wukko
2022-09-03 21:32:39 +06:00
parent 297c1ed116
commit 9ea832caf5
24 changed files with 313 additions and 269 deletions

View File

@@ -1,67 +0,0 @@
import got from "got";
import loc from "../../localization/manager.js";
import { genericUserAgent } from "../config.js";
export default async function(obj) {
try {
if (!obj.postId) {
let html = await got.get(`https://v.douyin.com/${obj.id}/`, { headers: { "user-agent": genericUserAgent } });
html.on('error', (err) => {
return { error: loc(obj.lang, 'ErrorCantConnectToServiceAPI', 'tiktok') };
});
if (html.body.includes('<html><head><meta charset="UTF-8" />')) {
obj.postId = html.url.split('video/')[1].split('?')[0]
} else {
obj.postId = html.body.split('video/')[1].split('/?')[0]
}
}
let iteminfo = await got.get(`https://www.iesdouyin.com/web/api/v2/aweme/iteminfo/?item_ids=${obj.postId}`, {
headers: {
'authority': 'www.iesdouyin.com',
'user-agent': genericUserAgent,
'content-type': 'application/x-www-form-urlencoded',
'accept': '*/*',
'referer': `https://www.iesdouyin.com/share/video/${obj.postId}/?region=CN&u_code=15b9142gf&titleType=title&utm_source=copy_link&utm_campaign=client_share&utm_medium=android&app=aweme`,
'accept-language': 'zh-CN,zh;q=0.9,en-GB;q=0.8,en;q=0.7'
}
});
iteminfo.on('error', (err) => {
return { error: loc(obj.lang, 'ErrorCantConnectToServiceAPI', 'douyin') };
});
iteminfo = JSON.parse(iteminfo.body);
let video = iteminfo['item_list'][0]['video']['play_addr']['url_list'][0];
let audio = obj.isAudioOnly ? iteminfo['item_list'][0]["music"]["play_url"]["url_list"][0] : false;
if (audio && obj.fullAudio) {
return {
urls: audio,
audioFilename: `douyin_${obj.postId}_audio_full`,
isAudio: true
}
} else if (audio && audio.slice(-4) == ".mp3") {
return {
urls: audio,
audioFilename: `douyin_${obj.postId}_audio`,
isAudio: true,
isMp3: true,
};
} else if (video) {
if (!obj.noWatermark) {
return {
urls: video,
audioFilename: `douyin_${obj.postId}_audio`,
filename: `douyin_${obj.postId}.mp4`
};
} else {
return {
urls: video.replace("playwm", "play"),
audioFilename: `douyin_${obj.postId}_audio`,
filename: `douyin_${obj.postId}_nw.mp4`
};
}
} else {
return { error: loc(obj.lang, 'ErrorEmptyDownload') };
}
} catch (e) {
return { error: loc(obj.lang, 'ErrorBadFetch') };
}
}

View File

@@ -36,7 +36,6 @@ export default async function(obj) {
} else return { error: loc(obj.lang, 'ErrorEmptyDownload') }
} else return { error: loc(obj.lang, 'ErrorBrokenLink', 'soundcloud') }
} catch (e) {
console.log(e)
return { error: loc(obj.lang, 'ErrorBadFetch') };
}
}

View File

@@ -4,66 +4,102 @@ import { genericUserAgent } from "../config.js";
import { unicodeDecode } from "../sub/utils.js";
let userAgent = genericUserAgent.split(' Chrome/1')[0]
let config = {
tiktok: {
short: "https://vt.tiktok.com/",
api: "https://api.tiktokv.com/aweme/v1/aweme/detail/?aweme_id=",
},
douyin: {
short: "https://v.douyin.com/",
api: "https://www.iesdouyin.com/web/api/v2/aweme/iteminfo/?item_ids=",
}
}
function selector(j, h) {
switch (h) {
case "tiktok":
return j["aweme_detail"]
case "douyin":
return j['item_list'][0]
}
}
export default async function(obj) {
try {
if (!obj.postId) {
let html = await got.get(`https://vt.tiktok.com/${obj.id}`, { headers: { "user-agent": userAgent } });
let html = await got.get(`${config[obj.host]["short"]}${obj.id}`, { followRedirect: false, headers: { "user-agent": userAgent } });
html.on('error', (err) => {
return { error: loc(obj.lang, 'ErrorCantConnectToServiceAPI', 'tiktok') };
});
html = html.body
if (!html.includes('<!DOCTYPE html>')) {
obj.postId = html.split('video/')[1].split('?')[0]
} else {
obj.postId = html.split('aweme/detail/')[1].split('?')[0]
}
}
if (!obj.noWatermark && !obj.isAudioOnly) {
let html = await got.get(`https://tiktok.com/@video/video/${obj.postId}`, { headers: { "user-agent": userAgent } });
html.on('error', (err) => {
return { error: loc(obj.lang, 'ErrorCantConnectToServiceAPI', 'tiktok') };
return { error: loc(obj.lang, 'ErrorCantConnectToServiceAPI', obj.host) };
});
html = html.body;
if (html.includes(',"preloadList":[{"url":"')) {
return {
urls: unicodeDecode(html.split(',"preloadList":[{"url":"')[1].split('","id":"')[0].trim()),
audioFilename: `tiktok_${obj.postId}_audio`,
filename: `tiktok_${obj.postId}.mp4`
};
if (html.slice(0, 17) === '<a href="https://' && html.includes('/video/')) obj.postId = html.split('video/')[1].split('?')[0].replace("/", '')
}
if (!obj.postId) return { error: loc(obj.lang, 'ErrorCantGetID') };
let detail = await got.get(`${config[obj.host]["api"]}${obj.postId}`);
detail.on('error', (err) => {
return { error: loc(obj.lang, 'ErrorCantConnectToServiceAPI', obj.host) };
});
detail = selector(JSON.parse(detail.body), obj.host);
let video, videoFilename, audioFilename, isMp3, audio,
images = detail["image_post_info"] ? detail["image_post_info"]["images"] : false,
filenameBase = `${obj.host}_${obj.postId}`;
if (!obj.isAudioOnly && !images) {
if (obj.host == "tiktok") {
video = detail["video"]["play_addr"]["url_list"][0]
} else {
return { error: loc(obj.lang, 'ErrorEmptyDownload') };
video = detail["video"]["play_addr"]["url_list"][0].replace("playwm", "play")
}
videoFilename = `${filenameBase}_video_nw.mp4` // nw - no watermark
if (!obj.noWatermark) {
if (obj.host == "tiktok") {
let html = await got.get(`https://tiktok.com/@video/video/${obj.postId}`, { headers: { "user-agent": userAgent } });
html.on('error', (err) => {
return { error: loc(obj.lang, 'ErrorCantConnectToServiceAPI', obj.host) };
});
html = html.body;
if (html.includes(',"preloadList":[{"url":"')) {
video = unicodeDecode(html.split(',"preloadList":[{"url":"')[1].split('","id":"')[0].trim())
}
} else {
video = detail['video']['play_addr']['url_list'][0]
}
videoFilename = `${filenameBase}_video.mp4`
}
} else {
let detail = await got.get(`https://api.tiktokv.com/aweme/v1/aweme/detail/?aweme_id=${obj.postId}`);
detail.on('error', (err) => {
return { error: loc(obj.lang, 'ErrorCantConnectToServiceAPI', 'tiktok') };
});
detail = JSON.parse(detail.body);
let video = detail["aweme_detail"]["video"]["play_addr"]["url_list"][0];
let audio = obj.isAudioOnly ? detail["aweme_detail"]["music"]["play_url"]["url_list"][0] : false;
if (audio && obj.fullAudio) {
return {
urls: audio,
audioFilename: `tiktok_${obj.postId}_audio_full`,
isAudio: true
}
} else if (audio && audio.slice(-4) == ".mp3") {
return {
urls: audio,
audioFilename: `tiktok_${obj.postId}_audio`,
isAudio: true,
isMp3: true,
};
} else if (video) {
return {
urls: video,
audioFilename: `tiktok_${obj.postId}_audio`,
filename: `tiktok_${obj.postId}_nw.mp4`
};
let fallback = obj.host == "douyin" ? detail["video"]["play_addr"]["url_list"][0].replace("playwm", "play") : detail["video"]["play_addr"]["url_list"][0];
if (obj.fullAudio || fallback.includes("music")) {
audio = detail["music"]["play_url"]["url_list"][0]
audioFilename = `${filenameBase}_audio`
} else {
return { error: loc(obj.lang, 'ErrorEmptyDownload') };
audio = fallback
audioFilename = `${filenameBase}_audio_fv` // fv - from video
}
if (audio.slice(-4) == ".mp3") isMp3 = true;
}
if (video) return {
urls: video,
filename: videoFilename
}
if (images) {
let imageLinks = [];
for (let i in images) {
imageLinks.push(images[i]["display_image"]["url_list"][0])
}
return {
images: imageLinks,
urls: audio,
audioFilename: audioFilename,
isAudioOnly: true,
isMp3: isMp3,
}
}
if (audio) return {
urls: audio,
audioFilename: audioFilename,
isAudioOnly: true,
isMp3: isMp3,
}
} catch (e) {
return { error: loc(obj.lang, 'ErrorBadFetch') };

View File

@@ -1,52 +1,38 @@
import got from "got";
import loc from "../../localization/manager.js";
import { services } from "../config.js";
const configSt = services.twitter;
async function fetchTweetInfo(obj) {
let cantConnect = { error: loc(obj.lang, 'ErrorCantConnectToServiceAPI', 'twitter') }
export default async function(obj) {
try {
let _headers = {
"Authorization": `Bearer ${configSt.token}`,
"Host": configSt.api,
"Authorization": "Bearer AAAAAAAAAAAAAAAAAAAAAIK1zgAAAAAA2tUWuhGZ2JceoId5GwYWU5GspY4%3DUq7gzFoCZs1QfwGoVdvSac3IniczZEYXIcDyumCauIXpcAPorE",
"Host": "api.twitter.com",
"Content-Type": "application/json",
"Content-Length": 0
};
let req_act = await got.post(`https://${configSt.api}/${configSt.apiURLs.activate}`, {
let req_act = await got.post("https://api.twitter.com/1.1/guest/activate.json", {
headers: _headers
});
req_act.on('error', (err) => {
return cantConnect
return { error: loc(obj.lang, 'ErrorCantConnectToServiceAPI', 'twitter') }
})
_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`, {
let req_status = await got.get(`https://api.twitter.com/1.1/statuses/show.json?id=${obj.id}&tweet_mode=extended`, {
headers: _headers
});
req_status.on('error', (err) => {
return cantConnect
return { error: loc(obj.lang, 'ErrorCantConnectToServiceAPI', 'twitter') }
})
return JSON.parse(req_status.body);
} catch (err) {
return cantConnect;
}
}
export default async function(obj) {
let nothing = { error: loc(obj.lang, 'ErrorEmptyDownload') }
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 { urls: variants.filter((v) => { if (v["content_type"] == "video/mp4") return true; }).sort((a, b) => Number(b.bitrate) - Number(a.bitrate))[0]["url"].split('?')[0], audioFilename: `twitter_${obj.id}_audio` }
} else {
return nothing
}
let parsbod = JSON.parse(req_status.body);
if (parsbod.hasOwnProperty("extended_entities") && parsbod["extended_entities"].hasOwnProperty("media")) {
let media = parsbod["extended_entities"]["media"][0]
if (media["type"] === "video" || media["type"] === "animated_gif") {
return { urls: media["video_info"]["variants"].filter((v) => { if (v["content_type"] == "video/mp4") return true; }).sort((a, b) => Number(b.bitrate) - Number(a.bitrate))[0]["url"].split('?')[0], audioFilename: `twitter_${obj.id}_audio` }
} else {
return nothing
return { error: loc(obj.lang, 'ErrorNoVideosInTweet') }
}
} else return parsbod;
} else {
return { error: loc(obj.lang, 'ErrorNoVideosInTweet') }
}
} catch (err) {
return { error: loc(obj.lang, 'ErrorBadFetch') };
}