]> jfr.im git - yt-dlp.git/blob - youtube_dlc/postprocessor/sponskrub.py
[ffmpeg] Allow passing custom arguments before -i
[yt-dlp.git] / youtube_dlc / postprocessor / sponskrub.py
1 from __future__ import unicode_literals
2 import os
3 import subprocess
4
5 from .common import PostProcessor
6 from ..compat import compat_shlex_split
7 from ..utils import (
8 check_executable,
9 encodeArgument,
10 encodeFilename,
11 shell_quote,
12 str_or_none,
13 PostProcessingError,
14 prepend_extension,
15 process_communicate_or_kill,
16 )
17
18
19 class SponSkrubPP(PostProcessor):
20 _temp_ext = 'spons'
21 _exe_name = 'sponskrub'
22
23 def __init__(self, downloader, path='', args=None, ignoreerror=False, cut=False, force=False):
24 PostProcessor.__init__(self, downloader)
25 self.force = force
26 self.cutout = cut
27 self.args = str_or_none(args) or '' # For backward compatibility
28 self.path = self.get_exe(path)
29
30 if not ignoreerror and self.path is None:
31 if path:
32 raise PostProcessingError('sponskrub not found in "%s"' % path)
33 else:
34 raise PostProcessingError('sponskrub not found. Please install or provide the path using --sponskrub-path.')
35
36 def get_exe(self, path=''):
37 if not path or not check_executable(path, ['-h']):
38 path = os.path.join(path, self._exe_name)
39 if not check_executable(path, ['-h']):
40 return None
41 return path
42
43 def run(self, information):
44 if self.path is None:
45 return [], information
46
47 filename = information['filepath']
48 if not os.path.exists(encodeFilename(filename)): # no download
49 return [], information
50
51 if information['extractor_key'].lower() != 'youtube':
52 self.to_screen('Skipping sponskrub since it is not a YouTube video')
53 return [], information
54 if self.cutout and not self.force and not information.get('__real_download', False):
55 self.report_warning(
56 'Skipping sponskrub since the video was already downloaded. '
57 'Use --sponskrub-force to run sponskrub anyway')
58 return [], information
59
60 self.to_screen('Trying to %s sponsor sections' % ('remove' if self.cutout else 'mark'))
61 if self.cutout:
62 self.report_warning('Cutting out sponsor segments will cause the subtitles to go out of sync.')
63 if not information.get('__real_download', False):
64 self.report_warning('If sponskrub is run multiple times, unintended parts of the video could be cut out.')
65
66 temp_filename = prepend_extension(filename, self._temp_ext)
67 if os.path.exists(encodeFilename(temp_filename)):
68 os.remove(encodeFilename(temp_filename))
69
70 cmd = [self.path]
71 if not self.cutout:
72 cmd += ['-chapter']
73 cmd += compat_shlex_split(self.args) # For backward compatibility
74 cmd += self._configuration_args(exe=self._exe_name, use_default_arg='no_compat')
75 cmd += ['--', information['id'], filename, temp_filename]
76 cmd = [encodeArgument(i) for i in cmd]
77
78 self.write_debug('sponskrub command line: %s' % shell_quote(cmd))
79 pipe = None if self.get_param('verbose') else subprocess.PIPE
80 p = subprocess.Popen(cmd, stdout=pipe)
81 stdout = process_communicate_or_kill(p)[0]
82
83 if p.returncode == 0:
84 os.remove(encodeFilename(filename))
85 os.rename(encodeFilename(temp_filename), encodeFilename(filename))
86 self.to_screen('Sponsor sections have been %s' % ('removed' if self.cutout else 'marked'))
87 elif p.returncode == 3:
88 self.to_screen('No segments in the SponsorBlock database')
89 else:
90 msg = stdout.decode('utf-8', 'replace').strip() if stdout else ''
91 msg = msg.split('\n')[0 if msg.lower().startswith('unrecognised') else -1]
92 raise PostProcessingError(msg if msg else 'sponskrub failed with error code %s' % p.returncode)
93 return [], information