Back to Home
Gistify Snippet
kyiov
3d ago·1 file(s)
Public

TikTok Media Scraper & Downloader TikWM API

Mengimplementasikan klien API TikWM untuk mengunduh video TikTok tanpa watermark, mengekstrak metadata, gambar multi-slide, dan audio latar. Mendukung pencarian video dan feed trending global.

#tiktok#scraper#downloader#tikwm#nodejs#api-client
4
Raw
tikwm.jsjavascript
198 lines
1/**
2 * @fileoverview Modul Downloader & Scraper TikTok Tanpa Watermark (TikWM API).
3 *
4 * Mengimplementasikan antarmuka klien API TikWM untuk mengekstrak metadata, video tanpa watermark (HD/SD),
5 * format gambar multi-slide, serta audio latar (MP3) dari video TikTok.
6 * Didukung fitur pencarian video berbasis kata kunci dan feed trending global.
7 *
8 * @module scrapers/tiktok
9 * @version 2.0.0
10 * @author kyiov
11 * @license MIT
12 */
13
14import { pathToFileURL } from 'node:url'
15
16/**
17 * @typedef {Object} TikTokAuthor
18 * @property {string} id - Pengenal unik pembuat konten
19 * @property {string} unique_id - Username handle TikTok (@username)
20 * @property {string} nickname - Nama tampilan profil
21 * @property {string} avatar - Tautan foto profil
22 */
23
24/**
25 * @typedef {Object} TikTokMedia
26 * @property {'video'|'image'} type - Jenis media konten
27 * @property {number} [duration] - Durasi video dalam detik
28 * @property {string} [play] - URL unduhan video tanpa watermark
29 * @property {string} [hdplay] - URL unduhan video kualitas HD tanpa watermark
30 * @property {string} [wmplay] - URL unduhan video dengan watermark asli
31 * @property {string[]} [images] - Daftar tautan gambar untuk post slide
32 */
33
34/**
35 * @typedef {Object} TikTokDownloadResult
36 * @property {string} id - ID unik video TikTok
37 * @property {string} title - Judul atau takarir (caption) video
38 * @property {string} cover - URL gambar sampul (thumbnail)
39 * @property {TikTokMedia} media - Objek aset media (video/gambar)
40 * @property {TikTokAuthor} author - Informasi pembuat konten
41 * @property {Object} music - Metadata musik/audio latar
42 * @property {number} views - Jumlah penayangan
43 * @property {number} likes - Jumlah suka
44 * @property {number} comments - Jumlah komentar
45 * @property {number} shares - Jumlah pembagian
46 */
47
48export class TikWMScraper {
49 /**
50 * Menginisialisasi klien TikWM dengan base URL dan konfigurasi header default.
51 */
52 constructor() {
53 this.baseUrl = 'https://tikwm.com'
54 this.headers = {
55 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
56 'User-Agent':
57 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36',
58 'Accept': 'application/json, text/javascript, */*; q=0.01'
59 }
60 }
61
62 /**
63 * Mengunduh metadata video TikTok beserta tautan media tanpa watermark.
64 *
65 * @param {string} url - Tautan URL postingan TikTok lengkap atau format pendek (vt.tiktok.com)
66 * @returns {Promise<TikTokDownloadResult>} Metadata lengkap dan tautan download media
67 * @throws {Error} Jika URL tidak valid atau video gagal diekstrak
68 */
69 async download(url) {
70 if (!url) throw new Error('Parameter URL video TikTok wajib disertakan.')
71
72 const params = new URLSearchParams({ url, hd: '1' })
73 const res = await fetch(`${this.baseUrl}/api/`, {
74 method: 'POST',
75 headers: this.headers,
76 body: params
77 })
78
79 if (!res.ok) throw new Error(`HTTP Error: ${res.status}`)
80 const json = await res.json()
81
82 if (json.code !== 0 || !json.data) {
83 throw new Error(json.msg || 'Gagal mengekstrak data video dari URL tersebut.')
84 }
85
86 const data = json.data
87 const isImage = data.duration === 0 && Array.isArray(data.images) && data.images.length > 0
88
89 return {
90 id: data.id,
91 title: data.title || '',
92 cover: data.cover || '',
93 media: isImage
94 ? {
95 type: 'image',
96 images: data.images,
97 image_count: data.images.length
98 }
99 : {
100 type: 'video',
101 duration: data.duration,
102 play: data.play,
103 hdplay: data.hdplay || data.play,
104 wmplay: data.wmplay,
105 size: data.size,
106 hd_size: data.hd_size
107 },
108 author: {
109 id: data.author?.id,
110 unique_id: data.author?.unique_id,
111 nickname: data.author?.nickname,
112 avatar: data.author?.avatar
113 },
114 music: data.music_info || {},
115 views: data.play_count || 0,
116 likes: data.digg_count || 0,
117 comments: data.comment_count || 0,
118 shares: data.share_count || 0,
119 created_at: data.create_time
120 }
121 }
122
123 /**
124 * Mencari video TikTok berdasarkan kata kunci tertentu.
125 *
126 * @param {string} keywords - Kata kunci penelusuran video
127 * @param {number} [count=10] - Jumlah video maksimum yang ingin diambil
128 * @returns {Promise<Array<Object>>} Daftar video yang cocok dengan kata kunci
129 * @throws {Error} Jika kata kunci kosong atau penelusuran gagal
130 */
131 async search(keywords, count = 10) {
132 if (!keywords) throw new Error('Kata kunci pencarian wajib disertakan.')
133
134 const params = new URLSearchParams({
135 keywords,
136 count: String(count),
137 cursor: '0',
138 hd: '1'
139 })
140
141 const res = await fetch(`${this.baseUrl}/api/feed/search/`, {
142 method: 'POST',
143 headers: this.headers,
144 body: params
145 })
146
147 if (!res.ok) throw new Error(`HTTP Error: ${res.status}`)
148 const json = await res.json()
149
150 if (json.code !== 0 || !json.data?.videos) {
151 throw new Error(json.msg || 'Tidak ditemukan video yang sesuai dengan kata kunci.')
152 }
153
154 return json.data.videos.map((item) => ({
155 id: item.video_id,
156 title: item.title,
157 cover: item.cover,
158 play: item.play,
159 duration: item.duration,
160 author: {
161 id: item.author?.id,
162 unique_id: item.author?.unique_id,
163 nickname: item.author?.nickname,
164 avatar: item.author?.avatar
165 },
166 views: item.play_count,
167 likes: item.digg_count
168 }))
169 }
170}
171
172export const tikwm = new TikWMScraper()
173export default tikwm
174
175// Eksekusi mandiri untuk pengujian langsung tanpa argumen CLI
176if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
177 try {
178 console.log('Menguji pencarian video TikTok...')
179 const searchResults = await tikwm.search('nature', 2)
180 console.log('Hasil Pencarian:', JSON.stringify(searchResults, null, 2))
181
182 if (searchResults.length > 0) {
183 const first = searchResults[0]
184 const videoUrl = `https://www.tiktok.com/@${first.author.unique_id}/video/${first.id}`
185 console.log(`Menguji ekstraksi video langsung: ${videoUrl}`)
186 const downloadData = await tikwm.download(videoUrl)
187 console.log('Hasil Ekstraksi Video:', {
188 id: downloadData.id,
189 title: downloadData.title,
190 play: downloadData.media.play,
191 author: downloadData.author.unique_id
192 })
193 }
194 } catch (err) {
195 console.error('Galat eksekusi TikWM:', err.message || err)
196 }
197}
198
Discussion & Comments0

No comments yet — be the first to leave feedback or start a code discussion.

Sign in with your GitHub account to write comments and join the discussion.