Loading snippets...
downloader video/foto TikTok tanpa watermark, built with Node.js Support video, slideshow/foto, audio, trending feed, user feed, music feed, search, dan stories. Provider: tikwm.com
/**
*
* base: https://www.tikwm.com
* Creator: ShanMolvyr
* reupload/modif cantumkan sumber ini woii parah
*
* Note: cek https://snippet.vyr.my.id/shanmolvyr/tiktok-downloader/README.md
* Sumber Scraper: https://whatsapp.com/channel/0029VbB4Kw8EFeXfeExaXc3Q
* "Kalau kamu benar seorang developer, kamu pasti paham bahwa credit bukan beban. Modifikasi sesukamu, jadikan API sesukamu, reupload pun silakan. Tapi jangan hilangkan sumber. Karena menghargai karya orang lain adalah etika, bukan kelemahan."
*/
import axios from 'axios';
import qs from 'qs';
const BASE = 'https://www.tikwm.com';
const API = `${BASE}/api/`;
const CREDIT = { author: 'ShanMolvyr', github: 'https://github.com/Sanzzy111', provider: 'tikwm.com' };
const HEADERS = {
'Accept': 'application/json, text/javascript, */*; q=0.01',
'Accept-Language': 'id-ID,id;q=0.9',
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
'Origin': BASE, 'Referer': BASE + '/',
'Sec-Ch-Ua': '"Not)A;Brand";v="24","Chromium";v="116"',
'Sec-Ch-Ua-Mobile': '?1', 'Sec-Ch-Ua-Platform': 'Android',
'Sec-Fetch-Dest': 'empty', 'Sec-Fetch-Mode': 'cors', 'Sec-Fetch-Site': 'same-origin',
'User-Agent': 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Mobile Safari/537.36',
'X-Requested-With': 'XMLHttpRequest'
};
const post = async (endpoint, body) => {
const r = await axios.post(`${API}${endpoint}`, qs.stringify(body), { headers: HEADERS });
if (r.data.code !== 0) throw new Error(r.data.msg || 'API error');
return r.data.data;
};
const fmtNum = n => { const x = parseInt(n); return isNaN(x) ? '0' : x.toLocaleString().replace(/,/g, '.'); };
const fmtDate = n => n ? new Date(n * 1000).toLocaleDateString('id-ID', { weekday:'long', day:'numeric', month:'long', year:'numeric', hour:'numeric', minute:'numeric', second:'numeric' }) : null;
const url = u => !u ? null : u.startsWith('http') ? u : BASE + u;
function parse(item) {
if (!item) return null;
const data = [];
if ((!item.size || item.size === 0) && Array.isArray(item.images) && item.images.length > 0) {
item.images.forEach(v => data.push({ type: 'photo', url: url(v) }));
} else {
if (item.wmplay) data.push({ type: 'watermark', url: url(item.wmplay) });
if (item.play) data.push({ type: 'nowatermark', url: url(item.play) });
if (item.hdplay) data.push({ type: 'nowatermark_hd', url: url(item.hdplay) });
}
const musicUrl = item.music ? url(item.music) : item.music_info?.play ? url(item.music_info.play) : null;
return {
title: item.title || '', taken_at: fmtDate(item.create_time), region: item.region || null,
id: item.id || item.video_id, duration: (item.duration || 0) + ' Seconds', cover: url(item.cover),
size_wm: item.wm_size || 0, size_nowm: item.size || 0, size_nowm_hd: item.hd_size || null,
data,
music_info: item.music_info ? { id: item.music_info.id, title: item.music_info.title, author: item.music_info.author, album: item.music_info.album || null, url: musicUrl } : null,
stats: { views: fmtNum(item.play_count), likes: fmtNum(item.digg_count), comment: fmtNum(item.comment_count), share: fmtNum(item.share_count), download: fmtNum(item.download_count) },
author: { id: item.author?.id, username: item.author?.unique_id, nickname: item.author?.nickname, avatar: url(item.author?.avatar) }
};
}
const out = d => console.log(JSON.stringify({ ...CREDIT, ...d }, null, 2));
const die = msg => { console.error(JSON.stringify({ ...CREDIT, status: false, error: msg }, null, 2)); process.exit(1); };
const [cmd, ...rest] = process.argv.slice(2);
if (!cmd) die('Usage: https://snippet.vyr.my.id/shanmolvyr/tiktok-downloader/README.md');
(async () => {
try {
if (cmd === 'download') {
const [turl] = rest;
if (!turl) die('Provide a TikTok URL');
const raw = await post('', { url: turl, count: 12, cursor: 0, web: 1, hd: 1 });
out({ status: true, data: parse(raw) });
} else if (cmd === 'trending') {
const [region = 'ID', count = 12, cursor = 0] = rest;
const raw = await post('feed/list', { region, count, cursor, web: 1, hd: 1 });
const items = Array.isArray(raw) ? raw : (raw.videos || []);
out({ status: true, cursor: Array.isArray(raw) ? null : (raw.cursor ?? null), hasMore: Array.isArray(raw) ? null : (raw.hasMore ?? null), total: items.length, videos: items.map(parse).filter(Boolean) });
} else if (cmd === 'user-feed') {
const [unique_id, count = 12, cursor = 0] = rest;
if (!unique_id) die('Provide a username e.g. @tiktok');
const d = await post('user/posts', { unique_id, count, cursor, web: 1, hd: 1 });
out({ status: true, cursor: d.cursor ?? null, hasMore: d.hasMore ?? false, total: (d.videos || []).length, videos: (d.videos || []).map(parse).filter(Boolean) });
} else if (cmd === 'music-feed') {
const [music_id, count = 12, cursor = 0] = rest;
if (!music_id) die('Provide a music_id');
const d = await post('music/posts', { music_id, count, cursor, web: 1, hd: 1 });
out({ status: true, cursor: d.cursor ?? null, hasMore: d.hasMore ?? false, total: (d.videos || []).length, videos: (d.videos || []).map(parse).filter(Boolean) });
} else if (cmd === 'search') {
const [keywords, count = 12, cursor = 0] = rest;
if (!keywords) die('Provide keywords');
const d = await post('feed/search', { keywords, count, cursor, web: 1, hd: 1 });
out({ status: true, cursor: d.cursor ?? null, hasMore: d.hasMore ?? false, total: (d.videos || []).length, videos: (d.videos || []).map(parse).filter(Boolean) });
} else if (cmd === 'search-photo') {
const [keywords, count = 12, cursor = 0] = rest;
if (!keywords) die('Provide keywords');
const d = await post('photo/search', { keywords, count, cursor, web: 1, hd: 1 });
out({ status: true, cursor: d.cursor ?? null, hasMore: d.hasMore ?? false, total: (d.videos || []).length, videos: (d.videos || []).map(parse).filter(Boolean) });
} else if (cmd === 'stories') {
if (!rest.length) die('Provide at least one URL');
const videos = [];
for (let i = 0; i < rest.length; i++) {
try {
const raw = await post('', { url: rest[i], count: 12, cursor: 0, web: 1, hd: 1 });
const p = parse(raw);
if (p) videos.push(p);
} catch (e) { console.error(`[stories] Failed: ${rest[i]} — ${e.message}`); }
if (i < rest.length - 1) await new Promise(r => setTimeout(r, 1000));
}
out({ status: true, total: videos.length, videos });
} else {
die(`Unknown command: "${cmd}"`);
}
} catch (e) { die(e.message); }
})();
bashnpm install axios qs
bashnode tikwm.js download https://www.tiktok.com/@user/video/xxx node tikwm.js trending ID node tikwm.js search kucing node tikwm.js stories https://vt.tiktok.com/xxx https://vt.tiktok.com/yyy node tikwm.js user-feed @tiktok