tictacsync 0.3a4__py3-none-any.whl → 0.5a0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -77,6 +77,7 @@ class Device:
77
77
  name: str
78
78
  dev_type: str # CAM or REC
79
79
  n_chan: int
80
+ ttc: int
80
81
  tracks: Tracks
81
82
  def __hash__(self):
82
83
  return self.UID
@@ -89,10 +90,12 @@ class Media:
89
90
  """
90
91
  path: Path
91
92
  device: Device
93
+
92
94
  def media_at_path(input_structure, p):
93
95
  # return Media object for mediafile using ffprobe
94
96
  dev_UID, dt = get_device_ffprobe_UID(p)
95
- dev_name = None
97
+ dev_name = None
98
+ logger.debug('ffprobe dev_UID:%s dt:%s'%(dev_UID, dt))
96
99
  if input_structure == 'folder_is_device':
97
100
  dev_name = p.parent.name
98
101
  if dev_UID is None:
@@ -113,9 +116,10 @@ def media_at_path(input_structure, p):
113
116
  else:
114
117
  n = sox.file_info.channels(_pathname(p)) # eg 2
115
118
  logger.debug('for file %s dev_UID established %s'%(p.name, dev_UID))
116
- return Media(p,
117
- Device(UID=dev_UID, folder=p.parent, name=dev_name, dev_type=dt,
118
- n_chan=n, tracks=None))
119
+ device = Device(UID=dev_UID, folder=p.parent, name=dev_name, dev_type=dt,
120
+ n_chan=n, ttc=None, tracks=None)
121
+ logger.debug('for path: %s, device:%s'%(p,device))
122
+ return Media(p, device)
119
123
 
120
124
  def get_device_ffprobe_UID(file):
121
125
  """
@@ -140,7 +144,7 @@ def get_device_ffprobe_UID(file):
140
144
  except ffmpeg.Error as e:
141
145
  print('ffmpeg.probe error')
142
146
  print(e.stderr, file)
143
- return None, None
147
+ return None, None #-----------------------------------------------------
144
148
  # fall back to folder name
145
149
  streams = probe['streams']
146
150
  codecs = [stream['codec_type'] for stream in streams]
@@ -154,9 +158,12 @@ def get_device_ffprobe_UID(file):
154
158
  and 'date' not in l ]
155
159
  # this removes any metadata related to the file
156
160
  # but keeps metadata related to the device
161
+ logger.debug('probe_lines %s'%probe_lines)
157
162
  UID = hash(''.join(probe_lines))
158
163
  else:
159
164
  UID = None
165
+ if UID == 0: # empty probe_lines from Audacity ?!?
166
+ UID = None
160
167
  logger.debug('ffprobe_UID is: %s'%UID)
161
168
  return UID, device_type
162
169
 
@@ -256,9 +263,6 @@ class Scanner:
256
263
  for p in paths:
257
264
  new_media = media_at_path(self.input_structure, p) # dev UID set here
258
265
  self.found_media_files.append(new_media)
259
- # files from devices without UID or name
260
- # def _list_all_the_same(l):
261
- # return all(e == l[0] for e in l)
262
266
  def _try_name(medias):
263
267
  # return common first strings in filename
264
268
  names = [m.path.name for m in medias]
@@ -273,7 +277,6 @@ class Scanner:
273
277
  if not m.device.UID]
274
278
  if no_device_UID_media:
275
279
  logger.debug('no_device_UID_media %s'%no_device_UID_media)
276
- # print(no_device_UID_media)
277
280
  start_string = _try_name(no_device_UID_media)
278
281
  if len(start_string) < 2:
279
282
  print('\nError, cant identify the device for those files:')
@@ -285,7 +288,8 @@ class Scanner:
285
288
  if not one_device.UID:
286
289
  one_device.UID = hash(start_string)
287
290
  print('\nWarning, guessing a device ID for those files:')
