SilverElixir commited on
Commit
eb3b809
·
1 Parent(s): 4e6721e

TikTok music: unswap TikWM title/author when title is author handle

Browse files
Files changed (2) hide show
  1. lumen_tiktok_flow.py +13 -0
  2. tests/test_bot_tiktok.py +56 -0
lumen_tiktok_flow.py CHANGED
@@ -84,6 +84,19 @@ async def _send_tiktok_music(session, media_data: dict, message: Message, author
84
  # Именованный трек или "оригинальный" с названием — реальное название важнее подписи; очищенный остаток — если был префикс.
85
  cleaned_title = residual_title if (mentions_generic_phrase and residual_title) else raw_music_title
86
  performer_name = raw_music_author
 
 
 
 
 
 
 
 
 
 
 
 
 
87
 
88
  # достаём обложку трека
89
  cover_url = music_info.get("cover") or music_info.get("avatar") or media_data.get("author", {}).get("avatar")
 
84
  # Именованный трек или "оригинальный" с названием — реальное название важнее подписи; очищенный остаток — если был префикс.
85
  cleaned_title = residual_title if (mentions_generic_phrase and residual_title) else raw_music_title
86
  performer_name = raw_music_author
87
+ # TikWM иногда привозит поля перевёрнутыми (прод 22.09.2026: в title лежал юзернейм
88
+ # автора видео, в author — название трека; по той же ссылке в другой раз — наоборот).
89
+ # Чиним очевидный случай: название без единого пробела совпало с хендлом автора видео,
90
+ # а в "авторе" — фраза с пробелами. Однословный настоящий трек под правило не попадает:
91
+ # он не равен хендлу автора.
92
+ _title_handle = cleaned_title.strip().lower().lstrip("@")
93
+ _known_handles = {h for h in (author_uniq_clean.lower(), author_nick.lower()) if h}
94
+ if _title_handle in _known_handles and re.search(r"\s", performer_name or ""):
95
+ log.info(
96
+ "[tiktok-music][diag] Swapped music title/author from TikWM (title=%r looked like author handle, author=%r looked like a title) — unswapping.",
97
+ cleaned_title, performer_name,
98
+ )
99
+ cleaned_title, performer_name = performer_name, author_uniq_clean or author_nick or performer_name
100
 
101
  # достаём обложку трека
102
  cover_url = music_info.get("cover") or music_info.get("avatar") or media_data.get("author", {}).get("avatar")
tests/test_bot_tiktok.py CHANGED
@@ -1146,6 +1146,62 @@ def test_send_tiktok_music_passes_audio_duration():
1146
  bot.chat_state.pop(999452, None)
1147
 
1148
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1149
  def test_single_video_status_deleted_after_music():
1150
  # Статус живёт и во время скачивания музыки тоже — сносится только после неё, а не до.
1151
  import lumen_tiktok_flow
 
1146
  bot.chat_state.pop(999452, None)
1147
 
1148
 
1149
+ def _run_music_capturing_audio(media_data, chat_id=999454):
1150
+ import lumen_tiktok_flow
1151
+ incoming = _FakeIncomingMessage(chat_id)
1152
+ incoming.message_id = 1
1153
+ incoming.from_user = SimpleNamespace(language_code="ru")
1154
+ sent = {}
1155
+
1156
+ class _AudioBot:
1157
+ async def send_audio(self, **kwargs):
1158
+ sent.update(kwargs)
1159
+ return SimpleNamespace()
1160
+
1161
+ async def fake_download(session, url, headers=None):
1162
+ return b"fake-bytes"
1163
+
1164
+ def fake_write_tags(path, title, artist, cover):
1165
+ pass
1166
+
1167
+ original_download = bot._download_url_bin
1168
+ original_write_tags = bot._write_mp3_tags
1169
+ original_bot = bot.bot
1170
+ bot._download_url_bin = fake_download
1171
+ bot._write_mp3_tags = fake_write_tags
1172
+ bot.bot = _AudioBot()
1173
+ try:
1174
+ asyncio.run(lumen_tiktok_flow._send_tiktok_music(None, media_data, incoming, "Nick", {}))
1175
+ finally:
1176
+ bot._download_url_bin = original_download
1177
+ bot._write_mp3_tags = original_write_tags
1178
+ bot.bot = original_bot
1179
+ bot.chat_state.pop(chat_id, None)
1180
+ return sent
1181
+
1182
+
1183
+ def test_send_tiktok_music_unswaps_tikwm_title_author():
1184
+ # Прод 22.09.2026: TikWM иногда кладёт юзернейм в title, а название трека — в author.
1185
+ sent = _run_music_capturing_audio({
1186
+ "music": "https://tikwm.com/song.mp3",
1187
+ "music_info": {"title": "milka_kicm12", "author": "Миля, ты че творишь"},
1188
+ "author": {"nickname": "Milka", "unique_id": "milka_kicm12"},
1189
+ })
1190
+ assert sent.get("title") == "Миля, ты че творишь"
1191
+ assert sent.get("performer") == "milka_kicm12"
1192
+
1193
+
1194
+ def test_send_tiktok_music_keeps_one_word_track_title():
1195
+ # Однословный настоящий трек НЕ равен хендлу автора — не трогаем.
1196
+ sent = _run_music_capturing_audio({
1197
+ "music": "https://tikwm.com/song.mp3",
1198
+ "music_info": {"title": "Believer", "author": "Imagine Dragons"},
1199
+ "author": {"nickname": "Other", "unique_id": "other_user"},
1200
+ })
1201
+ assert sent.get("title") == "Believer"
1202
+ assert sent.get("performer") == "Imagine Dragons"
1203
+
1204
+
1205
  def test_single_video_status_deleted_after_music():
1206
  # Статус живёт и во время скачивания музыки тоже — сносится только после неё, а не до.
1207
  import lumen_tiktok_flow