@xbibzlibrary/tiktokscrap
Version:
Powerful TikTok Scraper and Downloader Library
133 lines (118 loc) • 3.94 kB
text/typescript
import BaseDownloader from './base';
import { TikTokVideo, TikTokDownloadOptions, TikTokScrapResult } from '../types';
import path from 'path';
export class VideoDownloader extends BaseDownloader {
public async downloadVideo(
video: TikTokVideo,
options: TikTokDownloadOptions = {}
): Promise<TikTokScrapResult<string>> {
return this.executeDownload(async () => {
const { outputDir = './downloads', filename } = options;
if (!video.downloadAddr) {
throw new Error('Video download URL not available');
}
const videoFilename = this.generateFilename(video.downloadAddr, '.mp4', { filename });
const outputPath = this.getOutputPath(outputDir, videoFilename);
return this.downloadFile(video.downloadAddr, outputPath, options);
}, `Download video: ${video.id}`);
}
public async downloadVideoByUrl(
url: string,
options: TikTokDownloadOptions = {}
): Promise<TikTokScrapResult<string>> {
return this.executeDownload(async () => {
// This would require importing the VideoScraper, but to avoid circular dependencies,
// we'll assume the URL is valid and extract the video ID
const videoId = this.extractVideoIdFromUrl(url);
if (!videoId) {
throw new Error('Could not extract video ID from URL');
}
// In a real implementation, you would use the VideoScraper to get the video data
// For now, we'll construct a minimal video object with the URL
const video: TikTokVideo = {
id: videoId,
text: '',
createTime: 0,
author: {
id: '',
uniqueId: '',
nickname: '',
avatarUrl: '',
signature: '',
verified: false,
following: 0,
fans: 0,
heart: 0,
video: 0,
digg: 0,
privateAccount: false,
isSecret: false,
secUid: ''
},
music: {
id: '',
title: '',
author: '',
album: '',
playUrl: '',
coverLarge: '',
coverMedium: '',
coverThumb: '',
duration: 0
},
stats: {
digg: 0,
share: 0,
comment: 0,
play: 0
},
videoMeta: {
width: 0,
height: 0,
duration: 0,
cover: '',
dynamicCover: '',
originCover: ''
},
downloadAddr: url,
webVideoUrl: url,
hashtags: [],
mentions: [],
effects: [],
isAd: false,
commentsDisabled: false,
duetEnabled: false,
stitchEnabled: false,
secret: false,
forFriend: false,
digged: false,
itemCommentStatus: 0
};
const result = await this.downloadVideo(video, options);
if (result.success && result.data) {
return result.data;
} else {
throw new Error(result.error || 'Failed to download video by URL');
}
}, `Download video by URL: ${url}`);
}
public async downloadVideoCover(
video: TikTokVideo,
options: TikTokDownloadOptions = {}
): Promise<TikTokScrapResult<string>> {
return this.executeDownload(async () => {
const { outputDir = './downloads', filename } = options;
if (!video.videoMeta.cover) {
throw new Error('Video cover URL not available');
}
const coverFilename = this.generateFilename(video.videoMeta.cover, '.jpg', { filename });
const outputPath = this.getOutputPath(outputDir, coverFilename);
return this.downloadFile(video.videoMeta.cover, outputPath, options);
}, `Download video cover: ${video.id}`);
}
private extractVideoIdFromUrl(url: string): string | null {
const match = url.match(/\/video\/(\d+)/);
return match ? match[1] : null;
}
}
export default VideoDownloader;