288
- [print('[gold1]%s[/gold1], '%m.path.name, end='') for m in no_device_UID_media]
291
+ [print('[gold1]%s[/gold1], '%m.path.name, end='') for m
292
+ in no_device_UID_media]
289
293
  print('UID: [gold1]%s[/gold1]'%start_string)
290
294
  for m in no_device_UID_media:
291
295
  m.device = one_device
@@ -342,32 +346,22 @@ class Scanner:
342
346
  ntracks += len(tracks.others)
343
347
  ntracks += 1 # for ttc track
344
348
  logger.debug(' n chan: %i n tracks file: %i'%(nchan, ntracks))
345
- # if ntracks != nchan:
346
- # print('\nError parsing %s content'%tracks_file)
347
- # print('incoherent number of tracks, %i vs %i quitting\n'%
348
- # (nchan, ntracks))
349
- # sys.exit(1)
349
+ if ntracks != nchan:
350
+ print('\nError parsing %s content'%tracks_file)
351
+ print('incoherent number of tracks, %i vs %i quitting\n'%
352
+ (nchan, ntracks))
353
+ sys.exit(1)
350
354
  err_msg = tracks.error_msg
351
355
  if err_msg != None:
352
356
  print('Error, quitting: in file %s, %s'%(tracks_file, err_msg))
353
357
  raise Exception
354
358
  else:
359
+ logger.debug('tracks object%s'%tracks)
355
360
  return tracks
356
361
  else:
357
362
  logger.debug('no tracks.txt file found')
358
363
  return None
359
364
 
360
- # def _use_folder_as_device_name(self):
361
- # """
362
- # For each media in self.found_media_files replace existing Device.name by
363
- # folder name.
364
-
365
- # Returns nothing
366
- # """
367
- # for m in self.found_media_files:
368
- # m.device.name = m.path.parent.name
369
- # logger.debug(self.found_media_files)
370
-
371
365
  def _check_folders_have_same_device(self):
372
366
  """
373
367
  Since input_structure == 'folder_is_device,
tictacsync/entry.py CHANGED
@@ -126,10 +126,10 @@ def main():
126
126
  # logger.add(sys.stdout, filter="__main__")
127
127
  # logger.add(sys.stdout, filter="device_scanner")
128
128
  # logger.add(sys.stdout, filter="yaltc") _extract_sound_to_merge
129
+ # logger.add(sys.stdout, filter=lambda r: r["function"] == "media_at_path")
129
130
  # logger.add(sys.stdout, filter=lambda r: r["function"] == "scan_media_and_build_devices_UID")
130
- # logger.add(sys.stdout, filter=lambda r: r["function"] == "_sox_multi2mono")
131
- # logger.add(sys.stdout, filter=lambda r: r["function"] == "_get_mix")
132
- # logger.add(sys.stdout, filter=lambda r: r["function"] == "_sox_mix")
131
+ # logger.add(sys.stdout, filter=lambda r: r["function"] == "_get_device_mix")
132
+ # logger.add(sys.stdout, filter=lambda r: r["function"] == "_sox_mix_files")
133
133
  top_dir = args.directory[0]
134
134
  if os.path.isfile(top_dir):
135
135
  file = top_dir
@@ -234,7 +234,7 @@ def main():
234
234
  print('\nNothing to sync, exiting.\n')
235
235
  sys.exit(1)
236
236
  matcher = timeline.Matcher(recordings_with_time)
237
- matcher.scan_audio_for_each_ref_rec()
237
+ matcher.scan_audio_for_each_videoclip()
238
238
  if not matcher.video_mergers:
239
239
  if not args.terse:
240
240
  print('\nNothing to sync, bye.\n')
@@ -263,11 +263,11 @@ def main():
263
263
  print('\nWrote output in folder [gold1]%s[/gold1]'%(
264
264
  a_stitcher.synced_clip_dir))
265
265
  for stitcher in matcher.video_mergers:
266
- print('[gold1]%s[/gold1]'%stitcher.ref_recording.AVpath.name, end='')
266
+ print('[gold1]%s[/gold1]'%stitcher.videoclip.AVpath.name, end='')
267
267
  for audio in stitcher.get_matched_audio_recs():
268
268
  print(' + [gold1]%s[/gold1]'%audio.AVpath.name, end='')
269
- new_file = stitcher.ref_recording.final_synced_file.parts
270
- print(' became [gold1]%s[/gold1]'%stitcher.ref_recording.final_synced_file.name)
269
+ new_file = stitcher.videoclip.final_synced_file.parts
270
+ print(' became [gold1]%s[/gold1]'%stitcher.videoclip.final_synced_file.name)
271
271
  # matcher._build_otio_tracks_for_cam()
272
272
  matcher.shrink_gaps_between_takes()
273
273
  sys.exit(0)
@@ -277,6 +277,3 @@ if __name__ == '__main__':
277
277
 
278
278
 
279
279
 
280
-
281
-
282
-
@@ -61,7 +61,7 @@ def build_poly_name(multifiles):
61
61
  """
