diff --git a/backend/src/controllers/cleanupController.ts b/backend/src/controllers/cleanupController.ts index c99c8e4..76ae0e4 100644 --- a/backend/src/controllers/cleanupController.ts +++ b/backend/src/controllers/cleanupController.ts @@ -5,7 +5,6 @@ import { VIDEOS_DIR } from "../config/paths"; import { ValidationError } from "../errors/DownloadErrors"; import * as storageService from "../services/storageService"; import { logger } from "../utils/logger"; -import { successResponse } from "../utils/response"; /** * Clean up temporary download files (.ytdl, .part) @@ -67,13 +66,9 @@ export const cleanupTempFiles = async ( // Start cleanup from VIDEOS_DIR await cleanupDirectory(VIDEOS_DIR); - res.status(200).json( - successResponse( - { - deletedCount, - ...(errors.length > 0 && { errors }), - }, - `Cleaned up ${deletedCount} temporary files` - ) - ); + // Return format expected by frontend: { deletedCount, errors? } + res.status(200).json({ + deletedCount, + ...(errors.length > 0 && { errors }), + }); }; diff --git a/backend/src/controllers/collectionController.ts b/backend/src/controllers/collectionController.ts index c161ede..a84e65d 100644 --- a/backend/src/controllers/collectionController.ts +++ b/backend/src/controllers/collectionController.ts @@ -2,23 +2,26 @@ import { Request, Response } from "express"; import { NotFoundError, ValidationError } from "../errors/DownloadErrors"; import * as storageService from "../services/storageService"; import { Collection } from "../services/storageService"; -import { successMessage, successResponse } from "../utils/response"; +import { successMessage } from "../utils/response"; /** * Get all collections * Errors are automatically handled by asyncHandler middleware + * Note: Returns array directly for backward compatibility with frontend */ export const getCollections = async ( _req: Request, res: Response ): Promise => { const collections = storageService.getCollections(); - res.json(successResponse(collections)); + // Return array directly for backward compatibility (frontend expects response.data to be Collection[]) + res.json(collections); }; /** * Create a new collection * Errors are automatically handled by asyncHandler middleware + * Note: Returns collection object directly for backward compatibility with frontend */ export const createCollection = async ( req: Request, @@ -49,19 +52,20 @@ export const createCollection = async ( videoId ); if (updatedCollection) { - res - .status(201) - .json(successResponse(updatedCollection, "Collection created")); + // Return collection object directly for backward compatibility + res.status(201).json(updatedCollection); return; } } - res.status(201).json(successResponse(newCollection, "Collection created")); + // Return collection object directly for backward compatibility + res.status(201).json(newCollection); }; /** * Update a collection * Errors are automatically handled by asyncHandler middleware + * Note: Returns collection object directly for backward compatibility with frontend */ export const updateCollection = async ( req: Request, @@ -102,7 +106,8 @@ export const updateCollection = async ( throw new NotFoundError("Collection", id); } - res.json(successResponse(updatedCollection)); + // Return collection object directly for backward compatibility + res.json(updatedCollection); }; /** diff --git a/backend/src/controllers/downloadController.ts b/backend/src/controllers/downloadController.ts index bd94a43..7056af3 100644 --- a/backend/src/controllers/downloadController.ts +++ b/backend/src/controllers/downloadController.ts @@ -1,7 +1,7 @@ import { Request, Response } from "express"; import downloadManager from "../services/downloadManager"; import * as storageService from "../services/storageService"; -import { successMessage, successResponse } from "../utils/response"; +import { successMessage } from "../utils/response"; /** * Cancel a download @@ -44,13 +44,15 @@ export const clearQueue = async ( /** * Get download history * Errors are automatically handled by asyncHandler middleware + * Note: Returns array directly for backward compatibility with frontend */ export const getDownloadHistory = async ( _req: Request, res: Response ): Promise => { const history = storageService.getDownloadHistory(); - res.status(200).json(successResponse(history)); + // Return array directly for backward compatibility (frontend expects response.data to be DownloadHistoryItem[]) + res.status(200).json(history); }; /** diff --git a/backend/src/controllers/scanController.ts b/backend/src/controllers/scanController.ts index 50c5894..7ea85fc 100644 --- a/backend/src/controllers/scanController.ts +++ b/backend/src/controllers/scanController.ts @@ -234,5 +234,6 @@ export const scanFiles = async ( const message = `Scan complete. Added ${addedCount} new videos. Deleted ${deletedCount} missing videos.`; logger.info(message); - res.status(200).json(successResponse({ addedCount, deletedCount }, message)); + // Return format expected by frontend: { addedCount, deletedCount } + res.status(200).json({ addedCount, deletedCount }); }; diff --git a/backend/src/controllers/settingsController.ts b/backend/src/controllers/settingsController.ts index 5284860..b0f5297 100644 --- a/backend/src/controllers/settingsController.ts +++ b/backend/src/controllers/settingsController.ts @@ -11,7 +11,7 @@ import { NotFoundError, ValidationError } from "../errors/DownloadErrors"; import downloadManager from "../services/downloadManager"; import * as storageService from "../services/storageService"; import { logger } from "../utils/logger"; -import { successMessage, successResponse } from "../utils/response"; +import { successMessage } from "../utils/response"; interface Settings { loginEnabled: boolean; @@ -57,6 +57,7 @@ const defaultSettings: Settings = { /** * Get application settings * Errors are automatically handled by asyncHandler middleware + * Note: Returns data directly for backward compatibility with frontend */ export const getSettings = async ( _req: Request, @@ -67,7 +68,8 @@ export const getSettings = async ( // If empty (first run), save defaults if (Object.keys(settings).length === 0) { storageService.saveSettings(defaultSettings); - res.json(successResponse(defaultSettings)); + // Return data directly for backward compatibility + res.json(defaultSettings); return; } @@ -76,7 +78,8 @@ export const getSettings = async ( // Do not send the hashed password to the frontend const { password, ...safeSettings } = mergedSettings; - res.json(successResponse({ ...safeSettings, isPasswordSet: !!password })); + // Return data directly for backward compatibility + res.json({ ...safeSettings, isPasswordSet: !!password }); }; /** @@ -89,7 +92,8 @@ export const migrateData = async ( ): Promise => { const { runMigration } = await import("../services/migrationService"); const results = await runMigration(); - res.json(successResponse(results, "Migration completed")); + // Return format expected by frontend: { results: {...} } + res.json({ results }); }; /** @@ -128,7 +132,8 @@ export const deleteLegacyData = async ( } } - res.json(successResponse(results, "Legacy data deletion completed")); + // Return format expected by frontend: { results: { deleted: [], failed: [] } } + res.json({ results }); }; /** @@ -140,7 +145,8 @@ export const formatFilenames = async ( res: Response ): Promise => { const results = storageService.formatLegacyFilenames(); - res.json(successResponse(results, "Filenames formatted")); + // Return format expected by frontend: { results: {...} } + res.json({ results }); }; /** @@ -236,9 +242,11 @@ export const updateSettings = async ( // Apply settings immediately where possible downloadManager.setMaxConcurrentDownloads(newSettings.maxConcurrentDownloads); - res.json( - successResponse({ ...newSettings, password: undefined }, "Settings updated") - ); + // Return format expected by frontend: { success: true, settings: {...} } + res.json({ + success: true, + settings: { ...newSettings, password: undefined }, + }); }; /** @@ -255,7 +263,8 @@ export const getPasswordEnabled = async ( // Return true only if login is enabled AND a password is set const isEnabled = mergedSettings.loginEnabled && !!mergedSettings.password; - res.json(successResponse({ enabled: isEnabled })); + // Return format expected by frontend: { enabled: boolean } + res.json({ enabled: isEnabled }); }; /** @@ -272,20 +281,23 @@ export const verifyPassword = async ( const mergedSettings = { ...defaultSettings, ...settings }; if (!mergedSettings.loginEnabled) { - res.json(successResponse({ verified: true })); + // Return format expected by frontend: { success: boolean } + res.json({ success: true }); return; } if (!mergedSettings.password) { // If no password set but login enabled, allow access - res.json(successResponse({ verified: true })); + // Return format expected by frontend: { success: boolean } + res.json({ success: true }); return; } const isMatch = await bcrypt.compare(password, mergedSettings.password); if (isMatch) { - res.json(successResponse({ verified: true })); + // Return format expected by frontend: { success: boolean } + res.json({ success: true }); } else { throw new ValidationError("Incorrect password", "password"); } @@ -332,7 +344,8 @@ export const checkCookies = async ( const { DATA_DIR } = require("../config/paths"); const cookiesPath = path.join(DATA_DIR, "cookies.txt"); const exists = fs.existsSync(cookiesPath); - res.json(successResponse({ exists })); + // Return format expected by frontend: { exists: boolean } + res.json({ exists }); }; /** diff --git a/backend/src/controllers/subscriptionController.ts b/backend/src/controllers/subscriptionController.ts index fca6a37..d82aa52 100644 --- a/backend/src/controllers/subscriptionController.ts +++ b/backend/src/controllers/subscriptionController.ts @@ -2,7 +2,7 @@ import { Request, Response } from "express"; import { ValidationError } from "../errors/DownloadErrors"; import { subscriptionService } from "../services/subscriptionService"; import { logger } from "../utils/logger"; -import { successMessage, successResponse } from "../utils/response"; +import { successMessage } from "../utils/response"; /** * Create a new subscription @@ -23,19 +23,22 @@ export const createSubscription = async ( url, parseInt(interval) ); - res.status(201).json(successResponse(subscription, "Subscription created")); + // Return subscription object directly for backward compatibility + res.status(201).json(subscription); }; /** * Get all subscriptions * Errors are automatically handled by asyncHandler middleware + * Note: Returns array directly for backward compatibility with frontend */ export const getSubscriptions = async ( req: Request, res: Response ): Promise => { const subscriptions = await subscriptionService.listSubscriptions(); - res.json(successResponse(subscriptions)); + // Return array directly for backward compatibility (frontend expects response.data to be Subscription[]) + res.json(subscriptions); }; /** diff --git a/backend/src/controllers/videoController.ts b/backend/src/controllers/videoController.ts index 012e6f7..442b730 100644 --- a/backend/src/controllers/videoController.ts +++ b/backend/src/controllers/videoController.ts @@ -38,6 +38,7 @@ export const upload = multer({ storage: storage }); /** * Search for videos * Errors are automatically handled by asyncHandler middleware + * Note: Returns { results } format for backward compatibility with frontend */ export const searchVideos = async ( req: Request, @@ -57,7 +58,8 @@ export const searchVideos = async ( limit, offset ); - res.status(200).json(successResponse({ results })); + // Return { results } format for backward compatibility (frontend expects response.data.results) + res.status(200).json({ results }); }; /** @@ -85,7 +87,8 @@ export const checkVideoDownloadStatus = async ( const { id: sourceVideoId, platform } = extractSourceVideoId(videoUrl); if (!sourceVideoId) { - res.status(200).json(successResponse({ found: false })); + // Return object directly for backward compatibility (frontend expects response.data.found) + res.status(200).json({ found: false }); return; } @@ -100,47 +103,45 @@ export const checkVideoDownloadStatus = async ( if (!existingVideo) { // Video was deleted but not marked in download history, update it storageService.markVideoDownloadDeleted(downloadCheck.videoId); - res.status(200).json( - successResponse({ - found: true, - status: "deleted", - title: downloadCheck.title, - author: downloadCheck.author, - downloadedAt: downloadCheck.downloadedAt, - }) - ); + // Return object directly for backward compatibility + res.status(200).json({ + found: true, + status: "deleted", + title: downloadCheck.title, + author: downloadCheck.author, + downloadedAt: downloadCheck.downloadedAt, + }); return; } - res.status(200).json( - successResponse({ - found: true, - status: "exists", - videoId: downloadCheck.videoId, - title: downloadCheck.title || existingVideo.title, - author: downloadCheck.author || existingVideo.author, - downloadedAt: downloadCheck.downloadedAt, - videoPath: existingVideo.videoPath, - thumbnailPath: existingVideo.thumbnailPath, - }) - ); + // Return object directly for backward compatibility + res.status(200).json({ + found: true, + status: "exists", + videoId: downloadCheck.videoId, + title: downloadCheck.title || existingVideo.title, + author: downloadCheck.author || existingVideo.author, + downloadedAt: downloadCheck.downloadedAt, + videoPath: existingVideo.videoPath, + thumbnailPath: existingVideo.thumbnailPath, + }); return; } - res.status(200).json( - successResponse({ - found: true, - status: downloadCheck.status, - title: downloadCheck.title, - author: downloadCheck.author, - downloadedAt: downloadCheck.downloadedAt, - deletedAt: downloadCheck.deletedAt, - }) - ); + // Return object directly for backward compatibility + res.status(200).json({ + found: true, + status: downloadCheck.status, + title: downloadCheck.title, + author: downloadCheck.author, + downloadedAt: downloadCheck.downloadedAt, + deletedAt: downloadCheck.deletedAt, + }); return; } - res.status(200).json(successResponse({ found: false })); + // Return object directly for backward compatibility + res.status(200).json({ found: false }); }; // Download video @@ -476,18 +477,21 @@ export const downloadVideo = async ( /** * Get all videos * Errors are automatically handled by asyncHandler middleware + * Note: Returns array directly for backward compatibility with frontend */ export const getVideos = async ( _req: Request, res: Response ): Promise => { const videos = storageService.getVideos(); - res.status(200).json(successResponse(videos)); + // Return array directly for backward compatibility (frontend expects response.data to be Video[]) + res.status(200).json(videos); }; /** * Get video by ID * Errors are automatically handled by asyncHandler middleware + * Note: Returns video object directly for backward compatibility with frontend */ export const getVideoById = async ( req: Request, @@ -500,7 +504,8 @@ export const getVideoById = async ( throw new NotFoundError("Video", id); } - res.status(200).json(successResponse(video)); + // Return video object directly for backward compatibility (frontend expects response.data to be Video) + res.status(200).json(video); }; /** @@ -524,6 +529,7 @@ export const deleteVideo = async ( /** * Get download status * Errors are automatically handled by asyncHandler middleware + * Note: Returns status object directly for backward compatibility with frontend */ export const getDownloadStatus = async ( _req: Request, @@ -540,7 +546,8 @@ export const getDownloadStatus = async ( } }); } - res.status(200).json(successResponse(status)); + // Return status object directly for backward compatibility (frontend expects response.data to be DownloadStatus) + res.status(200).json(status); }; /** @@ -580,7 +587,8 @@ export const checkBilibiliParts = async ( const result = await downloadService.checkBilibiliVideoParts(videoId); - res.status(200).json(successResponse(result)); + // Return result object directly for backward compatibility (frontend expects response.data.success, response.data.videosNumber) + res.status(200).json(result); }; /** @@ -621,12 +629,14 @@ export const checkBilibiliCollection = async ( // Check if it's a collection or series const result = await downloadService.checkBilibiliCollectionOrSeries(videoId); - res.status(200).json(successResponse(result)); + // Return result object directly for backward compatibility (frontend expects response.data.success, response.data.type) + res.status(200).json(result); }; /** * Get video comments * Errors are automatically handled by asyncHandler middleware + * Note: Returns comments array directly for backward compatibility with frontend */ export const getVideoComments = async ( req: Request, @@ -636,7 +646,8 @@ export const getVideoComments = async ( const comments = await import("../services/commentService").then((m) => m.getComments(id) ); - res.status(200).json(successResponse(comments)); + // Return comments array directly for backward compatibility (frontend expects response.data to be Comment[]) + res.status(200).json(comments); }; /** @@ -741,9 +752,11 @@ export const rateVideo = async (req: Request, res: Response): Promise => { throw new NotFoundError("Video", id); } - res - .status(200) - .json(successResponse({ video: updatedVideo }, "Video rated successfully")); + // Return format expected by frontend: { success: true, video: ... } + res.status(200).json({ + success: true, + video: updatedVideo, + }); }; /** @@ -773,11 +786,11 @@ export const updateVideoDetails = async ( throw new NotFoundError("Video", id); } - res - .status(200) - .json( - successResponse({ video: updatedVideo }, "Video updated successfully") - ); + // Return format expected by frontend: { success: true, video: ... } + res.status(200).json({ + success: true, + video: updatedVideo, + }); }; /** @@ -864,11 +877,11 @@ export const refreshThumbnail = async ( // Return success with timestamp to bust cache const thumbnailUrl = `${newThumbnailPath}?t=${Date.now()}`; - res - .status(200) - .json( - successResponse({ thumbnailUrl }, "Thumbnail refreshed successfully") - ); + // Return format expected by frontend: { success: true, thumbnailUrl: ... } + res.status(200).json({ + success: true, + thumbnailUrl, + }); }; /** @@ -892,11 +905,11 @@ export const incrementViewCount = async ( lastPlayedAt: Date.now(), }); - res.status(200).json( - successResponse({ - viewCount: updatedVideo?.viewCount, - }) - ); + // Return format expected by frontend: { success: true, viewCount: ... } + res.status(200).json({ + success: true, + viewCount: updatedVideo?.viewCount, + }); }; /**