feat: Add downloadId parameter for progress monitoring

This commit is contained in:
Peifan Li
2025-12-08 13:42:49 -05:00
parent b55c34e5d0
commit 48e3821ed3
3 changed files with 93 additions and 12 deletions

View File

@@ -198,7 +198,8 @@ export const downloadVideo = async (
firstPartUrl, firstPartUrl,
1, 1,
videosNumber, videosNumber,
title || "Bilibili Video" title || "Bilibili Video",
downloadId
); );
// Add to collection if needed // Add to collection if needed
@@ -240,7 +241,8 @@ export const downloadVideo = async (
videoUrl, videoUrl,
1, 1,
1, 1,
"" // seriesTitle not used when totalParts is 1 "", // seriesTitle not used when totalParts is 1
downloadId
); );
if (result.success) { if (result.success) {

View File

@@ -21,9 +21,10 @@ export type {
export async function downloadBilibiliVideo( export async function downloadBilibiliVideo(
url: string, url: string,
videoPath: string, videoPath: string,
thumbnailPath: string thumbnailPath: string,
downloadId?: string
): Promise<BilibiliVideoInfo> { ): Promise<BilibiliVideoInfo> {
return BilibiliDownloader.downloadVideo(url, videoPath, thumbnailPath); return BilibiliDownloader.downloadVideo(url, videoPath, thumbnailPath, downloadId);
} }
// Helper function to check if a Bilibili video has multiple parts // Helper function to check if a Bilibili video has multiple parts
@@ -51,9 +52,10 @@ export async function downloadSingleBilibiliPart(
url: string, url: string,
partNumber: number, partNumber: number,
totalParts: number, totalParts: number,
seriesTitle: string seriesTitle: string,
downloadId?: string
): Promise<DownloadResult> { ): Promise<DownloadResult> {
return BilibiliDownloader.downloadSinglePart(url, partNumber, totalParts, seriesTitle); return BilibiliDownloader.downloadSinglePart(url, partNumber, totalParts, seriesTitle, downloadId);
} }
// Helper function to download all videos from a Bilibili collection or series // Helper function to download all videos from a Bilibili collection or series

View File

@@ -88,11 +88,21 @@ export class BilibiliDownloader {
} }
} }
// Helper function to format bytes
private static formatBytes(bytes: number): string {
if (bytes === 0) return "0 B";
const k = 1024;
const sizes = ["B", "KiB", "MiB", "GiB", "TiB"];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return Math.round((bytes / Math.pow(k, i)) * 100) / 100 + " " + sizes[i];
}
// Helper function to download Bilibili video // Helper function to download Bilibili video
static async downloadVideo( static async downloadVideo(
url: string, url: string,
videoPath: string, videoPath: string,
thumbnailPath: string thumbnailPath: string,
downloadId?: string
): Promise<BilibiliVideoInfo> { ): Promise<BilibiliVideoInfo> {
const tempDir = path.join(VIDEOS_DIR, `temp_${Date.now()}_${Math.floor(Math.random() * 10000)}`); const tempDir = path.join(VIDEOS_DIR, `temp_${Date.now()}_${Math.floor(Math.random() * 10000)}`);
@@ -102,6 +112,52 @@ export class BilibiliDownloader {
console.log("Downloading Bilibili video to temp directory:", tempDir); console.log("Downloading Bilibili video to temp directory:", tempDir);
// Start monitoring progress
let progressInterval: NodeJS.Timeout | undefined;
if (downloadId) {
let lastSize = 0;
let lastUpdateTime = Date.now();
progressInterval = setInterval(() => {
try {
const files = fs.readdirSync(tempDir);
const videoFile = files.find((file: string) => file.endsWith(".mp4"));
if (videoFile) {
const filePath = path.join(tempDir, videoFile);
if (fs.existsSync(filePath)) {
const stats = fs.statSync(filePath);
const currentSize = stats.size;
const currentTime = Date.now();
const timeDiff = (currentTime - lastUpdateTime) / 1000; // seconds
if (timeDiff > 0 && currentSize > lastSize) {
// Calculate speed (bytes per second)
const bytesPerSecond = (currentSize - lastSize) / timeDiff;
// Format speed
const speedStr = this.formatBytes(bytesPerSecond) + "/s";
// Format downloaded size
const downloadedSizeStr = this.formatBytes(currentSize);
// Update progress
storageService.updateActiveDownload(downloadId, {
downloadedSize: downloadedSizeStr,
speed: speedStr,
});
}
lastSize = currentSize;
lastUpdateTime = currentTime;
}
}
} catch (error) {
// Ignore errors during monitoring
}
}, 500);
}
// Download the video using the package // Download the video using the package
await downloadByVedioPath({ await downloadByVedioPath({
url: url, url: url,
@@ -109,6 +165,11 @@ export class BilibiliDownloader {
folder: tempDir, folder: tempDir,
}); });
// Stop progress monitoring
if (progressInterval) {
clearInterval(progressInterval);
}
console.log("Download completed, checking for video file"); console.log("Download completed, checking for video file");
// Find the downloaded file // Find the downloaded file
@@ -123,8 +184,20 @@ export class BilibiliDownloader {
console.log("Found video file:", videoFile); console.log("Found video file:", videoFile);
// Move the file to the desired location // Get final file size for progress update
const tempVideoPath = path.join(tempDir, videoFile); const tempVideoPath = path.join(tempDir, videoFile);
if (downloadId && fs.existsSync(tempVideoPath)) {
const stats = fs.statSync(tempVideoPath);
const finalSize = this.formatBytes(stats.size);
storageService.updateActiveDownload(downloadId, {
downloadedSize: finalSize,
totalSize: finalSize,
progress: 100,
speed: "0 B/s",
});
}
// Move the file to the desired location
fs.moveSync(tempVideoPath, videoPath, { overwrite: true }); fs.moveSync(tempVideoPath, videoPath, { overwrite: true });
console.log("Moved video file to:", videoPath); console.log("Moved video file to:", videoPath);
@@ -424,7 +497,8 @@ export class BilibiliDownloader {
url: string, url: string,
partNumber: number, partNumber: number,
totalParts: number, totalParts: number,
seriesTitle: string seriesTitle: string,
downloadId?: string
): Promise<DownloadResult> { ): Promise<DownloadResult> {
try { try {
console.log( console.log(
@@ -451,7 +525,8 @@ export class BilibiliDownloader {
const bilibiliInfo = await BilibiliDownloader.downloadVideo( const bilibiliInfo = await BilibiliDownloader.downloadVideo(
url, url,
videoPath, videoPath,
thumbnailPath thumbnailPath,
downloadId
); );
if (!bilibiliInfo) { if (!bilibiliInfo) {
@@ -642,7 +717,8 @@ export class BilibiliDownloader {
videoUrl, videoUrl,
videoNumber, videoNumber,
videos.length, videos.length,
title || "Collection" title || "Collection",
downloadId
); );
// If download was successful, add to collection // If download was successful, add to collection
@@ -721,7 +797,8 @@ export class BilibiliDownloader {
partUrl, partUrl,
part, part,
totalParts, totalParts,
seriesTitle seriesTitle,
downloadId
); );
// If download was successful and we have a collection ID, add to collection // If download was successful and we have a collection ID, add to collection