mirror of
https://github.com/streamyfin/streamyfin.git
synced 2026-06-12 17:00:23 +01:00
The storage bar showed 0.00% because calculateTotalDownloadedSize summed the stored videoFileSize, which is 0 for items downloaded before the size was recorded (or when fileInfo.size was undefined). Stat the file on disk and fall back to the stored value.
117 lines
3.6 KiB
TypeScript
117 lines
3.6 KiB
TypeScript
import { Directory, File, Paths } from "expo-file-system";
|
|
import { getAllDownloadedItems, getDownloadedItemById } from "./database";
|
|
import type { DownloadedItem } from "./types";
|
|
import { filePathToUri } from "./utils";
|
|
|
|
/**
|
|
* Delete a video file and all associated files (subtitles, trickplay, etc.)
|
|
*/
|
|
export function deleteVideoFile(filePath: string): void {
|
|
try {
|
|
const videoFile = new File(filePathToUri(filePath));
|
|
if (videoFile.exists) {
|
|
videoFile.delete();
|
|
console.log(`[DELETE] Video file deleted: ${filePath}`);
|
|
}
|
|
} catch (error) {
|
|
console.error("Failed to delete video file:", error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Delete all associated files for a downloaded item
|
|
* Includes: video, subtitles, trickplay images
|
|
*/
|
|
export function deleteAllAssociatedFiles(item: DownloadedItem): void {
|
|
try {
|
|
// Delete video file
|
|
if (item.videoFilePath) {
|
|
deleteVideoFile(item.videoFilePath);
|
|
}
|
|
|
|
// Delete subtitle files
|
|
if (item.mediaSource?.MediaStreams) {
|
|
for (const stream of item.mediaSource.MediaStreams) {
|
|
if (
|
|
stream.Type === "Subtitle" &&
|
|
stream.DeliveryMethod === "External" &&
|
|
stream.DeliveryUrl
|
|
) {
|
|
try {
|
|
const subtitleFilename = stream.DeliveryUrl.split("/").pop();
|
|
if (subtitleFilename) {
|
|
const subtitleFile = new File(Paths.document, subtitleFilename);
|
|
if (subtitleFile.exists) {
|
|
subtitleFile.delete();
|
|
console.log(`[DELETE] Subtitle deleted: ${subtitleFilename}`);
|
|
}
|
|
}
|
|
} catch (error) {
|
|
console.error("[DELETE] Failed to delete subtitle:", error);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Delete trickplay directory
|
|
if (item.trickPlayData?.path) {
|
|
try {
|
|
const trickplayDirName = item.trickPlayData.path.split("/").pop();
|
|
if (trickplayDirName) {
|
|
const trickplayDir = new Directory(Paths.document, trickplayDirName);
|
|
if (trickplayDir.exists) {
|
|
trickplayDir.delete();
|
|
console.log(
|
|
`[DELETE] Trickplay directory deleted: ${trickplayDirName}`,
|
|
);
|
|
}
|
|
}
|
|
} catch (error) {
|
|
console.error("[DELETE] Failed to delete trickplay directory:", error);
|
|
}
|
|
}
|
|
} catch (error) {
|
|
console.error("[DELETE] Error deleting associated files:", error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get the size of a downloaded item by ID
|
|
* Includes video file size and trickplay data size
|
|
*/
|
|
export function getDownloadedItemSize(id: string): number {
|
|
const item = getDownloadedItemById(id);
|
|
if (!item) return 0;
|
|
|
|
const videoSize = item.videoFileSize || 0;
|
|
const trickplaySize = item.trickPlayData?.size || 0;
|
|
|
|
return videoSize + trickplaySize;
|
|
}
|
|
|
|
/**
|
|
* Calculate total size of all downloaded items
|
|
*/
|
|
export function calculateTotalDownloadedSize(): number {
|
|
const items = getAllDownloadedItems();
|
|
return items.reduce((sum, item) => {
|
|
// Read the live file size on disk so the total reflects actual usage and
|
|
// self-heals items whose stored videoFileSize is 0 (old schema, or
|
|
// `fileInfo.size` was undefined at download time). Fall back to the stored
|
|
// value if the file can't be stat'd.
|
|
if (item.videoFilePath) {
|
|
try {
|
|
const file = new File(filePathToUri(item.videoFilePath));
|
|
if (file.exists) {
|
|
return sum + (file.size ?? item.videoFileSize ?? 0);
|
|
}
|
|
} catch (error) {
|
|
console.warn("Failed to stat downloaded file for size:", error);
|
|
}
|
|
}
|
|
return sum + (item.videoFileSize ?? 0);
|
|
}, 0);
|
|
}
|