[READ-ONLY] Mirror of https://github.com/mrgnw/scripts.
1.7 kB
76 lines
1#!/usr/bin/env python3
2
3import subprocess
4from pathlib import Path
5import sys
6from concurrent.futures import ThreadPoolExecutor, as_completed
7import os
8
9
10def main():
11 files = get_files(sys.argv[1:])
12 with ThreadPoolExecutor(max_workers=32) as executor:
13 future_to_file = {executor.submit(get_duration, file): file for file in files}
14 durations = {
15 str(future_to_file[future]): future.result()
16 for future in as_completed(future_to_file)
17 if future.result() > 0
18 }
19 dur_strs = [f'{format_time(duration)}\t{file}' for file, duration in durations.items()]
20 print('\n'.join(dur_strs))
21 total_seconds = sum(durations.values())
22 print('Total playtime:', format_time(total_seconds))
23
24
25def get_files(args):
26 files = []
27 if not args:
28 files.extend(scan_directory('.'))
29 else:
30 for arg in args:
31 path = Path(arg)
32 if path.is_dir():
33 files.extend(scan_directory(arg))
34 else:
35 files.extend(scan_directory('.', pattern=arg))
36 return [file for file in files if file.is_file()]
37
38
39def scan_directory(directory, pattern='*'):
40 with os.scandir(directory) as it:
41 for entry in it:
42 if entry.is_file() and Path(entry.name).match(pattern):
43 yield Path(entry.path)
44
45
46def get_duration(filename):
47 try:
48 result = subprocess.run(
49 [
50 'ffprobe',
51 '-v',
52 'error',
53 '-show_entries',
54 'format=duration',
55 '-of',
56 'default=noprint_wrappers=1:nokey=1',
57 filename,
58 ],
59 stdout=subprocess.PIPE,
60 stderr=subprocess.STDOUT,
61 universal_newlines=True,
62 )
63 return float(result.stdout.strip())
64 except Exception:
65 return 0
66
67
68def format_time(seconds):
69 h = int(seconds // 3600)
70 m = int((seconds % 3600) // 60)
71 s = int(seconds % 60)
72 return f'{h:2d}h {m:2d}m {s:2d}s'
73
74
75if __name__ == '__main__':
76 main()