Commit 37eefbba 37eefbba91b99fed15872cd465ce39f5713598cd by 沈秋雨

refactor(crawler): 调整oss路径结构以统一目录层级

- 修改路径顺序,将平台(platform)调整至类别(category)之后
1 parent 7ef2362f
...@@ -108,4 +108,4 @@ def build_oss_key(platform: str, category: str, filename: str) -> str: ...@@ -108,4 +108,4 @@ def build_oss_key(platform: str, category: str, filename: str) -> str:
108 category: 'audio' | 'cover' | 'singer' | 'album' 108 category: 'audio' | 'cover' | 'singer' | 'album'
109 filename: 带扩展名的文件名 109 filename: 带扩展名的文件名
110 """ 110 """
111 return f"crawler/{platform}/{category}/{filename}" 111 return f"crawler/{category}/{platform}/{filename}"
......
...@@ -113,7 +113,7 @@ def upload_plain_lyric_to_bucket(platform: str, unique_id: str, lyric: str, buck ...@@ -113,7 +113,7 @@ def upload_plain_lyric_to_bucket(platform: str, unique_id: str, lyric: str, buck
113 plain_lyric = extract_plain_lyric(lyric) 113 plain_lyric = extract_plain_lyric(lyric)
114 if not plain_lyric: 114 if not plain_lyric:
115 return "" 115 return ""
116 oss_key = f"crawler/{platform}/lyric/{unique_id}.txt" 116 oss_key = f"crawler/lyric/{platform}/{unique_id}.txt"
117 bucket.put_object(oss_key, plain_lyric.encode("utf-8"), headers={'Content-Type': 'text/plain; charset=utf-8'}) 117 bucket.put_object(oss_key, plain_lyric.encode("utf-8"), headers={'Content-Type': 'text/plain; charset=utf-8'})
118 return f"{base_url.rstrip('/')}/{oss_key}" 118 return f"{base_url.rstrip('/')}/{oss_key}"
119 119
......
...@@ -42,9 +42,9 @@ def test_external_url_downloads_and_uploads(): ...@@ -42,9 +42,9 @@ def test_external_url_downloads_and_uploads():
42 with patch('etl_to_crawler.oss._http_get') as mock_get: 42 with patch('etl_to_crawler.oss._http_get') as mock_get:
43 mock_get.return_value.content = fake_content 43 mock_get.return_value.content = fake_content
44 mock_get.return_value.raise_for_status = MagicMock() 44 mock_get.return_value.raise_for_status = MagicMock()
45 result = transfer_url(OTHER_URL, "crawler/qq/audio/abc.mp3", bucket, BASE_URL) 45 result = transfer_url(OTHER_URL, "crawler/audio/qq/abc.mp3", bucket, BASE_URL)
46 bucket.put_object.assert_called_once_with("crawler/qq/audio/abc.mp3", fake_content) 46 bucket.put_object.assert_called_once_with("crawler/audio/qq/abc.mp3", fake_content)
47 assert result == f"{BASE_URL}/crawler/qq/audio/abc.mp3" 47 assert result == f"{BASE_URL}/crawler/audio/qq/abc.mp3"
48 48
49 49
50 def test_external_url_can_rewrite_download_base_to_internal_endpoint(): 50 def test_external_url_can_rewrite_download_base_to_internal_endpoint():
...@@ -59,11 +59,11 @@ def test_external_url_can_rewrite_download_base_to_internal_endpoint(): ...@@ -59,11 +59,11 @@ def test_external_url_can_rewrite_download_base_to_internal_endpoint():
59 with patch('etl_to_crawler.oss._http_get') as mock_get: 59 with patch('etl_to_crawler.oss._http_get') as mock_get:
60 mock_get.return_value.content = fake_content 60 mock_get.return_value.content = fake_content
61 mock_get.return_value.raise_for_status = MagicMock() 61 mock_get.return_value.raise_for_status = MagicMock()
62 result = transfer_url(public_source, "crawler/qq/audio/abc.mp3", bucket, BASE_URL) 62 result = transfer_url(public_source, "crawler/audio/qq/abc.mp3", bucket, BASE_URL)
63 63
64 mock_get.assert_called_once_with(f"{internal_source_base}/audio/abc.mp3", timeout=30) 64 mock_get.assert_called_once_with(f"{internal_source_base}/audio/abc.mp3", timeout=30)
65 bucket.put_object.assert_called_once_with("crawler/qq/audio/abc.mp3", fake_content) 65 bucket.put_object.assert_called_once_with("crawler/audio/qq/abc.mp3", fake_content)
66 assert result == f"{BASE_URL}/crawler/qq/audio/abc.mp3" 66 assert result == f"{BASE_URL}/crawler/audio/qq/abc.mp3"
67 67
68 68
69 def test_transfer_url_with_md5_hashes_downloaded_content_before_upload(): 69 def test_transfer_url_with_md5_hashes_downloaded_content_before_upload():
...@@ -72,9 +72,9 @@ def test_transfer_url_with_md5_hashes_downloaded_content_before_upload(): ...@@ -72,9 +72,9 @@ def test_transfer_url_with_md5_hashes_downloaded_content_before_upload():
72 with patch('etl_to_crawler.oss._http_get') as mock_get: 72 with patch('etl_to_crawler.oss._http_get') as mock_get:
73 mock_get.return_value.content = fake_content 73 mock_get.return_value.content = fake_content
74 mock_get.return_value.raise_for_status = MagicMock() 74 mock_get.return_value.raise_for_status = MagicMock()
75 result, audio_md5 = transfer_url_with_md5(OTHER_URL, "crawler/qq/audio/abc.mp3", bucket, BASE_URL) 75 result, audio_md5 = transfer_url_with_md5(OTHER_URL, "crawler/audio/qq/abc.mp3", bucket, BASE_URL)
76 bucket.put_object.assert_called_once_with("crawler/qq/audio/abc.mp3", fake_content) 76 bucket.put_object.assert_called_once_with("crawler/audio/qq/abc.mp3", fake_content)
77 assert result == f"{BASE_URL}/crawler/qq/audio/abc.mp3" 77 assert result == f"{BASE_URL}/crawler/audio/qq/abc.mp3"
78 assert audio_md5 == "04d43544b267629d9089eaed3b847a99" 78 assert audio_md5 == "04d43544b267629d9089eaed3b847a99"
79 79
80 80
...@@ -84,11 +84,11 @@ def test_audio_transfer_retries_timeout_then_uploads(): ...@@ -84,11 +84,11 @@ def test_audio_transfer_retries_timeout_then_uploads():
84 response.raise_for_status.return_value = None 84 response.raise_for_status.return_value = None
85 with patch('etl_to_crawler.oss._http_get', side_effect=[requests.ReadTimeout('slow'), response]) as mock_get: 85 with patch('etl_to_crawler.oss._http_get', side_effect=[requests.ReadTimeout('slow'), response]) as mock_get:
86 with patch('etl_to_crawler.oss.time.sleep') as mock_sleep: 86 with patch('etl_to_crawler.oss.time.sleep') as mock_sleep:
87 result, _ = transfer_url_with_md5(OTHER_URL, 'crawler/qq/audio/abc.mp3', bucket, BASE_URL) 87 result, _ = transfer_url_with_md5(OTHER_URL, 'crawler/audio/qq/abc.mp3', bucket, BASE_URL)
88 88
89 assert mock_get.call_count == 2 89 assert mock_get.call_count == 2
90 mock_sleep.assert_called_once() 90 mock_sleep.assert_called_once()
91 assert result == f"{BASE_URL}/crawler/qq/audio/abc.mp3" 91 assert result == f"{BASE_URL}/crawler/audio/qq/abc.mp3"
92 92
93 93
94 def test_transfer_does_not_retry_not_found_response(): 94 def test_transfer_does_not_retry_not_found_response():
...@@ -98,7 +98,7 @@ def test_transfer_does_not_retry_not_found_response(): ...@@ -98,7 +98,7 @@ def test_transfer_does_not_retry_not_found_response():
98 with patch('etl_to_crawler.oss._http_get', side_effect=error) as mock_get: 98 with patch('etl_to_crawler.oss._http_get', side_effect=error) as mock_get:
99 with patch('etl_to_crawler.oss.time.sleep') as mock_sleep: 99 with patch('etl_to_crawler.oss.time.sleep') as mock_sleep:
100 try: 100 try:
101 transfer_url_with_md5(OTHER_URL, 'crawler/qq/audio/abc.mp3', bucket, BASE_URL) 101 transfer_url_with_md5(OTHER_URL, 'crawler/audio/qq/abc.mp3', bucket, BASE_URL)
102 except requests.HTTPError: 102 except requests.HTTPError:
103 pass 103 pass
104 else: 104 else:
......
...@@ -522,5 +522,5 @@ def test_process_netease_keeps_timestamped_lyric_and_uploads_plain_lyric(monkeyp ...@@ -522,5 +522,5 @@ def test_process_netease_keeps_timestamped_lyric_and_uploads_plain_lyric(monkeyp
522 522
523 assert inserted_songs[0]['lyric'] == '[ti:歌名]\n[00:01.00]第一句\n[00:02.00]第二句' 523 assert inserted_songs[0]['lyric'] == '[ti:歌名]\n[00:01.00]第一句\n[00:02.00]第二句'
524 assert inserted_songs[0]['audio_md5'] == 'audio-md5' 524 assert inserted_songs[0]['audio_md5'] == 'audio-md5'
525 assert inserted_songs[0]['lyric_url'] == 'https://bucket.example.com/crawler/netease/lyric/300.txt' 525 assert inserted_songs[0]['lyric_url'] == 'https://bucket.example.com/crawler/lyric/netease/300.txt'
526 assert uploaded['body'].decode('utf-8') == '第一句\n第二句' 526 assert uploaded['body'].decode('utf-8') == '第一句\n第二句'
......