Commit 63589d3c 63589d3c84acde4f51e11b0857525c12c41cbca2 by 沈秋雨

更新支持pg下载多版本歌曲

1 parent 5ae39abf
1 #!/usr/bin/env python3
2 import argparse
3 import csv
4 import os
5 import re
6 import sys
7 from pathlib import Path
8 from urllib.parse import urlparse
9
10 from dotenv import load_dotenv
11 from qcloud_cos import CosConfig, CosS3Client
12
13 load_dotenv(Path(__file__).resolve().parents[1] / '.env')
14
15 AUDIO_EXTS = {'.mp3', '.wav', '.flac', '.m4a', '.aac', '.ogg', '.wma', '.ape', '.alac'}
16
17
18 def normalize_key(raw_url: str) -> str:
19 if not raw_url:
20 return ''
21 raw_url = raw_url.strip()
22 if re.match(r'^https?://', raw_url, re.I):
23 return urlparse(raw_url).path.lstrip('/')
24 return raw_url.lstrip('/')
25
26
27 def ext_ok(path: str) -> bool:
28 return Path(path).suffix.lower() in AUDIO_EXTS
29
30
31 def main():
32 ap = argparse.ArgumentParser()
33 ap.add_argument('--manifest', default='output_selection_budgeted/selected_files.csv')
34 ap.add_argument('--output-dir', default='downloads')
35 ap.add_argument('--types', default='1,7,8,11,16')
36 ap.add_argument('--song-limit', type=int, default=3)
37 ap.add_argument('--start-song-offset', type=int, default=0)
38 ap.add_argument('--overwrite', action='store_true')
39 ap.add_argument('--fail-log', default='download_failures.csv')
40 args = ap.parse_args()
41
42 region = os.environ['COS_REGION']
43 secret_id = os.environ['COS_SECRET_ID']
44 secret_key = os.environ['COS_SECRET_KEY']
45 bucket = os.environ['COS_BUCKET']
46
47 config = CosConfig(Region=region, SecretId=secret_id, SecretKey=secret_key)
48 client = CosS3Client(config)
49 wanted_types = {int(x) for x in args.types.split(',') if x.strip()}
50
51 out_dir = Path(args.output_dir)
52 out_dir.mkdir(parents=True, exist_ok=True)
53 fail_log = Path(args.fail_log)
54 fail_exists = fail_log.exists()
55 fail_f = fail_log.open('a', encoding='utf-8', newline='')
56 fail_w = csv.writer(fail_f)
57 if not fail_exists:
58 fail_w.writerow(['song_id', 'type', 'url', 'error'])
59
60 downloaded = skipped = errors = 0
61 active_song_ids = []
62 current_song = None
63 started = False
64 song_counter = 0
65
66 with open(args.manifest, 'r', encoding='utf-8', newline='') as f:
67 reader = csv.DictReader(f)
68 for row in reader:
69 sid = row['song_id']
70 if sid != current_song:
71 current_song = sid
72 if song_counter < args.start_song_offset:
73 song_counter += 1
74 continue
75 if args.song_limit and started and len(active_song_ids) >= args.song_limit and sid not in set(active_song_ids):
76 break
77 if sid not in active_song_ids:
78 active_song_ids.append(sid)
79 started = True
80 if sid not in active_song_ids:
81 continue
82 try:
83 t = int(row['type'])
84 except Exception:
85 skipped += 1
86 continue
87 if t not in wanted_types:
88 skipped += 1
89 continue
90 key = normalize_key(row['url'])
91 if not key or not ext_ok(key):
92 skipped += 1
93 continue
94 target_dir = out_dir / sid / f'type_{t}'
95 target_dir.mkdir(parents=True, exist_ok=True)
96 target = target_dir / Path(key).name
97 if target.exists() and not args.overwrite:
98 skipped += 1
99 continue
100 try:
101 client.download_file(Bucket=bucket, Key=key, DestFilePath=str(target))
102 downloaded += 1
103 if downloaded % 50 == 0:
104 print({'downloaded': downloaded, 'songs': len(active_song_ids), 'last': str(target)})
105 except Exception as e:
106 errors += 1
107 fail_w.writerow([sid, t, row['url'], str(e)])
108 fail_f.flush()
109 print({'error_song': sid, 'type': t, 'key': key, 'error': str(e)}, file=sys.stderr)
110
111 fail_f.close()
112 print({
113 'downloaded_files': downloaded,
114 'skipped_rows': skipped,
115 'error_files': errors,
116 'song_count': len(active_song_ids),
117 'output_dir': str(out_dir.resolve()),
118 })
119
120
121 if __name__ == '__main__':
122 main()