mirror of
https://github.com/hansputera/tiktok-dl.git
synced 2026-04-05 19:51:57 +02:00
fix(provider): fixed musically down token match
This commit is contained in:
@@ -11,7 +11,8 @@ export default async (req: VercelRequest, res: VercelResponse) => {
|
||||
'type': ow.optional.string.validate((v) => ({
|
||||
'validator': typeof v === 'string' &&
|
||||
providersType.includes(v.toLowerCase()),
|
||||
'message': 'Invalid Provider',
|
||||
'message': 'Invalid Provider, available provider is: ' +
|
||||
Providers.map((x) => x.resourceName()).join(', '),
|
||||
})),
|
||||
}));
|
||||
|
||||
|
||||
@@ -1,22 +1,30 @@
|
||||
/**
|
||||
* Decorator to handle exception.
|
||||
* @return {Function}
|
||||
* @param {any} target
|
||||
* @param {string} _
|
||||
* @param {PropertyDescriptor} descriptor
|
||||
* @return {void}
|
||||
*/
|
||||
export const handleException = (): Function => {
|
||||
return function(
|
||||
target: any,
|
||||
_: string,
|
||||
descriptor: PropertyDescriptor) {
|
||||
const oldValue = descriptor.value;
|
||||
descriptor.value = (...args: any) => {
|
||||
export const handleException = <T extends Function>
|
||||
(target: object, _: string, descriptor: TypedPropertyDescriptor<T>):
|
||||
TypedPropertyDescriptor<T> | void => {
|
||||
return {
|
||||
configurable: true,
|
||||
get(this: T): T {
|
||||
try {
|
||||
return oldValue.apply(target, args);
|
||||
const bound: T = descriptor.value?.bind(this);
|
||||
Object.defineProperty(this, _, {
|
||||
value: bound,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
});
|
||||
|
||||
return bound;
|
||||
} catch (err) {
|
||||
return {
|
||||
'error': (err as Error).message,
|
||||
'error.stack': (err as Error).stack as string,
|
||||
};
|
||||
} as unknown as T;
|
||||
}
|
||||
};
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
21
lib/fetch.ts
21
lib/fetch.ts
@@ -1,4 +1,4 @@
|
||||
import got from 'got';
|
||||
import got, {ExtendOptions} from 'got';
|
||||
import {tiktokBase, tiktokTBase} from './config';
|
||||
|
||||
export const TFetch = got.extend({
|
||||
@@ -11,17 +11,10 @@ export const fetch = got.extend({
|
||||
dnsCache: true,
|
||||
});
|
||||
|
||||
export const snaptikFetch = got.extend({
|
||||
prefixUrl: 'https://snaptik.app/en',
|
||||
dnsCache: true,
|
||||
});
|
||||
|
||||
export const tikmateFetch = got.extend({
|
||||
prefixUrl: 'https://tikmate.online',
|
||||
dnsCache: true,
|
||||
});
|
||||
|
||||
export const musicalyFetch = got.extend({
|
||||
prefixUrl: 'https://musicaldown.com/id',
|
||||
dnsCache: true,
|
||||
});
|
||||
export const getFetch = (baseUrl: string, options?: ExtendOptions) =>
|
||||
got.extend({
|
||||
prefixUrl: baseUrl,
|
||||
dnsCache: true,
|
||||
...options,
|
||||
});
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import {Got} from 'got';
|
||||
|
||||
export interface ExtractedInfo {
|
||||
error?: string;
|
||||
result?: {
|
||||
@@ -10,8 +12,8 @@ export interface ExtractedInfo {
|
||||
* @class BaseProvider
|
||||
*/
|
||||
export abstract class BaseProvider {
|
||||
abstract client: Got;
|
||||
abstract resourceName(): string;
|
||||
abstract fetch(url: string): Promise<ExtractedInfo>;
|
||||
abstract extract(html: string): ExtractedInfo;
|
||||
abstract getURI(): string;
|
||||
};
|
||||
|
||||
@@ -3,11 +3,13 @@ import {MusicalyDown} from './musicalyDown';
|
||||
|
||||
import {SnaptikProvider} from './snaptikProvider';
|
||||
import {TikmateProvider} from './tikmateProvider';
|
||||
import {TTDownloader} from './ttDownloader';
|
||||
|
||||
export const Providers: BaseProvider[] = [
|
||||
new SnaptikProvider(),
|
||||
new TikmateProvider(),
|
||||
new MusicalyDown(),
|
||||
new TTDownloader(),
|
||||
];
|
||||
|
||||
export const getRandomProvider = () => Providers[
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {musicalyFetch} from '..';
|
||||
import {getFetch} from '..';
|
||||
import {handleException} from '../decorators';
|
||||
import {BaseProvider, ExtractedInfo} from './baseProvider';
|
||||
|
||||
@@ -6,6 +6,7 @@ import {BaseProvider, ExtractedInfo} from './baseProvider';
|
||||
* @class MusicalyDown
|
||||
*/
|
||||
export class MusicalyDown extends BaseProvider {
|
||||
public client = getFetch('https://musicaldown.com/id');
|
||||
/**
|
||||
*
|
||||
* @return {string}
|
||||
@@ -14,47 +15,40 @@ export class MusicalyDown extends BaseProvider {
|
||||
return 'musicalydown';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {string}
|
||||
*/
|
||||
public getURI(): string {
|
||||
return musicalyFetch.defaults.options.prefixUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {string} url - Video Tiktok URL
|
||||
* @return {string}
|
||||
*/
|
||||
@handleException()
|
||||
@handleException
|
||||
public async fetch(url: string): Promise<ExtractedInfo> {
|
||||
const headers = {
|
||||
'Accept': '*/*',
|
||||
'Referer': this.client.defaults.options.prefixUrl,
|
||||
'Origin': this.client.defaults.options.prefixUrl,
|
||||
};
|
||||
const res = await musicalyFetch('./', {
|
||||
const res = await this.client('./', {
|
||||
headers,
|
||||
});
|
||||
const form = {} as Record<string, string>;
|
||||
const tokens = (res.body.match(/input name="([^"]+)/gi) as string[])
|
||||
.map((x) => x.split('"').pop() as string);
|
||||
const token = (
|
||||
res.body.match(/type="hidden" value="(.*?)"/gi) as string[])[0]
|
||||
.split(/=/g).pop()?.replace(/\"/g, '');
|
||||
const value = [url, token as string, '1'];
|
||||
// eslint-disable-next-line guard-for-in
|
||||
for (const tok in tokens) {
|
||||
form[tokens[tok]] = value[tok];
|
||||
}
|
||||
const cookie = res.headers['set-cookie']?.toString();
|
||||
const response = await musicalyFetch.post('./download', {
|
||||
form,
|
||||
const tokens = (
|
||||
res.body.match(
|
||||
/input name="([^""]+)" type="hidden" value="([^""]+)"/) as string[]
|
||||
);
|
||||
const response = await this.client.post('./download', {
|
||||
form: {
|
||||
[(
|
||||
res.body.match(/input name="([^"]+)/) as string[]
|
||||
)[1]]: url,
|
||||
[tokens[1]]: tokens[2],
|
||||
'verify': 1,
|
||||
},
|
||||
headers: {
|
||||
cookie,
|
||||
'Cookie': res.headers['set-cookie']?.toString(),
|
||||
...headers,
|
||||
},
|
||||
method: 'POST',
|
||||
}).text();
|
||||
return this.extract(response);
|
||||
});
|
||||
|
||||
return this.extract(response.body);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {snaptikFetch} from '..';
|
||||
import {getFetch} from '..';
|
||||
import {handleException} from '../decorators';
|
||||
import {BaseProvider, ExtractedInfo} from './baseProvider';
|
||||
import {deObfuscate, matchLink} from './util';
|
||||
@@ -7,6 +7,7 @@ import {deObfuscate, matchLink} from './util';
|
||||
* @class SnaptikProvider
|
||||
*/
|
||||
export class SnaptikProvider extends BaseProvider {
|
||||
public client = getFetch('https://snaptik.app/en');
|
||||
/**
|
||||
*
|
||||
* @return {string}
|
||||
@@ -15,22 +16,14 @@ export class SnaptikProvider extends BaseProvider {
|
||||
return 'snaptik';
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return {string}
|
||||
*/
|
||||
public getURI(): string {
|
||||
return snaptikFetch.defaults.options.prefixUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {string} url - TikTok Video URL
|
||||
* @return {Promise<ExtractedInfo>}
|
||||
*/
|
||||
@handleException()
|
||||
@handleException
|
||||
public async fetch(url: string): Promise<ExtractedInfo> {
|
||||
const response = await snaptikFetch('./abc.php', {
|
||||
const response = await this.client('./abc.php', {
|
||||
searchParams: {
|
||||
'url': url,
|
||||
},
|
||||
@@ -45,7 +38,7 @@ export class SnaptikProvider extends BaseProvider {
|
||||
* @param {string} html - Raw HTML
|
||||
* @return {ExtractedInfo}
|
||||
*/
|
||||
@handleException()
|
||||
@handleException
|
||||
extract(html: string): ExtractedInfo {
|
||||
const results = matchLink(deObfuscate(html));
|
||||
if (!results || !results.length) throw new Error('Broken');
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {tikmateFetch} from '..';
|
||||
import {getFetch} from '..';
|
||||
import {handleException} from '../decorators';
|
||||
import {BaseProvider, ExtractedInfo} from './baseProvider';
|
||||
import {deObfuscate, matchTikmateDownload} from './util';
|
||||
@@ -7,6 +7,7 @@ import {deObfuscate, matchTikmateDownload} from './util';
|
||||
* @class TikmateProvider
|
||||
*/
|
||||
export class TikmateProvider extends BaseProvider {
|
||||
public client = getFetch('https://tikmate.online');
|
||||
/**
|
||||
*
|
||||
* @return {string}
|
||||
@@ -20,7 +21,7 @@ export class TikmateProvider extends BaseProvider {
|
||||
* @return {string}
|
||||
*/
|
||||
public getURI(): string {
|
||||
return tikmateFetch.defaults.options.prefixUrl;
|
||||
return this.client.defaults.options.prefixUrl;
|
||||
}
|
||||
|
||||
|
||||
@@ -28,23 +29,23 @@ export class TikmateProvider extends BaseProvider {
|
||||
*
|
||||
* @param {string} url - Video TikTok URL
|
||||
*/
|
||||
@handleException()
|
||||
@handleException
|
||||
public async fetch(url: string): Promise<ExtractedInfo> {
|
||||
// we need to get the token
|
||||
|
||||
const response = await tikmateFetch('./');
|
||||
const response = await this.client('./');
|
||||
const token =
|
||||
(response.body.match(/id="token" value="(.*)?"/) as string[])[1];
|
||||
const cookies = response.headers['cookie'];
|
||||
|
||||
const abcResponse = await tikmateFetch.post('./abc.php', {
|
||||
const abcResponse = await this.client.post('./abc.php', {
|
||||
form: {
|
||||
'url': url,
|
||||
'token': token,
|
||||
},
|
||||
headers: {
|
||||
'Origin': tikmateFetch.defaults.options.prefixUrl,
|
||||
'Referer': tikmateFetch.defaults.options.prefixUrl + '/',
|
||||
'Origin': this.client.defaults.options.prefixUrl,
|
||||
'Referer': this.client.defaults.options.prefixUrl + '/',
|
||||
'Cookie': cookies,
|
||||
},
|
||||
});
|
||||
|
||||
58
lib/providers/ttDownloader.ts
Normal file
58
lib/providers/ttDownloader.ts
Normal file
@@ -0,0 +1,58 @@
|
||||
import {getFetch} from '..';
|
||||
import {handleException} from '../decorators';
|
||||
import {BaseProvider, ExtractedInfo} from './baseProvider';
|
||||
import bind from 'bind-decorator';
|
||||
|
||||
/**
|
||||
* @class TTDownloader
|
||||
*/
|
||||
export class TTDownloader extends BaseProvider {
|
||||
/**
|
||||
* @return {string}
|
||||
*/
|
||||
public resourceName(): string {
|
||||
return 'tt';
|
||||
}
|
||||
|
||||
public client = getFetch('https://ttdownloader.com');
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {string} url - Video TikTok URL
|
||||
* @return {Promise<ExtractedInfo>}
|
||||
*/
|
||||
@handleException
|
||||
@bind
|
||||
public async fetch(url: string): Promise<ExtractedInfo> {
|
||||
// getting token and cookies
|
||||
const firstResponse = await this.client('./');
|
||||
const token = (firstResponse.body
|
||||
.match(/name="token" value="(.*)?"/) as string[])[1];
|
||||
const videoResponse = await this.client.post('./req', {
|
||||
form: {
|
||||
'token': token,
|
||||
'format': '',
|
||||
'url': url,
|
||||
},
|
||||
headers: {
|
||||
'Origin': 'https://ttdownloader.com',
|
||||
'Referer': 'https://ttdownloader.com',
|
||||
'Cookie': firstResponse.headers['cookie'],
|
||||
},
|
||||
});
|
||||
|
||||
return this.extract(videoResponse.body);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {string} html - HTML Raw
|
||||
* @return {ExtractedInfo}
|
||||
*/
|
||||
extract(html: string): ExtractedInfo {
|
||||
console.log(html);
|
||||
return {
|
||||
'error': '',
|
||||
};
|
||||
}
|
||||
};
|
||||
@@ -1,4 +1,5 @@
|
||||
import {tikmateFetch} from '../..';
|
||||
import {getProvider} from '..';
|
||||
import type {BaseProvider} from '../baseProvider';
|
||||
|
||||
export const deObfuscate = (html: string): string => {
|
||||
if (/error/gi.test(html)) {
|
||||
@@ -30,7 +31,8 @@ export const matchLink = (raw: string): string[] | null => {
|
||||
export const matchTikmateDownload = (raw: string): string[] => {
|
||||
const links = matchLink(raw) as string[];
|
||||
const urls = raw.match(/\/download.php\?token=(.*?)"/gi)
|
||||
?.map((url) => tikmateFetch.defaults.options.prefixUrl.slice(0, -1)+
|
||||
?.map((url) => (getProvider('tikmate') as BaseProvider).client.
|
||||
defaults.options.prefixUrl.slice(0, -1)+
|
||||
url.slice(0, -3));
|
||||
|
||||
return [links[0]].concat(urls as string[]);
|
||||
|
||||
@@ -11,12 +11,13 @@
|
||||
"@typescript-eslint/eslint-plugin": "^5.3.0",
|
||||
"@typescript-eslint/parser": "^5.3.0",
|
||||
"@vercel/node": "^1.12.1",
|
||||
"bind-decorator": "^1.0.11",
|
||||
"eslint": "^8.2.0",
|
||||
"eslint-config-google": "^0.14.0",
|
||||
"typescript": "^4.4.4"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "npm run lint && echo build",
|
||||
"build": "echo build",
|
||||
"lint": "eslint \"./lib/**/*.ts\" \"./types/*.ts\" \"./api/**/*.ts\" --fix"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
"skipLibCheck": true,
|
||||
"skipDefaultLibCheck": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"noImplicitAny": true,
|
||||
"experimentalDecorators": true
|
||||
},
|
||||
"exclude": ["node_modules", "dist"]
|
||||
|
||||
@@ -239,6 +239,11 @@ balanced-match@^1.0.0:
|
||||
resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz"
|
||||
integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
|
||||
|
||||
bind-decorator@^1.0.11:
|
||||
version "1.0.11"
|
||||
resolved "https://registry.yarnpkg.com/bind-decorator/-/bind-decorator-1.0.11.tgz#e41bc06a1f65dd9cec476c91c5daf3978488252f"
|
||||
integrity sha1-5BvAah9l3ZzsR2yRxdrzl4SIJS8=
|
||||
|
||||
brace-expansion@^1.1.7:
|
||||
version "1.1.11"
|
||||
resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz"
|
||||
|
||||
Reference in New Issue
Block a user