62
62
  Returns string of polywav filename, constructed from similitudes between
63
63
  multifile names. Ex:
64
- /full/path/4CH002I.wav and /full/path/4CH002M.wav returns 4CH002X.wav
64
+ 4CH002I.wav and 4CH002M.wav returns 4CH002X.wav
65
65
  """
66
66
  s1 = str(multifiles[0].stem)
67
67
  s2 = str(multifiles[1].stem)
@@ -96,6 +96,7 @@ def build_poly(multifiles):
96
96
  # multifiles is list of Path
97
97
  # change extensions to mfw (multifile wav)
98
98
  dir_multi = multifiles[0].parent
99
+ multifiles.reverse()
99
100
  poly_name_b = build_poly_name(multifiles) # base only
100
101
  poly_name = str(dir_multi/Path(poly_name_b))
101
102
  filenames = [str(p) for p in multifiles]
tictacsync/remergemix.py CHANGED
@@ -3,13 +3,35 @@ from loguru import logger
3
3
  from pathlib import Path
4
4
  import sox, tempfile, os, ffmpeg
5
5
  from rich import print
6
- import shutil
6
+ import shutil, sys, re
7
+ from pprint import pformat
8
+ from itertools import groupby
7
9
 
10
+ try:
11
+ from . import timeline
12
+ except:
13
+ import timeline
8
14
 
15
+ DEL_TEMP = False
16
+
17
+ logger.level("DEBUG", color="<yellow>")
9
18
  logger.remove()
10
- # OUT_DIR = 'SyncedMedia'
19
+
20
+ # logger.add(sys.stdout, filter=lambda r: r["function"] == "_get_ISO_dirs")
21
+ # logger.add(sys.stdout, filter=lambda r: r["function"] == "_join_audio2video")
22
+ # logger.add(sys.stdout, filter=lambda r: r["function"] == "main")
23
+ # logger.add(sys.stdout, filter="__main__")
24
+
25
+ OUT_DIR = 'SyncedMedia'
26
+ SEC_DELAY_CHANGED_ISO = 10 #sec, ISO_DIR changed if diff time is bigger
27
+
28
+ video_extensions = \
29
+ """webm mkv flv flv vob ogv ogg drc gif gifv mng avi mov
30
+ qt wmv yuv rm rmvb viv asf mp4 m4p m4v mpg mp2 mpeg mpe
31
+ mpv mpg mpeg m2v m4v svi 3gp 3g2 mxf roq nsv""".split() # from wikipedia
11
32
 
12
33
  def _pathname(tempfile_or_path) -> str:
34
+ # utility for obtaining a str from different filesystem objects
13
35
  if isinstance(tempfile_or_path, str):
14
36
  return tempfile_or_path
15
37
  if isinstance(tempfile_or_path, Path):
@@ -19,125 +41,216 @@ def _pathname(tempfile_or_path) -> str:
19
41
  else:
20
42
  raise Exception('%s should be Path or tempfile...'%tempfile_or_path)
21
43
 
22
- def _join(left_right: list, video: Path, out: Path):
44
+ def _keep_VIDEO_only(video_path):
45
+ # return file handle to a temp video file formed from the video_path
46
+ # stripped of its sound
47
+ in1 = ffmpeg.input(_pathname(video_path))
48
+ video_extension = video_path.suffix
49
+ silenced_opts = ["-loglevel", "quiet", "-nostats", "-hide_banner"]
50
+ file_handle = tempfile.NamedTemporaryFile(suffix=video_extension,
51
+ delete=DEL_TEMP)
52
+ out1 = in1.output(file_handle.name, map='0:v', vcodec='copy')
53
+ ffmpeg.run([out1.global_args(*silenced_opts)], overwrite_output=True)
54
+ return file_handle
55
+
56
+ def _join_audio2video(audio_path: Path, video: Path):
57
+ """
58
+ Replace audio in video (argument) by the audio contained in
59
+ audio_path (argument) returns nothing
60
+ """
23
61
  video_ext = video.name.split('.')[1]
24
- audio_left = (
62
+ vid_only_handle = _keep_VIDEO_only(video)
63
+ a_n = _pathname(audio_path)
64
+ v_n = _pathname(vid_only_handle)
65
+ out_n = _pathname(video)
66
+ # building args for debug purpose only:
67
+ ffmpeg_args = (
25
68
  ffmpeg
26
- .input(_pathname(left_right[0])))
27
- audio_right = (
69
+ .input(v_n)
70
+ .output(out_n, shortest=None, vcodec='copy')
71
+ .global_args('-i', a_n, "-hide_banner")
72
+ .overwrite_output()
73
+ .get_args()
74
+ )
75
+ logger.debug('ffmpeg args: %s'%' '.join(ffmpeg_args))
76
+ try: # for real now
77
+ _, out = (
28
78
  ffmpeg
29
- .input(_pathname(left_right[1])))
30
- input_video = ffmpeg.input(_pathname(video))
31
- out_file = tempfile.NamedTemporaryFile(suffix='.%s'%video_ext)
32
- try:
33
- (ffmpeg
34
- .filter((audio_left, audio_right), 'join', inputs=2,
35
- channel_layout='stereo')
36
- .output(input_video.video, _pathname(out_file),
37
- shortest=None, vcodec='copy', loglevel="quiet")
79
+ .input(v_n)
80
+ .output(out_n, shortest=None, vcodec='copy')
81
+ .global_args('-i', a_n, "-hide_banner")
38
82
  .overwrite_output()
39
- .run())
83
+ .run(capture_stderr=True)
84
+ )
85
+ logger.debug('ffmpeg output')
86
+ for l in out.decode("utf-8").split('\n'):
87
+ logger.debug(l)
40
88
  except ffmpeg.Error as e:
89
+ print('ffmpeg.run error merging: \n\t %s + %s = %s\n'%(
90
+ audio_path,
91
+ video_path,
92
+ synced_clip_file
93
+ ))
41
94
  print(e)
42
95
  print(e.stderr.decode('UTF-8'))
43
96
  sys.exit(1)
44
- shutil.copyfile(_pathname(out_file), _pathname(video))
45
-
46
-
47
- def sync_cam(dir):
48
- # dir is a CAM dir, contents are clips and ISO folders
49
- ISOs = list(dir.glob('*.ISO'))
50
- for iso in ISOs:
51
- # iso is a folder
52
- statResult = iso.stat()
53
- mtime = statResult.st_mtime
54
- # print('%s: %s'%(iso.name, biggest_mtime_in_dir(iso)))
55
- iso_mod_time = biggest_mtime_in_dir(iso)
56
- clip = clip_from_iso(iso)
57
- clip_mod_time = clip.stat().st_mtime
58
- iso_edited = iso_mod_time > clip_mod_time
59
- # print('clip %s should be resync: %s'%(clip.name, iso_edited))
60
- # print(clip)
61
- if iso_edited:
62
- print('Resyncing [gold1]%s[/gold1]'%clip.name)
63
- LR_channels = list(valid_audio_files(iso))
64
- _join(LR_channels, clip, 'test.MOV')
65
-
66
-
67
- def valid_audio_files(isofolder: Path) -> list:
97
+
98
+ def _changed(dir) -> bool:
68
99
  """
