diff --git a/src/api/index.ts b/src/api/index.ts index aadfd6e..cfb9677 100644 --- a/src/api/index.ts +++ b/src/api/index.ts @@ -2,3 +2,6 @@ export const _tiktokurl: string = "https://www.tiktok.com" export const _tiktokapi = (id: string): string => `https://api.tiktokv.com/aweme/v1/feed/?aweme_id=${id}` export const _ssstikapi: string = "https://ssstik.io/abc?url=dl" export const _ssstikurl: string = "https://ssstik.io" +export const _musicaldownapi: string = "https://musicaldown.com/download" +export const _musicaldownurl: string = "https://musicaldown.com" +export const _musicaldownmusicapi: string = "https://musicaldown.com/mp3/download" diff --git a/src/types/musicaldown.ts b/src/types/musicaldown.ts new file mode 100644 index 0000000..6cd972e --- /dev/null +++ b/src/types/musicaldown.ts @@ -0,0 +1,32 @@ +export interface getRequest { + status: "success" | "error" + request?: { + [key: string]: string + } + message?: string + cookie?: string +} + +export interface MusicalDownResponse { + status: "success" | "error" + message?: string + result?: { + type: "video" | "image" + desc?: string + author: { + avatar?: string + nickname: string + } + music?: string + images?: string[] + video1?: string + video2?: string + video_hd?: string + video_watermark?: string + } +} + +export interface getMusic { + status: "success" | "error" + result?: string +} diff --git a/src/utils/musicaldown.ts b/src/utils/musicaldown.ts new file mode 100644 index 0000000..3c49f13 --- /dev/null +++ b/src/utils/musicaldown.ts @@ -0,0 +1,123 @@ +import Axios from "axios" +import { load } from "cheerio" +import { MusicalDownResponse, getMusic, getRequest } from "../types/musicaldown" +import { _musicaldownapi, _musicaldownmusicapi, _musicaldownurl } from "../api" + +/** + * Using API from Website: + * BASE URL : https://ssstik.io + */ + +const getRequest = (url: string) => + new Promise((resolve, reject) => { + Axios.get(_musicaldownurl, { + headers: { + "User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/111.0" + } + }) + .then((data) => { + const cookie = data.headers["set-cookie"][0].split(";")[0] + "; " + "lang=en" + const $ = load(data.data) + const input = $("div > input").map((_, el) => $(el)) + const request = { + [input.get(0).attr("name")]: url, + [input.get(1).attr("name")]: input.get(1).attr("value"), + [input.get(2).attr("name")]: input.get(2).attr("value") + } + resolve({ status: "success", request, cookie }) + }) + .catch((e) => resolve({ status: "error", message: "Failed to get the request form!" })) + }) + +const getMusic = (cookie: string) => + new Promise((resolve, reject) => { + Axios.get(_musicaldownmusicapi, { + headers: { + cookie: cookie, + "Upgrade-Insecure-Requests": "1", + "User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/111.0" + } + }) + .then(({ data }) => { + const $ = load(data) + const music = $("audio > source").attr("src") + resolve({ status: "success", result: music }) + }) + .catch((e) => resolve({ status: "error" })) + }) + +export const MusicalDown = (url: string) => + new Promise(async (resolve, reject) => { + const request: getRequest = await getRequest(url) + if (request.status !== "success") return resolve({ status: "error", message: request.message }) + Axios(_musicaldownapi, { + method: "POST", + headers: { + cookie: request.cookie, + "Upgrade-Insecure-Requests": "1", + "Content-Type": "application/x-www-form-urlencoded", + "User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/111.0" + }, + data: new URLSearchParams(Object.entries(request.request)) + }) + .then(async ({ data }) => { + const $ = load(data) + + // Get Image Video + const images = [] + $("div.row > div[class='col s12 m3']") + .get() + .map((v) => { + images.push($(v).find("img").attr("src")) + }) + + // Get Result Video + let i = 1 + let videos = {} + $("div[class='col s12 l8'] > a") + .get() + .map((v) => { + if ($(v).attr("href") !== "#modal2") { + let text = $(v).text().trim().replace(/\s/, " ").replace("arrow_downward", "").toLowerCase() + videos[text.includes("hd") ? "video_hd" : text.includes("watermark") ? "video_watermark" : `video${i}`] = $(v).attr("href") + i++ + } + }) + // Result + if (images.length !== 0) { + // Images or Slide Result + resolve({ + status: "success", + result: { + type: "image", + author: { + nickname: $("h2.white-text").text().trim().replace("Download Now: Check out ", "").replace("’s video! #TikTok >If MusicallyDown has helped you, you can help us too", "").replace("Download Now: ", "").replace("If MusicallyDown has helped you, you can help us too", "") + }, + images, + music: $("a.download").attr("href") + } + }) + } else { + // Video Result + const music = await getMusic(request.cookie) + resolve({ + status: "success", + result: { + type: "video", + author: { + avatar: $("div.img-area > img").attr("src"), + nickname: $("div.row > div > div > h2") + .map((_, el) => $(el).text()) + .get(0) + }, + desc: $("div.row > div > div > h2") + .map((_, el) => $(el).text()) + .get(1), + music: music.result, + ...videos + } + }) + } + }) + .catch((e) => resolve({ status: "error", message: e.message })) + }) diff --git a/src/utils/ssstik.ts b/src/utils/ssstik.ts index 326c865..2845324 100644 --- a/src/utils/ssstik.ts +++ b/src/utils/ssstik.ts @@ -3,6 +3,11 @@ import { load } from "cheerio" import { Author, Statistics, SSSTikFetchTT, SSSTikResult } from "../types/ssstik" import { _ssstikapi, _ssstikurl } from "../api" +/** + * Using API from Website: + * BASE URL : https://ssstik.io + */ + const fetchTT = () => new Promise(async (resolve, reject) => { Axios.get(_ssstikurl, { @@ -14,10 +19,10 @@ const fetchTT = () => const regex = /form\.setAttribute\("include-vals",\s*"([^"]+)"\)/ const match = data.match(regex) if (match) { - const includeValsValue = match[1] - resolve({ status: "success", result: includeValsValue }) + const value = match[1] + resolve({ status: "success", result: value }) } else { - resolve({ status: "error", message: "Not found" }) + resolve({ status: "error", message: "Failed to get the request form!" }) } }) .catch((e) => resolve({ status: "error", message: e.message })) @@ -39,7 +44,7 @@ export const SSSTik = (url: string) => Object.entries({ id: url, locale: "en", - tt: tt.result as string + tt: tt.result }) ) }) @@ -49,7 +54,7 @@ export const SSSTik = (url: string) => // Result const desc = $("p.maintext").text().trim() const author: Author = { - avatar: $("img.result_author").attr("src") as string, + avatar: $("img.result_author").attr("src"), nickname: $("h2").text().trim() } const statistics: Statistics = { @@ -63,7 +68,7 @@ export const SSSTik = (url: string) => $("ul.splide__list > li") .get() .map((img) => { - images.push($(img).find("img").attr("src") as string) + images.push($(img).find("img").attr("src")) }) if (images.length !== 0) { @@ -76,7 +81,7 @@ export const SSSTik = (url: string) => author, statistics, images, - music: $("a.music").attr("href") as string + music: $("a.music").attr("href") } }) } else { @@ -89,7 +94,7 @@ export const SSSTik = (url: string) => author, statistics, video: $("a.without_watermark").attr("href"), - music: $("a.music").attr("href") as string + music: $("a.music").attr("href") } }) } diff --git a/src/utils/switch.ts b/src/utils/switch.ts index b90a798..9112336 100644 --- a/src/utils/switch.ts +++ b/src/utils/switch.ts @@ -1,7 +1,8 @@ +import { MusicalDown } from "./musicaldown" import { SSSTik } from "./ssstik" import { TiktokAPI } from "./tiktokapi" -export const TiktokDL = (url: string, options: { version: "v1" | "v2" }) => +export const TiktokDL = (url: string, options: { version: "v1" | "v2" | "v3" }) => new Promise(async (resolve, reject) => { switch (options.version) { case "v1": { @@ -10,6 +11,9 @@ export const TiktokDL = (url: string, options: { version: "v1" | "v2" }) => case "v2": { await SSSTik(url).then(resolve).catch(reject) } + case "v3": { + await MusicalDown(url).then(resolve).catch(reject) + } default: { await TiktokAPI(url).then(resolve).catch(reject) }