From e9a67e1f48f52f36b93d7dd2bacb3d08f78c4368 Mon Sep 17 00:00:00 2001 From: wukko Date: Sat, 30 Jul 2022 16:58:14 +0600 Subject: [PATCH] added support for douyin - full support for douyin (no watermark) - fixed up some tiktok stuff in the module --- src/config.json | 1 + src/modules/config.js | 1 + src/modules/match.js | 16 ++++++++++++- src/modules/services/_config.json | 6 ++++- src/modules/services/douyin.js | 38 +++++++++++++++++++++++++++++++ src/modules/services/tiktok.js | 5 ++-- 6 files changed, 62 insertions(+), 5 deletions(-) create mode 100644 src/modules/services/douyin.js diff --git a/src/config.json b/src/config.json index 4b0885b..b2a1c75 100644 --- a/src/config.json +++ b/src/config.json @@ -2,6 +2,7 @@ "streamLifespan": 1800000, "maxVideoDuration": 1920000, "genericUserAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36", + "mobileUserAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1", "authorInfo": { "name": "wukko", "link": "https://wukko.me/", diff --git a/src/modules/config.js b/src/modules/config.js index da7f708..34e3acf 100644 --- a/src/modules/config.js +++ b/src/modules/config.js @@ -9,6 +9,7 @@ version = packageJson.version, streamLifespan = config.streamLifespan, maxVideoDuration = config.maxVideoDuration, genericUserAgent = config.genericUserAgent, +mobileUserAgent = config.mobileUserAgent, repo = packageJson["bugs"]["url"].replace('/issues', ''), authorInfo = config.authorInfo, supportedLanguages = config.supportedLanguages, diff --git a/src/modules/match.js b/src/modules/match.js index f2da4f1..03397e9 100644 --- a/src/modules/match.js +++ b/src/modules/match.js @@ -7,6 +7,7 @@ import twitter from "./services/twitter.js"; import youtube from "./services/youtube.js"; import vk from "./services/vk.js"; import tiktok from "./services/tiktok.js"; +import douyin from "./services/douyin.js"; export default async function (host, patternMatch, url, ip, lang, format, quality) { try { @@ -87,7 +88,7 @@ export default async function (host, patternMatch, url, ip, lang, format, qualit }) : apiJSON(0, { t: r.error }); } else throw Error() case "tiktok": - if ((patternMatch["user"] && patternMatch["type"] == "video" && patternMatch["postId"] && patternMatch["postId"].length <= 21) || + if ((patternMatch["user"] && patternMatch["postId"] && patternMatch["postId"].length <= 21) || (patternMatch["id"] && patternMatch["id"].length <= 13)) { let r = await tiktok({ postId: patternMatch["postId"], @@ -99,6 +100,19 @@ export default async function (host, patternMatch, url, ip, lang, format, qualit filename: r.filename, salt: process.env.streamSalt }) : apiJSON(0, { t: r.error }); } else throw Error() + case "douyin": + if ((patternMatch["postId"] && patternMatch["postId"].length <= 21) || + (patternMatch["id"] && patternMatch["id"].length <= 13)) { + let r = await douyin({ + postId: patternMatch["postId"], + id: patternMatch["id"], lang: lang, + }); + return (!r.error) ? apiJSON(2, { + type: "bridge", u: r.urls, lang: lang, + service: host, ip: ip, + filename: r.filename, salt: process.env.streamSalt + }) : apiJSON(0, { t: r.error }); + } else throw Error() default: return apiJSON(0, { t: errorUnsupported(lang) }) } diff --git a/src/modules/services/_config.json b/src/modules/services/_config.json index 291008e..7b2f6fc 100644 --- a/src/modules/services/_config.json +++ b/src/modules/services/_config.json @@ -66,7 +66,11 @@ "enabled": false }, "tiktok": { - "patterns": [":user/:type/:postId", ":id"], + "patterns": [":user/video/:postId", ":id"], + "enabled": true + }, + "douyin": { + "patterns": ["video/:postId", ":id"], "enabled": true } } \ No newline at end of file diff --git a/src/modules/services/douyin.js b/src/modules/services/douyin.js new file mode 100644 index 0000000..3e45ad6 --- /dev/null +++ b/src/modules/services/douyin.js @@ -0,0 +1,38 @@ +import got from "got"; +import loc from "../../localization/manager.js"; +import { genericUserAgent, mobileUserAgent } 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('')) { + 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': mobileUserAgent, + '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); + if (iteminfo['item_list'][0]['video']['play_addr']['url_list'][0]) { + return { urls: iteminfo['item_list'][0]['video']['play_addr']['url_list'][0].replace("playwm", "play"), filename: `douyin_${obj.postId}.mp4` }; + } else { + return { error: loc(obj.lang, 'ErrorEmptyDownload') }; + } + } catch (e) { + return { error: loc(obj.lang, 'ErrorBadFetch') }; + } +} diff --git a/src/modules/services/tiktok.js b/src/modules/services/tiktok.js index 20e38b6..3bd7f67 100644 --- a/src/modules/services/tiktok.js +++ b/src/modules/services/tiktok.js @@ -1,6 +1,6 @@ import got from "got"; import loc from "../../localization/manager.js"; -import { genericUserAgent} from "../config.js"; +import { genericUserAgent } from "../config.js"; import { unicodeDecode } from "../sub/utils.js"; export default async function(obj) { @@ -17,8 +17,7 @@ export default async function(obj) { obj.postId = html.split('aweme/detail/')[1].split('?')[0] } } - let url = `https://tiktok.com/@video/video/${obj.postId}` - let html = await got.get(url, { headers: { "user-agent": genericUserAgent } }); + let html = await got.get(`https://tiktok.com/@video/video/${obj.postId}`, { headers: { "user-agent": genericUserAgent } }); html.on('error', (err) => { return { error: loc(obj.lang, 'ErrorCantConnectToServiceAPI', 'tiktok') }; });