@@ -776,6 +776,50 @@ export class StreamingService {
776776 file . select ( ) ;
777777 logger . debug ( 'File selected for download priority' ) ;
778778
779+ // For MP4/MOV files, prioritize downloading the last ~10MB where the moov atom lives
780+ // Without the moov atom, browsers cannot begin playback (even for raw streaming)
781+ const ext = file . name . split ( '.' ) . pop ( ) ?. toLowerCase ( ) ;
782+ const MOOV_FORMATS = new Set ( [ 'mp4' , 'm4v' , 'mov' , 'm4a' , '3gp' , '3g2' ] ) ;
783+ if ( MOOV_FORMATS . has ( ext ?? '' ) && file . length > 10 * 1024 * 1024 ) {
784+ const fileOffset = ( file as unknown as { offset : number } ) . offset ?? 0 ;
785+ const moovBytes = 10 * 1024 * 1024 ; // 10MB should cover any moov atom
786+ const moovStart = fileOffset + file . length - moovBytes ;
787+ const moovStartPiece = Math . floor ( moovStart / torrent . pieceLength ) ;
788+ const moovEndPiece = Math . ceil ( ( fileOffset + file . length ) / torrent . pieceLength ) - 1 ;
789+
790+ // Also prioritize the first few pieces for the ftyp header
791+ const headerEndPiece = Math . min (
792+ Math . ceil ( ( fileOffset + 1 * 1024 * 1024 ) / torrent . pieceLength ) ,
793+ torrent . pieces . length - 1
794+ ) ;
795+ const headerStartPiece = Math . floor ( fileOffset / torrent . pieceLength ) ;
796+
797+ logger . info ( 'Prioritizing moov atom + header for MP4/MOV' , {
798+ fileName : file . name ,
799+ fileSizeMB : ( file . length / ( 1024 * 1024 ) ) . toFixed ( 0 ) ,
800+ headerPieces : `${ headerStartPiece } -${ headerEndPiece } ` ,
801+ moovPieces : `${ moovStartPiece } -${ moovEndPiece } ` ,
802+ totalPieces : torrent . pieces . length ,
803+ pieceLength : torrent . pieceLength ,
804+ } ) ;
805+
806+ // Use select with high priority for these critical ranges
807+ // WebTorrent select(start, end, priority) — higher priority = downloaded first
808+ file . select ( ) ;
809+ try {
810+ // Critical pieces for the header (beginning of file)
811+ for ( let i = headerStartPiece ; i <= headerEndPiece ; i ++ ) {
812+ ( torrent as unknown as { critical : ( start : number , end : number ) => void } ) . critical ( i , i ) ;
813+ }
814+ // Critical pieces for moov atom (end of file)
815+ for ( let i = moovStartPiece ; i <= moovEndPiece ; i ++ ) {
816+ ( torrent as unknown as { critical : ( start : number , end : number ) => void } ) . critical ( i , i ) ;
817+ }
818+ } catch ( err ) {
819+ logger . warn ( 'Could not set critical pieces' , { error : String ( err ) } ) ;
820+ }
821+ }
822+
779823 // Log current download state
780824 const fileProgress = ( file as unknown as { progress : number } ) . progress ?? 0 ;
781825 const downloadedBytes = fileProgress * file . length ;
0 commit comments