69
- Returns two valid audio files to be synced with video
70
- case A - only two files differing by L and R
71
- case B - more than two files, two are mixL mixR
72
- case C - one file only -> sys.exit(1)
73
- case D - more than two files, no mixL mixR -> sys.exit(1)
100
+ Returns True if any content of dir (arg) is more recent than dir itself by a
101
+ delay of SEC_DELAY_CHANGED_ISO. Uses modification times.
74
102
  """
75
- files = list(isofolder.iterdir())
76
- if len(files) == 1: # case C
77
- print('Error with folder %s: no mixL.wav, mixR.wav'%isofolder)
78
- print('or micL.wav, micR.wav... Quitting.')
79
- sys.exit(1)
80
- def _is_case_A(files):
81
- if len(files) != 2:
82
- return False
83
- stems = [p.stem.upper() for p in files]
84
- lasts = [st[-1] for st in stems]
85
- LR_pair = ''.join(lasts) in ['LR', 'RL']
86
- prefix = [st[:-1] for st in stems]
87
- same = prefix[0] == prefix[1]
88
- return same and LR_pair
89
- if _is_case_A(files):
90
- return files
91
- def _is_case_B(files):
92
- if len(files) <= 2:
93
- return False
94
- stems = [p.stem.upper() for p in files]
95
- return 'MIXL' in stems and 'MIXR' in stems
96
- if _is_case_B(files):
97
- return isofolder.glob('mix?.*')
98
- print('Error with folder %s: no mixL.wav, mixR.wav'%isofolder)
99
- print('or micL.wav, micR.wav... Quitting.')
100
- sys.exit(1)
103
+ logger.debug(f'checking {dir.name} for change')
104
+ ISO_modification_time = biggest_mtime_in_dir(dir)
105
+ clip = clip_from_iso(dir)
106
+ clip_mod_time = clip.stat().st_mtime
107
+ # difference of modification time in secs
108
+ ISO_more_recent_by = ISO_modification_time - clip_mod_time
109
+ logger.debug('ISO_more_recent_by: %s'%(ISO_more_recent_by))
110
+ iso_edited = ISO_more_recent_by > SEC_DELAY_CHANGED_ISO
111
+ logger.debug(f'_changed: {iso_edited}')
112
+ return iso_edited
113
+
114
+ def sox_mix(ISOdir):
115
+ """
116
+ Mixes all wav files present in ISOdir (so excludes ttc file and nullified
117
+ ones).
118
+ Returns a mono or stereo tempfile
119
+ """
120
+ logger.debug(f'mixing {ISOdir}')
121
+ def is_stereo_mic(p):
122
+ re_result = re.match(r'mic([lrLR])*', p.name)
123
+ # logger.debug(f're_result {re_result}')
124
+ return re_result is not None
125
+ stereo_mics = [p for p in ISOdir.iterdir() if is_stereo_mic(p)]
126
+ monofiles = [p for p in ISOdir.iterdir() if p not in stereo_mics]
127
+ # removing ttc files
128
+ def notTTC(p):
129
+ return p.name[:3] != 'ttc'
130
+ monofiles = [p for p in monofiles if notTTC(p)]
131
+ if stereo_mics == []: # mono
132
+ return timeline._sox_mix_files(monofiles) #-----------------------------
133
+ logger.debug(f'stereo_mics: {stereo_mics}')
134
+ def mic(p):
135
+ return re.search(r'(mic\d*)([lrLR])*', p.name).groups()
136
+ mics = [mic(p) for p in stereo_mics]
137
+ p_and_mic = list(zip(stereo_mics, mics))
138
+ logger.debug(f'p_and_mic: {p_and_mic}')
139
+ same_mic_key = lambda pair: pair[1][0]
140
+ p_and_mic = sorted(p_and_mic, key=same_mic_key)
141
+ grouped_by_mic = [ (k, list(iterator)) for k, iterator
142
+ in groupby(p_and_mic, same_mic_key)]
143
+ logger.debug(f'grouped_by_mic: {grouped_by_mic}')
144
+ def order_left_right(groupby_element):
145
+ # returns left and right path for a mic
146
+ name, paths = groupby_element
147
+ def chan(pair):
148
+ # (PosixPath('mic1r_ZOOM.wav'), ('mic1', 'r')) -> 'r'
149
+ return pair[1][1]
150
+ path_n_mic = sorted(paths, key=lambda pair: pair[1][1])
151
+ return [p[0] for p in path_n_mic] # just the path, not ('mic1', 'r')
152
+ left_right_paths = [order_left_right(e) for e in grouped_by_mic]
153
+ # logger.debug(f'left_right_paths: {left_right_paths}')
154
+ stereo_files = [timeline._sox_combine(pair) for pair in left_right_paths]
155
+ monoNstereo = monofiles + stereo_files
156
+ return timeline._sox_mix_files(monoNstereo)
157
+
158
+ def get_mix_file(iso_dir):
159
+ """
160
+ If iso_dir (arg) contains a mono mix sound file or a stereo mix, returns its
161
+ path. If not, this creates the mix and returns it.
162
+ """
163
+ wav_files = list(iso_dir.iterdir())
164
+ logger.debug(f'wav_files {wav_files}')
165
+ def is_mix(p):
166
+ re_result = re.match(r'mix([lrLR])*', p.name)
167
+ # logger.debug(f're_result {re_result}')
168
+ return re_result is not None
169
+ location_mix = [p for p in wav_files if is_mix(p)]
170
+ if location_mix == []:
171
+ logger.debug('no mix track, do the mix')
172
+ return sox_mix(iso_dir)
173
+ else:
174
+ return location_mix
101
175
 
102
176
  def biggest_mtime_in_dir(folder: Path) -> float:
103
- # return the most recent mod time in a folder
177
+ # return the most recent mod time of the files in a folder
104
178
  dir_content = list(folder.iterdir())
105
179
  stats = [p.stat() for p in dir_content]
106
180
  mtimes = [stat.st_mtime for stat in stats]
107
181
  return max(mtimes)
108
182
 
109
- def clip_from_iso(p: Path) -> Path:
110
- folder = p.parent
111
- pair = list(folder.glob('%s.*'%p.stem))
112
- return [p for p in pair if p.name.split('.')[1] != 'ISO'][0]
113
-
114
- def synciso(top_dir):
115
- p = Path(top_dir)/OUT_DIR
116
- dir_content = list(p.iterdir())
117
- logger.debug('dir_content %s'%dir_content)
118
- all_are_dir = all([p.is_dir() for p in dir_content])
119
- logger.debug('all_are_dir %s'%all_are_dir)
183
+ def clip_from_iso(ISO_dir: Path) -> Path:
184
+ # find the sibling video file of ISO_dir. eg : MVI_01.ISO -> MVI_01.MP4
185
+ folder = ISO_dir.parent
186
+ siblings = list(folder.glob('%s.*'%ISO_dir.stem))
187
+ candidates =[p for p in siblings if p.name.split('.')[1] != 'ISO']
188
+ # should be unique
189
+ if len(candidates) != 1:
190
+ print(f'Error finding video corresponding to {ISO_dir}, quitting')
191
+ sys.exit(1)
192
+ return candidates[0]
193
+
194
+ def _get_ISO_dirs(top_dir):
195
+ """
196
+ Check if top_dir contains (or somewhere beneath) videos with their
197
+ accompanying ISO folder (like the pair MVI_023.MP4 + MVI_023.ISO). If not
198
+ warns and exits.
199
+
200
+ Returns list of paths pointing to ISO dirs.
201
+ """
202
+ p = Path(top_dir)
203
+ ISO_dirs = list(Path(top_dir).rglob('*.ISO'))
204
+ logger.debug('all files: %s'%pformat(ISO_dirs))
205
+ # validation: .ISO should be dir
206
+ all_are_dir = all([p.is_dir() for p in ISO_dirs])
207
+ logger.debug('.ISO are all dir %s'%all_are_dir)
120
208
  if not all_are_dir:
121
- print('Error: resync possible only on structured folders,')
122
- print('Rerun tictacsync with one directory for each device.')
209
+ print('Error: some .ISO are not folders??? Quitting. %s'%ISO_dirs)
123
210
  sys.exit(1)
124
- [sync_cam(f) for f in dir_content]
211
+ # for each folder check a video file exists with the same stem
212
+ # but with a video format extension (listed in video_extensions)
213
+ for ISO in ISO_dirs:
214
+ logger.debug(f'checking {ISO}')
215
+ voisins = list(ISO.parent.glob(f'{ISO.stem}.*'))
216
+ voisins_suffixes = [p.suffix for p in voisins]
217
+ # remove ISO
218
+ voisins_suffixes.remove('.ISO')
219
+ # validations: should remain one element and should be video
220
+ suffix = voisins_suffixes[0].lower()[1:] # remove dot
221
+ logger.debug(f'remaining ext: {suffix}')
222
+ if len(voisins_suffixes) != 1 or suffix not in video_extensions:
223
+ print(f'Error with {voisins}, no video unique sibling?')
224
+ sys.exit(1) #-------------------------------------------------------
225
+ logger.debug(f'All ok, returning {ISO_dirs}')
226
+ return ISO_dirs
125
227
 
126
228
  def main():
127
229
  parser = argparse.ArgumentParser()
128
230
  parser.add_argument(
129
231
  "directory",
130
232
  type=str,
131
- nargs='+',
132
- help="path of media directory containing Synced videos and their ISOs",
233
+ nargs=1,
234
+ help="path of media directory containing Synced videos and their .ISO folder",
133
235
  default='.'
134
236
  )
135
237
  args = parser.parse_args()
136
- # logger.info('arguments: %s'%args)
137
238
  logger.debug('args %s'%args)
138
- synciso(args.directory)
139
- # for e in keylist:
140
- # print(' ', e)
239
+ ISO_dirs = _get_ISO_dirs(args.directory[0])
240
+ logger.debug(f'Will check any change in {pformat(ISO_dirs)}')
241
+ changed_ISOs = [isod for isod in ISO_dirs if _changed(isod)]
242
+ logger.debug(f'changed_ISOs: {changed_ISOs}')
243
+ if changed_ISOs != []:
244
+ print('Will remix audio for:')
245
+ for p in changed_ISOs:
246
+ print(p.name)
247
+ newaudio_and_videos = [(get_mix_file(iso), clip_from_iso(iso)) for iso
248
+ in changed_ISOs]
249
+ for audio, video_clip in newaudio_and_videos:
250
+ print(f'Will remerge {video_clip.name}')
251
+ _join_audio2video(audio, video_clip)
252
+ if newaudio_and_videos == []:
253
+ print('Nothing has changed, bye.')
141
254
  sys.exit(0)
142
255
 
143
256
  if __name__ == '__main__':