@@ -1956,6 +1956,58 @@ app.get('/api/dvr/storage', requireAuth, requireDvrAccess, (req, res) => {
19561956 }
19571957} ) ;
19581958
1959+ // --- FIX: Route Order Correction ---
1960+ // Specific bulk-delete routes are now placed BEFORE dynamic routes with :id
1961+ app . delete ( '/api/dvr/jobs/all' , requireAuth , requireDvrAccess , ( req , res ) => {
1962+ const userId = req . session . userId ;
1963+ console . log ( `[DVR_API] Clearing all scheduled/historical jobs for user ${ userId } .` ) ;
1964+
1965+ db . all ( "SELECT id FROM dvr_jobs WHERE user_id = ? AND status = 'scheduled'" , [ userId ] , ( err , scheduledJobs ) => {
1966+ if ( err ) {
1967+ return res . status ( 500 ) . json ( { error : 'Could not fetch jobs to cancel.' } ) ;
1968+ }
1969+ scheduledJobs . forEach ( job => {
1970+ if ( activeDvrJobs . has ( job . id ) ) {
1971+ activeDvrJobs . get ( job . id ) ?. cancel ( ) ;
1972+ activeDvrJobs . delete ( job . id ) ;
1973+ }
1974+ } ) ;
1975+
1976+ db . run ( "DELETE FROM dvr_jobs WHERE user_id = ?" , [ userId ] , function ( err ) {
1977+ if ( err ) {
1978+ return res . status ( 500 ) . json ( { error : 'Could not clear jobs from database.' } ) ;
1979+ }
1980+ res . json ( { success : true , deletedCount : this . changes } ) ;
1981+ } ) ;
1982+ } ) ;
1983+ } ) ;
1984+
1985+ app . delete ( '/api/dvr/recordings/all' , requireAuth , requireDvrAccess , ( req , res ) => {
1986+ const userId = req . session . userId ;
1987+ console . log ( `[DVR_API] Deleting all completed recordings for user ${ userId } .` ) ;
1988+
1989+ db . all ( "SELECT id, filePath FROM dvr_recordings WHERE user_id = ?" , [ userId ] , ( err , recordings ) => {
1990+ if ( err ) {
1991+ return res . status ( 500 ) . json ( { error : 'Could not fetch recordings to delete.' } ) ;
1992+ }
1993+
1994+ recordings . forEach ( rec => {
1995+ if ( fs . existsSync ( rec . filePath ) ) {
1996+ fs . unlink ( rec . filePath , ( unlinkErr ) => {
1997+ if ( unlinkErr ) console . error ( `[DVR_API] Failed to delete file ${ rec . filePath } :` , unlinkErr ) ;
1998+ } ) ;
1999+ }
2000+ } ) ;
2001+
2002+ db . run ( "DELETE FROM dvr_recordings WHERE user_id = ?" , [ userId ] , function ( err ) {
2003+ if ( err ) {
2004+ return res . status ( 500 ) . json ( { error : 'Could not clear recordings from database.' } ) ;
2005+ }
2006+ res . json ( { success : true , deletedCount : this . changes } ) ;
2007+ } ) ;
2008+ } ) ;
2009+ } ) ;
2010+
19592011
19602012app . delete ( '/api/dvr/jobs/:id' , requireAuth , requireDvrAccess , ( req , res ) => {
19612013 const { id } = req . params ;
@@ -2142,58 +2194,6 @@ app.post('/api/settings/import', requireAdmin, settingsUpload.single('settingsFi
21422194 }
21432195} ) ;
21442196
2145- // --- NEW: DVR Bulk Delete Endpoints ---
2146- app . delete ( '/api/dvr/jobs/all' , requireAuth , requireDvrAccess , ( req , res ) => {
2147- const userId = req . session . userId ;
2148- console . log ( `[DVR_API] Clearing all scheduled/historical jobs for user ${ userId } .` ) ;
2149-
2150- db . all ( "SELECT id FROM dvr_jobs WHERE user_id = ? AND status = 'scheduled'" , [ userId ] , ( err , scheduledJobs ) => {
2151- if ( err ) {
2152- return res . status ( 500 ) . json ( { error : 'Could not fetch jobs to cancel.' } ) ;
2153- }
2154- scheduledJobs . forEach ( job => {
2155- if ( activeDvrJobs . has ( job . id ) ) {
2156- activeDvrJobs . get ( job . id ) ?. cancel ( ) ;
2157- activeDvrJobs . delete ( job . id ) ;
2158- }
2159- } ) ;
2160-
2161- db . run ( "DELETE FROM dvr_jobs WHERE user_id = ?" , [ userId ] , function ( err ) {
2162- if ( err ) {
2163- return res . status ( 500 ) . json ( { error : 'Could not clear jobs from database.' } ) ;
2164- }
2165- res . json ( { success : true , deletedCount : this . changes } ) ;
2166- } ) ;
2167- } ) ;
2168- } ) ;
2169-
2170- app . delete ( '/api/dvr/recordings/all' , requireAuth , requireDvrAccess , ( req , res ) => {
2171- const userId = req . session . userId ;
2172- console . log ( `[DVR_API] Deleting all completed recordings for user ${ userId } .` ) ;
2173-
2174- db . all ( "SELECT id, filePath FROM dvr_recordings WHERE user_id = ?" , [ userId ] , ( err , recordings ) => {
2175- if ( err ) {
2176- return res . status ( 500 ) . json ( { error : 'Could not fetch recordings to delete.' } ) ;
2177- }
2178-
2179- recordings . forEach ( rec => {
2180- if ( fs . existsSync ( rec . filePath ) ) {
2181- fs . unlink ( rec . filePath , ( unlinkErr ) => {
2182- if ( unlinkErr ) console . error ( `[DVR_API] Failed to delete file ${ rec . filePath } :` , unlinkErr ) ;
2183- } ) ;
2184- }
2185- } ) ;
2186-
2187- db . run ( "DELETE FROM dvr_recordings WHERE user_id = ?" , [ userId ] , function ( err ) {
2188- if ( err ) {
2189- return res . status ( 500 ) . json ( { error : 'Could not clear recordings from database.' } ) ;
2190- }
2191- res . json ( { success : true , deletedCount : this . changes } ) ;
2192- } ) ;
2193- } ) ;
2194- } ) ;
2195-
2196-
21972197// --- Main Route Handling ---
21982198app . get ( '*' , ( req , res ) => {
21992199 const filePath = path . join ( PUBLIC_DIR , req . path ) ;
@@ -2232,6 +2232,7 @@ function parseM3U(data) {
22322232 const line = lines [ i ] . trim ( ) ;
22332233 if ( line . startsWith ( '#EXTINF:' ) ) {
22342234 const nextLine = lines [ i + 1 ] ?. trim ( ) ;
2235+ // Ensure the next line is a valid URL
22352236 if ( nextLine && ( nextLine . startsWith ( 'http' ) || nextLine . startsWith ( 'rtp' ) ) ) {
22362237 const idMatch = line . match ( / t v g - i d = " ( [ ^ " ] * ) " / ) ;
22372238 const logoMatch = line . match ( / t v g - l o g o = " ( [ ^ " ] * ) " / ) ;
0 commit comments