tictacsync 1.2.0b0__tar.gz → 1.4.6b0__tar.gz
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.
- {tictacsync-1.2.0b0/tictacsync.egg-info → tictacsync-1.4.6b0}/PKG-INFO +2 -2
- {tictacsync-1.2.0b0 → tictacsync-1.4.6b0}/README.md +1 -1
- {tictacsync-1.2.0b0 → tictacsync-1.4.6b0}/setup.py +3 -2
- {tictacsync-1.2.0b0 → tictacsync-1.4.6b0}/tictacsync/device_scanner.py +23 -245
- {tictacsync-1.2.0b0 → tictacsync-1.4.6b0}/tictacsync/entry.py +15 -34
- {tictacsync-1.2.0b0 → tictacsync-1.4.6b0}/tictacsync/mamconf.py +18 -36
- tictacsync-1.4.6b0/tictacsync/mamdav.py +651 -0
- tictacsync-1.4.6b0/tictacsync/mamreap.py +484 -0
- {tictacsync-1.2.0b0 → tictacsync-1.4.6b0}/tictacsync/mamsync.py +13 -75
- {tictacsync-1.2.0b0 → tictacsync-1.4.6b0}/tictacsync/multi2polywav.py +3 -2
- {tictacsync-1.2.0b0 → tictacsync-1.4.6b0}/tictacsync/timeline.py +28 -26
- {tictacsync-1.2.0b0 → tictacsync-1.4.6b0}/tictacsync/yaltc.py +357 -29
- {tictacsync-1.2.0b0 → tictacsync-1.4.6b0/tictacsync.egg-info}/PKG-INFO +2 -2
- {tictacsync-1.2.0b0 → tictacsync-1.4.6b0}/tictacsync.egg-info/SOURCES.txt +2 -2
- {tictacsync-1.2.0b0 → tictacsync-1.4.6b0}/tictacsync.egg-info/entry_points.txt +2 -1
- tictacsync-1.2.0b0/tictacsync/newmix.py +0 -483
- tictacsync-1.2.0b0/tictacsync/remergemix.py +0 -259
- {tictacsync-1.2.0b0 → tictacsync-1.4.6b0}/LICENSE +0 -0
- {tictacsync-1.2.0b0 → tictacsync-1.4.6b0}/setup.cfg +0 -0
- {tictacsync-1.2.0b0 → tictacsync-1.4.6b0}/tictacsync/__init__.py +0 -0
- {tictacsync-1.2.0b0 → tictacsync-1.4.6b0}/tictacsync.egg-info/dependency_links.txt +0 -0
- {tictacsync-1.2.0b0 → tictacsync-1.4.6b0}/tictacsync.egg-info/not-zip-safe +0 -0
- {tictacsync-1.2.0b0 → tictacsync-1.4.6b0}/tictacsync.egg-info/requires.txt +0 -0
- {tictacsync-1.2.0b0 → tictacsync-1.4.6b0}/tictacsync.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: tictacsync
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.4.6b0
|
|
4
4
|
Summary: commands for syncing audio video recordings
|
|
5
5
|
Home-page: https://tictacsync.org/
|
|
6
6
|
Author: Raymond Lutz
|
|
@@ -23,7 +23,7 @@ License-File: LICENSE
|
|
|
23
23
|
|
|
24
24
|
# tictacsync
|
|
25
25
|
|
|
26
|
-
## Warning: this is at
|
|
26
|
+
## Warning: this is at beta stage
|
|
27
27
|
|
|
28
28
|
Unfinished sloppy code ahead, but should run without errors. Some functionalities are still missing. Don't run the code without parental supervision. Suggestions and enquiries are welcome via the [lists hosted on sourcehut](https://sr.ht/~proflutz/TicTacSync/lists).
|
|
29
29
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# tictacsync
|
|
2
2
|
|
|
3
|
-
## Warning: this is at
|
|
3
|
+
## Warning: this is at beta stage
|
|
4
4
|
|
|
5
5
|
Unfinished sloppy code ahead, but should run without errors. Some functionalities are still missing. Don't run the code without parental supervision. Suggestions and enquiries are welcome via the [lists hosted on sourcehut](https://sr.ht/~proflutz/TicTacSync/lists).
|
|
6
6
|
|
|
@@ -29,13 +29,14 @@ setup(
|
|
|
29
29
|
entry_points = {
|
|
30
30
|
"console_scripts": [
|
|
31
31
|
'tictacsync = tictacsync.entry:main',
|
|
32
|
-
'
|
|
32
|
+
'mamreap = tictacsync.mamreap:main',
|
|
33
|
+
'mamdav = tictacsync.mamdav:called_from_cli',
|
|
33
34
|
'mamsync = tictacsync.mamsync:main',
|
|
34
35
|
'mamconf = tictacsync.mamconf:main',
|
|
35
36
|
'multi2polywav = tictacsync.multi2polywav:main',
|
|
36
37
|
]
|
|
37
38
|
},
|
|
38
|
-
version = '1.
|
|
39
|
+
version = '1.4.6-beta',
|
|
39
40
|
description = "commands for syncing audio video recordings",
|
|
40
41
|
long_description_content_type='text/markdown',
|
|
41
42
|
long_description = long_descr,
|
|
@@ -3,8 +3,6 @@
|
|
|
3
3
|
# while inotifywait --recursive -e close_write . ; do python entry.py tests/multi2/; done
|
|
4
4
|
# above for linux
|
|
5
5
|
|
|
6
|
-
TRACKSFILE = 'tracks.txt'
|
|
7
|
-
SILENT_TRACK_TOKENS = '-0n'
|
|
8
6
|
|
|
9
7
|
av_file_extensions = \
|
|
10
8
|
"""webm mkv flv flv vob ogv ogg drc gif gifv mng avi MTS M2TS TS mov qt
|
|
@@ -40,10 +38,12 @@ try:
|
|
|
40
38
|
from . import multi2polywav
|
|
41
39
|
from . import mamsync
|
|
42
40
|
from . import mamconf
|
|
41
|
+
from . import yaltc
|
|
43
42
|
except:
|
|
44
43
|
import multi2polywav
|
|
45
44
|
import mamsync
|
|
46
45
|
import mamconf
|
|
46
|
+
import yaltc
|
|
47
47
|
|
|
48
48
|
MCCDIR = 'SyncedMulticamClips'
|
|
49
49
|
SYNCEDFOLDER = 'SyncedMedia'
|
|
@@ -64,10 +64,9 @@ def print_grby(grby):
|
|
|
64
64
|
print('\ngrouped by %s:'%key)
|
|
65
65
|
for e in keylist:
|
|
66
66
|
print(' ', e)
|
|
67
|
-
|
|
68
67
|
@dataclass
|
|
69
68
|
class Tracks:
|
|
70
|
-
# track numbers start at 1 for first track (as needed by sox)
|
|
69
|
+
# track numbers start at 1 for first track (as needed by sox,1 Based Index)
|
|
71
70
|
ttc: int # track number of TicTacCode signal
|
|
72
71
|
unused: list # of unused tracks
|
|
73
72
|
stereomics: list # of stereo mics track tuples (Lchan#, Rchan#)
|
|
@@ -75,7 +74,9 @@ class Tracks:
|
|
|
75
74
|
others: list #of all other tags: (tag, track#) tuples
|
|
76
75
|
rawtrx: list # list of strings read from file
|
|
77
76
|
error_msg: str # 'None' if none
|
|
78
|
-
lag_values: list # list of
|
|
77
|
+
lag_values: list # list of lags in ms, entry is None if not specified.
|
|
78
|
+
# UTC_timestamp: str # to the nearest minute ISO 8601 date and time e.g.: "2007-04-05T14:30Z"
|
|
79
|
+
|
|
79
80
|
|
|
80
81
|
@dataclass
|
|
81
82
|
class Device:
|
|
@@ -158,7 +159,7 @@ def get_device_ffprobe_UID(file):
|
|
|
158
159
|
except ffmpeg.Error as e:
|
|
159
160
|
print('ffmpeg.probe error')
|
|
160
161
|
print(e.stderr, file)
|
|
161
|
-
return None, None #-----------------------------------------------------
|
|
162
|
+
return None, None, None #-----------------------------------------------------
|
|
162
163
|
# fall back to folder name
|
|
163
164
|
logger.debug('ffprobe %s'%probe)
|
|
164
165
|
streams = probe['streams']
|
|
@@ -216,10 +217,8 @@ class Scanner:
|
|
|
216
217
|
top_directory : string
|
|
217
218
|
String of path where to start searching for media files.
|
|
218
219
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
found_media_files: list of Media objects
|
|
220
|
+
found_media_files: list of dataclass Media instances encapsulating
|
|
221
|
+
the pathlibPath and the device (of Device dataclass).
|
|
223
222
|
"""
|
|
224
223
|
|
|
225
224
|
def __init__(
|
|
@@ -272,7 +271,7 @@ class Scanner:
|
|
|
272
271
|
with open(p, 'r') as fh:
|
|
273
272
|
done = set(fh.read().split()) # sets of strings of abs path
|
|
274
273
|
logger.debug(f'done clips: {pformat(done)}')
|
|
275
|
-
files = Path(self.top_directory).rglob('*')
|
|
274
|
+
files = [p for p in Path(self.top_directory).rglob('*') if not p.name[0] == '.']
|
|
276
275
|
clip_paths = []
|
|
277
276
|
some_done = False
|
|
278
277
|
for raw_path in files:
|
|
@@ -351,17 +350,19 @@ class Scanner:
|
|
|
351
350
|
logger.debug('Scanner.found_media_files = %s'%pformat(self.found_media_files))
|
|
352
351
|
if self.input_structure == 'ordered':
|
|
353
352
|
self._confirm_folders_have_same_device()
|
|
354
|
-
#
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
for
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
353
|
+
# [TODO] move this where Recordings have been TCed for any tracks timestamps
|
|
354
|
+
# <begin>
|
|
355
|
+
# devices = set([m.device for m in self.found_media_files])
|
|
356
|
+
# audio_devices = [d for d in devices if d.dev_type == 'REC']
|
|
357
|
+
# for recorder in audio_devices:
|
|
358
|
+
# # process tracks.txt for audio recorders
|
|
359
|
+
# recorder.tracks = self._get_tracks_from_file(recorder)
|
|
360
|
+
# # logging only:
|
|
361
|
+
# if recorder.tracks:
|
|
362
|
+
# if not all([lv == None for lv in recorder.tracks.lag_values]):
|
|
363
|
+
# logger.debug('%s has lag_values %s'%(
|
|
364
|
+
# recorder.name, recorder.tracks.lag_values))
|
|
365
|
+
# </end>
|
|
365
366
|
# check if device is in fact two parents up (and parent = ROLLxx):
|
|
366
367
|
# Group media by folder 2up and verify all media for each
|
|
367
368
|
# group have same device.
|
|
@@ -388,7 +389,6 @@ class Scanner:
|
|
|
388
389
|
for m in self.found_media_files:
|
|
389
390
|
if m.device.UID == UID:
|
|
390
391
|
m.device.name = name
|
|
391
|
-
# logger.debug('renamed device media: %s'%pformat(self.found_media_files))
|
|
392
392
|
no_name_devices = [m.device for m in self.found_media_files
|
|
393
393
|
if not m.device.name]
|
|
394
394
|
# possible if self.input_structure == 'loose'
|
|
@@ -421,50 +421,6 @@ class Scanner:
|
|
|
421
421
|
if not any(dev_is_REC): # no audio recordings!
|
|
422
422
|
print('\rNo audio recording found, nothing to sync, bye.')
|
|
423
423
|
sys.exit(0)
|
|
424
|
-
# print('devices 312 %s'%set([m.device for m in self.found_media_files]))
|
|
425
|
-
|
|
426
|
-
def _get_tracks_from_file(self, device) -> Tracks:
|
|
427
|
-
"""
|
|
428
|
-
Look for eventual track names in TRACKSFILE file, stored inside the
|
|
429
|
-
recorder folder alongside the audio files. If there, returns a Tracks
|
|
430
|
-
object, if not returns None.
|
|
431
|
-
"""
|
|
432
|
-
source_audio_folder = device.folder
|
|
433
|
-
tracks_file = source_audio_folder/TRACKSFILE
|
|
434
|
-
track_names = False
|
|
435
|
-
a_recording = [m for m in self.found_media_files
|
|
436
|
-
if m.device == device][0]
|
|
437
|
-
logger.debug('a_recording for device %s : %s'%(device, a_recording))
|
|
438
|
-
nchan = sox.file_info.channels(str(a_recording.path))
|
|
439
|
-
if os.path.isfile(tracks_file):
|
|
440
|
-
logger.debug('found file: %s'%(TRACKSFILE))
|
|
441
|
-
tracks = self._parse_track_values(tracks_file)
|
|
442
|
-
if tracks.error_msg:
|
|
443
|
-
print('\nError parsing [gold1]%s[/gold1] file: %s, quitting.\n'%
|
|
444
|
-
(tracks_file, tracks.error_msg))
|
|
445
|
-
sys.exit(1)
|
|
446
|
-
logger.debug('parsed tracks %s'%tracks)
|
|
447
|
-
ntracks = 2*len(tracks.stereomics)
|
|
448
|
-
ntracks += len(tracks.mix)
|
|
449
|
-
ntracks += len(tracks.unused)
|
|
450
|
-
ntracks += len(tracks.others)
|
|
451
|
-
ntracks += 1 # for ttc track
|
|
452
|
-
logger.debug(' n chan: %i n tracks file: %i'%(nchan, ntracks))
|
|
453
|
-
if ntracks != nchan:
|
|
454
|
-
print('\nError parsing %s content'%tracks_file)
|
|
455
|
-
print('incoherent number of tracks, %i vs %i quitting\n'%
|
|
456
|
-
(nchan, ntracks))
|
|
457
|
-
sys.exit(1)
|
|
458
|
-
err_msg = tracks.error_msg
|
|
459
|
-
if err_msg != None:
|
|
460
|
-
print('\nError, quitting: in file %s, %s'%(tracks_file, err_msg))
|
|
461
|
-
raise Exception
|
|
462
|
-
else:
|
|
463
|
-
logger.debug('tracks object%s'%tracks)
|
|
464
|
-
return tracks
|
|
465
|
-
else:
|
|
466
|
-
logger.debug('no tracks.txt file found')
|
|
467
|
-
return None
|
|
468
424
|
|
|
469
425
|
def _confirm_folders_have_same_device(self):
|
|
470
426
|
"""
|
|
@@ -602,184 +558,6 @@ class Scanner:
|
|
|
602
558
|
logger.debug('n_CAM_folder %i'%n_CAM_folder)
|
|
603
559
|
return
|
|
604
560
|
|
|
605
|
-
def _parse_track_values(self, tracks_file) -> Tracks:
|
|
606
|
-
"""
|
|
607
|
-
read track names for naming separated ISOs
|
|
608
|
-
from tracks_file.
|
|
609
|
-
|
|
610
|
-
tokens looked for: mix; mix L; mix R; 0 and TC
|
|
611
|
-
|
|
612
|
-
repeating "mic*" pattern signals a stereo track
|
|
613
|
-
and entries will correspondingly panned into
|
|
614
|
-
a stero mix named mixL.wav and mixL.wav
|
|
615
|
-
|
|
616
|
-
mic L # spaces are ignored |
|
|
617
|
-
mic R | stereo pair
|
|
618
|
-
micB L
|
|
619
|
-
micB R
|
|
620
|
-
|
|
621
|
-
Returns: a Tracks instance:
|
|
622
|
-
# track numbers start at 1 for first track (as needed by sox)
|
|
623
|
-
ttc: int # track number of TicTacCode signal
|
|
624
|
-
unused: list # of unused tracks
|
|
625
|
-
stereomics: list # of stereo mics track tuples (Lchan#, Rchan#)
|
|
626
|
-
mix: list # of mixed tracks, if a pair, order is L than R
|
|
627
|
-
others: list #of all other tags: (tag, track#) tuples
|
|
628
|
-
rawtrx: list # list of strings read from file
|
|
629
|
-
error_msg: str # 'None' if none
|
|
630
|
-
e.g.: Tracks( ttc=2,
|
|
631
|
-
unused=[],
|
|
632
|
-
stereomics=[('mic', (4, 3)), ('mic2', (6, 5))],
|
|
633
|
-
mix=[], others=[('clics', 1)],
|
|
634
|
-
rawtrx=['clics', 'TC', 'micL', 'micR', 'mic2L;1000', 'mic2R;1000', 'mixL', 'mixR'],
|
|
635
|
-
error_msg=None, lag_values=[None, None, None, None, '1000', '1000', None, None])
|
|
636
|
-
"""
|
|
637
|
-
def _WOspace(chaine):
|
|
638
|
-
ch = [c for c in chaine if c != ' ']
|
|
639
|
-
return ''.join(ch)
|
|
640
|
-
# def _WO_LR(chaine):
|
|
641
|
-
# ch = [c for c in chaine if c not in 'LR']
|
|
642
|
-
# return ''.join(ch)
|
|
643
|
-
# def _seemsStereoMic(tag):
|
|
644
|
-
# # is tag likely a stereo pair tag?
|
|
645
|
-
# # should starts with 'mic' and ends with 'l' or 'r'
|
|
646
|
-
# return tag[1:4]=='mic' and tag[0] in 'lr'
|
|
647
|
-
file=open(tracks_file,"r")
|
|
648
|
-
whole_txt = file.read()
|
|
649
|
-
logger.debug('file %s all_lines:\n%s'%(tracks_file, whole_txt))
|
|
650
|
-
tracks_lines_wspaces = [l.split('#')[0] for l in whole_txt.splitlines()
|
|
651
|
-
if len(l) > 0 ]
|
|
652
|
-
tracks_lines = [_WOspace(l) for l in tracks_lines_wspaces if len(l) > 0 ]
|
|
653
|
-
rawtrx = [l for l in tracks_lines_wspaces if len(l) > 0 ]
|
|
654
|
-
# add index with tuples, starting at 1
|
|
655
|
-
logger.debug('tracks_lines whole: %s'%tracks_lines)
|
|
656
|
-
def _detach_lag_value(line):
|
|
657
|
-
# look for ";number" ending any line, returns a two-list
|
|
658
|
-
splt = line.split(';')
|
|
659
|
-
if len(splt) == 1:
|
|
660
|
-
splt += [None]
|
|
661
|
-
if len(splt) != 2:
|
|
662
|
-
# error
|
|
663
|
-
print('\nText error in %s, line %s has too many ";"'%(
|
|
664
|
-
tracks_file, line))
|
|
665
|
-
return splt
|
|
666
|
-
tracks_lines, lag_values = zip(*[_detach_lag_value(l) for l
|
|
667
|
-
in tracks_lines])
|
|
668
|
-
lag_values = [e for e in lag_values] # from tuple to list
|
|
669
|
-
# logger.debug('tracks_lines WO lag: %s'%tracks_lines)
|
|
670
|
-
tracks_lines = [l.lower() for l in tracks_lines]
|
|
671
|
-
logger.debug('tracks_lines lower case: %s'%tracks_lines)
|
|
672
|
-
# print(lag_values)
|
|
673
|
-
logger.debug('lag_values: %s'%lag_values)
|
|
674
|
-
tagsWOl_r = [e[:-1] for e in tracks_lines] # skip last letter
|
|
675
|
-
logger.debug('tags WO LR letter %s'%tagsWOl_r)
|
|
676
|
-
# find idx of start of pairs
|
|
677
|
-
# ['clics', 'TC', 'micL', 'micR', 'mic2L', 'mic2R', 'mixL', 'mixR']
|
|
678
|
-
def _micOrmix(a,b):
|
|
679
|
-
# test if same and mic mic or mix mix
|
|
680
|
-
if len(a) == 0:
|
|
681
|
-
return False
|
|
682
|
-
return (a == b) and (a in 'micmix')
|
|
683
|
-
pair_idx_start =[i for i, same in enumerate([_micOrmix(a,b) for a,b
|
|
684
|
-
in zip(tagsWOl_r,tagsWOl_r[1:])]) if same]
|
|
685
|
-
logger.debug('pair_idx_start %s'%pair_idx_start)
|
|
686
|
-
def LR_OK(idx):
|
|
687
|
-
# in tracks_lines, check if idx ends a LR pair
|
|
688
|
-
# delays, if any, have been removed
|
|
689
|
-
a = tracks_lines[idx][-1]
|
|
690
|
-
b = tracks_lines[idx+1][-1]
|
|
691
|
-
return a+b in ['lr', 'rl']
|
|
692
|
-
LR_OKs = [LR_OK(p) for p in pair_idx_start]
|
|
693
|
-
logger.debug('LR_OKs %s'%LR_OKs)
|
|
694
|
-
if not all(LR_OKs):
|
|
695
|
-
print('\nError in %s'%tracks_file)
|
|
696
|
-
print('Some tracks are paired but not L and R: %s'%rawtrx)
|
|
697
|
-
print('quitting...')
|
|
698
|
-
quit()
|
|
699
|
-
complete_pairs_idx = pair_idx_start + [i + 1 for i in pair_idx_start]
|
|
700
|
-
singles = set(range(len(tracks_lines))).difference(complete_pairs_idx)
|
|
701
|
-
logger.debug('complete_pairs_idx %s'%complete_pairs_idx)
|
|
702
|
-
logger.debug('singles %s'%singles)
|
|
703
|
-
singles_tag = [tracks_lines[i] for i in singles]
|
|
704
|
-
logger.debug('singles_tag %s'%singles_tag)
|
|
705
|
-
n_tc_token = sum([t == 'tc' for t in singles_tag])
|
|
706
|
-
logger.debug('n tc tags %s'%n_tc_token)
|
|
707
|
-
if n_tc_token == 0:
|
|
708
|
-
print('\nError in %s'%tracks_file)
|
|
709
|
-
print('with %s'%rawtrx)
|
|
710
|
-
print('no TC track found, quitting...')
|
|
711
|
-
quit()
|
|
712
|
-
if n_tc_token > 1:
|
|
713
|
-
print('\nError in %s'%tracks_file)
|
|
714
|
-
print('with %s'%rawtrx)
|
|
715
|
-
print('more than one TC track, quitting...')
|
|
716
|
-
quit()
|
|
717
|
-
output_tracks = Tracks(None,[],[],[],[],rawtrx,None,[])
|
|
718
|
-
output_tracks.ttc = tracks_lines.index('tc') + 1 # 1st = 1
|
|
719
|
-
logger.debug('ttc_chan %s'%output_tracks.ttc)
|
|
720
|
-
zeroed = [i+1 for i, t in enumerate(tracks_lines) if t == '0']
|
|
721
|
-
logger.debug('zeroed %s'%zeroed)
|
|
722
|
-
output_tracks.unused = zeroed
|
|
723
|
-
output_tracks.others = [(st, tracks_lines.index(st)+1) for st
|
|
724
|
-
in singles_tag if st not
|
|
725
|
-
in ['tc', 'monomix', '0']]
|
|
726
|
-
logger.debug('output_tracks.others %s'%output_tracks.others)
|
|
727
|
-
# check for monomix
|
|
728
|
-
if 'monomix' in tracks_lines:
|
|
729
|
-
output_tracks.mix = [tracks_lines.index('monomix')+1]
|
|
730
|
-
else:
|
|
731
|
-
output_tracks.mix = []
|
|
732
|
-
# check for stereo mix
|
|
733
|
-
def _findLR(i_first):
|
|
734
|
-
# returns L R indexes (+1 for sox non zero based indexing)
|
|
735
|
-
i_2nd = i_first + 1
|
|
736
|
-
a = tracks_lines[i_first][-1] # l|r at end
|
|
737
|
-
b = tracks_lines[i_2nd][-1] # l|r at end
|
|
738
|
-
if a == 'l':
|
|
739
|
-
if b == 'r':
|
|
740
|
-
# sequence is mixL mixR
|
|
741
|
-
return i_first+1, i_2nd+1
|
|
742
|
-
else:
|
|
743
|
-
print('\nError in %s'%tracks_file)
|
|
744
|
-
print('with %s'%rawtrx)
|
|
745
|
-
print('can not find stereo mix')
|
|
746
|
-
quit()
|
|
747
|
-
elif a == 'r':
|
|
748
|
-
if b == 'l':
|
|
749
|
-
# sequence is mixR mixL
|
|
750
|
-
return i_2nd+1, i_first+1
|
|
751
|
-
else:
|
|
752
|
-
print('\nError in %s'%tracks_file)
|
|
753
|
-
print('with %s'%rawtrx)
|
|
754
|
-
print('can not find stereo mix')
|
|
755
|
-
quit()
|
|
756
|
-
logger.debug('for now, output_tracks.mix %s'%output_tracks.mix)
|
|
757
|
-
mix_pair = [p for p in pair_idx_start if tracks_lines[p][1:] == 'mix']
|
|
758
|
-
if len(mix_pair) == 1:
|
|
759
|
-
# one stereo mix, remove it from other pairs
|
|
760
|
-
i = mix_pair[0]
|
|
761
|
-
LR_pair = _findLR(i)
|
|
762
|
-
logger.debug('LR_pair %s'%str(LR_pair))
|
|
763
|
-
pair_idx_start.remove(i)
|
|
764
|
-
# consistency check
|
|
765
|
-
if output_tracks.mix != []:
|
|
766
|
-
# already found a mono mix above!
|
|
767
|
-
print('\nError in %s'%tracks_file)
|
|
768
|
-
print('with %s'%rawtrx)
|
|
769
|
-
print('found a mono mix AND a stereo mix')
|
|
770
|
-
quit()
|
|
771
|
-
output_tracks.mix = LR_pair
|
|
772
|
-
logger.debug('finally, output_tracks.mix %s'%str(output_tracks.mix))
|
|
773
|
-
logger.debug('remaining pairs %s'%pair_idx_start)
|
|
774
|
-
# those are stereo pairs
|
|
775
|
-
stereo_pairs = []
|
|
776
|
-
for first_in_pair in pair_idx_start:
|
|
777
|
-
suffix = tracks_lines[first_in_pair][:-1]
|
|
778
|
-
stereo_pairs.append((suffix, _findLR(first_in_pair)))
|
|
779
|
-
logger.debug('stereo_pairs %s'%stereo_pairs)
|
|
780
|
-
output_tracks.stereomics = stereo_pairs
|
|
781
|
-
logger.debug('finished: %s'%output_tracks)
|
|
782
|
-
return output_tracks
|
|
783
561
|
|
|
784
562
|
|
|
785
563
|
|
|
@@ -84,7 +84,11 @@ def process_lag_adjustement(media_object):
|
|
|
84
84
|
media_object.path.replace(backup_name)
|
|
85
85
|
logger.debug('channels %s'%channels)
|
|
86
86
|
def _trim(lag, chan_file):
|
|
87
|
-
#
|
|
87
|
+
# counter intuitive I know. if a file lags, there's too
|
|
88
|
+
# much samples at the start:
|
|
89
|
+
# ..................|.........
|
|
90
|
+
# .......................|....
|
|
91
|
+
# ^ play head ->
|
|
88
92
|
if lag == None:
|
|
89
93
|
return chan_file
|
|
90
94
|
else:
|
|
@@ -110,24 +114,13 @@ def main():
|
|
|
110
114
|
parser.add_argument(
|
|
111
115
|
"path",
|
|
112
116
|
type=str,
|
|
113
|
-
nargs=
|
|
117
|
+
nargs=1,
|
|
114
118
|
help="directory_name or media_file"
|
|
115
119
|
)
|
|
116
|
-
# parser.add_argument("directory", nargs="?", help="path of media directory")
|
|
117
|
-
# parser.add_argument('-v', action='store_true')
|
|
118
120
|
parser.add_argument('-v',
|
|
119
121
|
action='store_true', #ie default False
|
|
120
122
|
dest='verbose_output',
|
|
121
123
|
help='Set verbose ouput')
|
|
122
|
-
# parser.add_argument('--stop_mirroring',
|
|
123
|
-
# action='store_true', #ie default False
|
|
124
|
-
# dest='stop_mirroring',
|
|
125
|
-
# help='Stop mirroring mode, will write synced files alongside originals.')
|
|
126
|
-
# parser.add_argument('--start-project', '-s' ,
|
|
127
|
-
# nargs=2,
|
|
128
|
-
# dest='proj_folders',
|
|
129
|
-
# default = [],
|
|
130
|
-
# help='start mirrored tree output mode and specifies 2 folders: source (RAW) and destination (synced).')
|
|
131
124
|
parser.add_argument('-t','--timelineoffset',
|
|
132
125
|
nargs=1,
|
|
133
126
|
default=['00:00:00:00'],
|
|
@@ -141,10 +134,6 @@ def main():
|
|
|
141
134
|
action='store_true',
|
|
142
135
|
dest='dont_write_cam_folder',
|
|
143
136
|
help="Even if originals are inside CAM folders, don't put synced clips inside a CAM identified folder")
|
|
144
|
-
# parser.add_argument('-m',
|
|
145
|
-
# action='store_true',
|
|
146
|
-
# dest='multicam',
|
|
147
|
-
# help='Outputs multicam structure for NLE program (based on Davinci Resolve input processing)')
|
|
148
137
|
parser.add_argument('--isos',
|
|
149
138
|
action='store_true',
|
|
150
139
|
dest='write_ISOs',
|
|
@@ -165,14 +154,10 @@ def main():
|
|
|
165
154
|
if args.verbose_output:
|
|
166
155
|
logger.add(sys.stderr, level="DEBUG")
|
|
167
156
|
|
|
168
|
-
# logger.add(sys.stdout, filter=lambda r: r["function"] == "_write_ISOs")
|
|
169
|
-
logger.add(sys.stdout, filter=lambda r: r["function"] == "_build_and_write_audio")
|
|
170
|
-
#
|
|
171
|
-
# logger.add(sys.stdout, filter="__main__")
|
|
172
|
-
# logger.add(sys.stdout, filter="yaltc")
|
|
173
|
-
|
|
174
157
|
# logger.add(sys.stdout, filter=lambda r: r["function"] == "move_multicam_to_dir")
|
|
175
|
-
# logger.add(sys.stdout, filter=lambda r: r["function"] == "
|
|
158
|
+
# logger.add(sys.stdout, filter=lambda r: r["function"] == "_build_audio_and_write_video")
|
|
159
|
+
# logger.add(sys.stdout, filter=lambda r: r["function"] == "main")
|
|
160
|
+
# logger.add(sys.stdout, filter=lambda r: r["function"] == "_build_from_tracks_txt")
|
|
176
161
|
# logger.add(sys.stdout, filter=lambda r: r["function"] == "scan_media_and_build_devices_UID")
|
|
177
162
|
|
|
178
163
|
top_dir = args.path[0]
|
|
@@ -241,7 +226,6 @@ def main():
|
|
|
241
226
|
print('resulting in undefined results: quitting...')
|
|
242
227
|
quit()
|
|
243
228
|
print()
|
|
244
|
-
# recordings, rec_with_TTC = process_files(scanner.found_media_files, args)
|
|
245
229
|
recordings = [yaltc.Recording(m, do_plots=args.plotting) for m
|
|
246
230
|
in scanner.found_media_files]
|
|
247
231
|
recordings_with_time = [
|
|
@@ -249,6 +233,11 @@ def main():
|
|
|
249
233
|
for rec in recordings
|
|
250
234
|
if rec.get_start_time()
|
|
251
235
|
]
|
|
236
|
+
[r.load_track_info() for r in recordings_with_time if r.is_audio()]
|
|
237
|
+
for r in recordings:
|
|
238
|
+
# print(f'{r} device: #{id(r.device):x}')
|
|
239
|
+
logger.debug(f'{r} \nDevice instance id: #{id(r.device):x}')
|
|
240
|
+
logger.debug(f'device content: {r.device}')
|
|
252
241
|
if audio_REC_only:
|
|
253
242
|
for rec in recordings:
|
|
254
243
|
# print(rec, rec.device == ref_device)
|
|
@@ -304,15 +293,7 @@ def main():
|
|
|
304
293
|
if asked_ISOs and scanner.input_structure != 'ordered':
|
|
305
294
|
print('Warning, can\'t write ISOs without structured folders: [gold1]--isos[/gold1] option ignored.\n')
|
|
306
295
|
asked_ISOs = False
|
|
307
|
-
|
|
308
|
-
# if args.verbose_output or args.terse: # verbose, so no progress bars
|
|
309
|
-
print('Merging...')
|
|
310
|
-
# for merger in matcher.mergers:
|
|
311
|
-
# merger.build_audio_and_write_merged_media(top_dir,
|
|
312
|
-
# args.dont_write_cam_folder,
|
|
313
|
-
# asked_ISOs,
|
|
314
|
-
# audio_REC_only)
|
|
315
|
-
for merger in matcher.mergers:
|
|
296
|
+
for merger in track(matcher.mergers, description='Merging audio with video...'):
|
|
316
297
|
if audio_REC_only:
|
|
317
298
|
# rare
|
|
318
299
|
merger._build_and_write_audio(top_dir)
|
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
import argparse, platformdirs, configparser, sys
|
|
2
2
|
from loguru import logger
|
|
3
|
-
from pprint import
|
|
3
|
+
from pprint import pformat
|
|
4
4
|
from pathlib import Path
|
|
5
|
+
from rich import print
|
|
6
|
+
|
|
7
|
+
# [TODO] add in the doc:
|
|
8
|
+
# RAWROOT (sources with TC): "/Users/foobar/movies/MyBigMovie/"
|
|
9
|
+
# SYNCEDROOT (where RAWROOT will be mirrored, but with synced clips): "/Users/foobar/synced"
|
|
10
|
+
# SNDROOT (destination of ISOs sound files): "/Users/foobar/MovieSounds"
|
|
11
|
+
# then
|
|
12
|
+
# "/Users/foobar/synced/MyBigMovie" and "/Users/foobar/MovieSounds/MyBigMovie" will be created
|
|
5
13
|
|
|
6
14
|
|
|
7
15
|
CONF_FILE = 'mamsync.cfg'
|
|
@@ -13,8 +21,8 @@ logger.remove()
|
|
|
13
21
|
|
|
14
22
|
|
|
15
23
|
def print_out_conf(raw_root, synced_root, snd_root, proxies=''):
|
|
16
|
-
print(f'RAWROOT (
|
|
17
|
-
print(f'SYNCEDROOT (
|
|
24
|
+
print(f'RAWROOT (sources with TC): "{raw_root}"')
|
|
25
|
+
print(f'SYNCEDROOT (where RAWROOT will be mirrored, but with synced clips): "{synced_root}"')
|
|
18
26
|
print(f'SNDROOT (destination of ISOs sound files): "{snd_root}"')
|
|
19
27
|
if proxies != '':
|
|
20
28
|
print(f'PROXIES (NLE proxy clips folder): "{proxies}"')
|
|
@@ -48,11 +56,12 @@ def get_proj(print_conf_stdout=False):
|
|
|
48
56
|
# returns a tuple of strings (RAWROOT, SYNCEDROOTS, SNDROOT, PROXIES)
|
|
49
57
|
# if any, or a tuple of 4 empty strings '' otherwise.
|
|
50
58
|
# print location of conf file if print_conf_stdout
|
|
59
|
+
# Note: only raw_root contains the name project
|
|
51
60
|
conf_dir = platformdirs.user_config_dir('mamsync', 'plutz')
|
|
52
61
|
conf_file = Path(conf_dir)/CONF_FILE
|
|
53
62
|
logger.debug('try reading config in %s'%conf_file)
|
|
54
63
|
if print_conf_stdout:
|
|
55
|
-
print(f'
|
|
64
|
+
print(f'Will read configuration from file {conf_file}')
|
|
56
65
|
if conf_file.exists():
|
|
57
66
|
conf_prs = configparser.ConfigParser()
|
|
58
67
|
conf_prs.read(conf_file)
|
|
@@ -82,22 +91,22 @@ def get_proj(print_conf_stdout=False):
|
|
|
82
91
|
|
|
83
92
|
def new_parser():
|
|
84
93
|
parser = argparse.ArgumentParser()
|
|
85
|
-
parser.add_argument('--
|
|
94
|
+
parser.add_argument('--rr',
|
|
86
95
|
nargs = 1,
|
|
87
96
|
dest='rawroot',
|
|
88
97
|
help='Sets new value for raw root folder (i.e.: clips with TC)')
|
|
89
|
-
parser.add_argument('--
|
|
98
|
+
parser.add_argument('--sr',
|
|
90
99
|
nargs = 1,
|
|
91
100
|
dest='syncedroot',
|
|
92
101
|
help="""Sets where the synced files will be written, to be used by the NLE. Will contain a mirror copy of RAWROOT """)
|
|
93
|
-
parser.add_argument('--
|
|
102
|
+
parser.add_argument('--pr',
|
|
94
103
|
nargs = 1,
|
|
95
104
|
dest='proxies',
|
|
96
105
|
help='Sets where the proxy files are stored by the NLE')
|
|
97
|
-
parser.add_argument('--
|
|
106
|
+
parser.add_argument('--sf',
|
|
98
107
|
nargs = 1,
|
|
99
108
|
dest='sndfolder',
|
|
100
|
-
help='Sets
|
|
109
|
+
help='Sets value for sound folder (will contain a mirror copy of RAWROOT, but with ISO files only)')
|
|
101
110
|
parser.add_argument('--clearconf',
|
|
102
111
|
action='store_true',
|
|
103
112
|
dest='clearconf',
|
|
@@ -143,33 +152,6 @@ def main():
|
|
|
143
152
|
get_proj()
|
|
144
153
|
print_out_conf(*get_proj(True))
|
|
145
154
|
sys.exit(0)
|
|
146
|
-
# roots = get_proj(False)
|
|
147
|
-
# if any([r == '' for r in roots]):
|
|
148
|
-
# print("Can't sync if some folders are not set:")
|
|
149
|
-
# print_out_conf(*get_proj())
|
|
150
|
-
# print('Bye.')
|
|
151
|
-
# sys.exit(0)
|
|
152
|
-
# for r in roots:
|
|
153
|
-
# if not r.is_absolute():
|
|
154
|
-
# print(f'\rError: folder {r} must be an absolute path. Bye')
|
|
155
|
-
# sys.exit(0)
|
|
156
|
-
# if not r.exists():
|
|
157
|
-
# print(f'\rError: folder {r} does not exist. Bye')
|
|
158
|
-
# sys.exit(0)
|
|
159
|
-
# if not r.is_dir():
|
|
160
|
-
# print(f'\rError: path {r} is not a folder. Bye')
|
|
161
|
-
# sys.exit(0)
|
|
162
|
-
# raw_root, synced_root, snd_root = roots
|
|
163
|
-
# if args.sub_dir != None:
|
|
164
|
-
# top_dir = args.sub_dir
|
|
165
|
-
# logger.debug(f'sub _dir: {args.sub_dir}')
|
|
166
|
-
# if not Path(top_dir).exists():
|
|
167
|
-
# print(f"\rError: folder {top_dir} doesn't exist, bye.")
|
|
168
|
-
# sys.exit(0)
|
|
169
|
-
# else:
|
|
170
|
-
# top_dir = raw_root
|
|
171
|
-
# if args.resync:
|
|
172
|
-
# clear_log()
|
|
173
155
|
|
|
174
156
|
if __name__ == '__main__':
|
|
175
157
|
main()
|