@@ -201,9 +201,12 @@ class YoutubeDL(object):
201
201
verbose: Print additional info to stdout.
202
202
quiet: Do not print messages to stdout.
203
203
no_warnings: Do not print out anything for warnings.
204
- forceprint: A dict with keys video/playlist mapped to
205
- a list of templates to force print to stdout
204
+ forceprint: A dict with keys WHEN mapped to a list of templates to
205
+ print to stdout. The allowed keys are video or any of the
206
+ items in utils.POSTPROCESS_WHEN.
206
207
For compatibility, a single list is also accepted
208
+ print_to_file: A dict with keys WHEN (same as forceprint) mapped to
209
+ a list of tuples with (template, filename)
207
210
forceurl: Force printing final URL. (Deprecated)
208
211
forcetitle: Force printing title. (Deprecated)
209
212
forceid: Force printing ID. (Deprecated)
@@ -349,8 +352,8 @@ class YoutubeDL(object):
349
352
postprocessors: A list of dictionaries, each with an entry
350
353
* key: The name of the postprocessor. See
351
354
yt_dlp/postprocessor/__init__.py for a list.
352
- * when: When to run the postprocessor. Can be one of
353
- pre_process|before_dl|post_process|after_move.
355
+ * when: When to run the postprocessor. Allowed values are
356
+ the entries of utils.POSTPROCESS_WHEN
354
357
Assumed to be 'post_process' if not given
355
358
post_hooks: Deprecated - Register a custom postprocessor instead
356
359
A list of functions that get called as the final step
@@ -592,8 +595,10 @@ def check_deprecated(param, option, suggestion):
592
595
else :
593
596
self .params ['nooverwrites' ] = not self .params ['overwrites' ]
594
597
595
- # Compatibility with older syntax
596
598
params .setdefault ('forceprint' , {})
599
+ params .setdefault ('print_to_file' , {})
600
+
601
+ # Compatibility with older syntax
597
602
if not isinstance (params ['forceprint' ], dict ):
598
603
params ['forceprint' ] = {'video' : params ['forceprint' ]}
599
604
@@ -2683,19 +2688,32 @@ def process_subtitles(self, video_id, normal_subtitles, automatic_captions):
2683
2688
subs [lang ] = f
2684
2689
return subs
2685
2690
2686
- def _forceprint (self , tmpl , info_dict ):
2687
- mobj = re .match (r'\w+(=?)$' , tmpl )
2688
- if mobj and mobj .group (1 ):
2689
- tmpl = f'{ tmpl [:- 1 ]} = %({ tmpl [:- 1 ]} )r'
2690
- elif mobj :
2691
- tmpl = '%({})s' .format (tmpl )
2691
+ def _forceprint (self , key , info_dict ):
2692
+ if info_dict is None :
2693
+ return
2694
+ info_copy = info_dict .copy ()
2695
+ info_copy ['formats_table' ] = self .render_formats_table (info_dict )
2696
+ info_copy ['thumbnails_table' ] = self .render_thumbnails_table (info_dict )
2697
+ info_copy ['subtitles_table' ] = self .render_subtitles_table (info_dict .get ('id' ), info_dict .get ('subtitles' ))
2698
+ info_copy ['automatic_captions_table' ] = self .render_subtitles_table (info_dict .get ('id' ), info_dict .get ('automatic_captions' ))
2699
+
2700
+ def format_tmpl (tmpl ):
2701
+ mobj = re .match (r'\w+(=?)$' , tmpl )
2702
+ if mobj and mobj .group (1 ):
2703
+ return f'{ tmpl [:- 1 ]} = %({ tmpl [:- 1 ]} )r'
2704
+ elif mobj :
2705
+ return f'%({ tmpl } )s'
2706
+ return tmpl
2692
2707
2693
- info_dict = info_dict .copy ()
2694
- info_dict ['formats_table' ] = self .render_formats_table (info_dict )
2695
- info_dict ['thumbnails_table' ] = self .render_thumbnails_table (info_dict )
2696
- info_dict ['subtitles_table' ] = self .render_subtitles_table (info_dict .get ('id' ), info_dict .get ('subtitles' ))
2697
- info_dict ['automatic_captions_table' ] = self .render_subtitles_table (info_dict .get ('id' ), info_dict .get ('automatic_captions' ))
2698
- self .to_stdout (self .evaluate_outtmpl (tmpl , info_dict ))
2708
+ for tmpl in self .params ['forceprint' ].get (key , []):
2709
+ self .to_stdout (self .evaluate_outtmpl (format_tmpl (tmpl ), info_copy ))
2710
+
2711
+ for tmpl , file_tmpl in self .params ['print_to_file' ].get (key , []):
2712
+ filename = self .evaluate_outtmpl (file_tmpl , info_dict )
2713
+ tmpl = format_tmpl (tmpl )
2714
+ self .to_screen (f'[info] Writing { tmpl !r} to: { filename } ' )
2715
+ with io .open (filename , 'a' , encoding = 'utf-8' ) as f :
2716
+ f .write (self .evaluate_outtmpl (tmpl , info_copy ) + '\n ' )
2699
2717
2700
2718
def __forced_printings (self , info_dict , filename , incomplete ):
2701
2719
def print_mandatory (field , actual_field = None ):
@@ -2719,10 +2737,11 @@ def print_optional(field):
2719
2737
elif 'url' in info_dict :
2720
2738
info_dict ['urls' ] = info_dict ['url' ] + info_dict .get ('play_path' , '' )
2721
2739
2722
- if self .params ['forceprint' ].get ('video' ) or self .params .get ('forcejson' ):
2740
+ if (self .params .get ('forcejson' )
2741
+ or self .params ['forceprint' ].get ('video' )
2742
+ or self .params ['print_to_file' ].get ('video' )):
2723
2743
self .post_extract (info_dict )
2724
- for tmpl in self .params ['forceprint' ].get ('video' , []):
2725
- self ._forceprint (tmpl , info_dict )
2744
+ self ._forceprint ('video' , info_dict )
2726
2745
2727
2746
print_mandatory ('title' )
2728
2747
print_mandatory ('id' )
@@ -3290,8 +3309,7 @@ def run_pp(self, pp, infodict):
3290
3309
return infodict
3291
3310
3292
3311
def run_all_pps (self , key , info , * , additional_pps = None ):
3293
- for tmpl in self .params ['forceprint' ].get (key , []):
3294
- self ._forceprint (tmpl , info )
3312
+ self ._forceprint (key , info )
3295
3313
for pp in (additional_pps or []) + self ._pps [key ]:
3296
3314
info = self .run_pp (pp , info )
3297
3315
return info
0 commit comments