@@ -124,11 +124,11 @@ def test_seconds():
124124 assert seconds ('1:30' ) == 90
125125 assert seconds ('1:1:30' ) == 3690
126126 assert seconds ('1:1:30.5' ) == 3690.5
127- def humantime (x ):
127+ def humantime (x , show_hour = False ):
128128 hou = x // 3600
129129 min = (x % 3600 ) // 60
130130 sec = x % 60
131- if hou :
131+ if hou or show_hour :
132132 return "%d:%02d:%02d" % (hou , min , floor (sec ))
133133 return "%02d:%02d" % (min , floor (sec ))
134134def test_humantime ():
@@ -238,6 +238,8 @@ def main(argv=sys.argv[1:]):
238238 help = 'Number of encoding threads. Default: unset, autodetect' )
239239 parser .add_argument ('--wait' , action = 'store_true' ,
240240 help = 'Wait after each encoding (don\' t clean up the temporary directory right away' )
241+ parser .add_argument ('--no-mkv-chapters' , action = 'store_false' , default = True , dest = 'mkv_chapters' ,
242+ help = "Don't try to encode the chapters and description into the mkv file. This requires mkvnixtools to be installed" )
241243 parser .add_argument ('--list' , action = 'store_true' ,
242244 help = "Don't do anything, just list all outputs that would be processed (and nothing else)" )
243245
@@ -494,22 +496,15 @@ def main(argv=sys.argv[1:]):
494496 LOG .info (shell_join (cmd ))
495497 if not args .check :
496498 subprocess .check_call (cmd )
497- # We need another copy, since ffmpeg detects output based on filename. Yet for atomicness, we need a temporary filename for the temp part
498- if not args .check :
499- with atomic_write (output ) as tmp_output :
500- shutil .move (tmpdir_out , tmp_output )
501499
502- # Subtitles
503- if args .srt :
504- srt_output = os .path .splitext (output )[0 ] + '.srt'
505- open (srt_output , 'w' ).write (srt .compose (subtitles ))
500+ # Create the video properties/chapters/etc (needs to be done before
501+ # making the final mkv because it gets encoded into the mkv file).
506502
507503 # Print table of contents
508504 import pprint
509505 LOG .debug (pprint .pformat (segment_list ))
510506 LOG .debug (pprint .pformat (TOC ))
511507
512-
513508 video_description = [ ]
514509 if segment .get ('title' ):
515510 title = segment ['title' ]
@@ -521,12 +516,18 @@ def main(argv=sys.argv[1:]):
521516 video_description .extend ([segment ['description' ].strip ().replace ('\n ' , '\n \n ' )])
522517 # Print out the table of contents
523518 #video_description.append('\n')
519+ # Making chapters
524520 toc = [ ]
525- for seg_n , time , name in TOC :
521+ chapter_file = Path (tmpdir ) / 'chapters.txt'
522+ chapter_file_f = open (chapter_file , 'w' )
523+ for i , (seg_n , time , name ) in enumerate (TOC ):
526524 LOG .debug ("TOC entry %s %s" , time , name )
527525 new_time = map_time (seg_n , segment_list , time )
528526 print (humantime (new_time ), name )
529527 toc .append (f"{ humantime (new_time )} { name } " )
528+ chapter_file_f .write (f'CHAPTER{ i + 1 :02d} ={ humantime (new_time , show_hour = True )} .000\n ' )
529+ chapter_file_f .write (f'CHAPTER{ i + 1 :02d} NAME={ name } \n ' )
530+ chapter_file_f .close ()
530531 if toc :
531532 video_description .append ('\n ' .join (toc ))
532533
@@ -535,9 +536,36 @@ def main(argv=sys.argv[1:]):
535536 video_description .append (workshop_description .replace ('\n ' , '\n \n ' ).strip ())
536537
537538 if video_description :
538- with atomic_write (os .path .splitext (str (output ))[0 ]+ '.info.txt' , 'w' ) as toc_file :
539+ video_description_file = os .path .splitext (str (output ))[0 ]+ '.info.txt'
540+ with atomic_write (video_description_file , 'w' ) as toc_file :
539541 open (toc_file , 'w' ).write ('\n \n ' .join (video_description ))
540542
543+ # mkv chapters
544+ cmd = ['mkvpropedit' , tmpdir_out ,
545+ '--set' , f'title={ title } ' ,
546+ * (['--chapters' , str (chapter_file ),] if toc else []),
547+ * (['--attachment-name' , 'description' , '--add-attachment' , video_description_file ] if video_description else []),
548+ ]
549+ print (cmd )
550+ if not args .check and args .mkv_chapters :
551+ subprocess .check_call (cmd )
552+
553+
554+ # Finalize the video
555+
556+ # We need another copy, since ffmpeg detects output based on
557+ # filename. Yet for atomicness, we need a temporary filename for
558+ # the temp part
559+ if not args .check :
560+ with atomic_write (output ) as tmp_output :
561+ shutil .move (tmpdir_out , tmp_output )
562+
563+ # Subtitles
564+ if args .srt :
565+ srt_output = os .path .splitext (output )[0 ] + '.srt'
566+ open (srt_output , 'w' ).write (srt .compose (subtitles ))
567+
568+
541569 # Print out covered segments (for verification purposes)
542570 for seg_n , time in covers :
543571 new_time = map_time (seg_n , segment_list , time )
0 commit comments