Ethscriptions commited on
Commit
08c72b2
·
verified ·
1 Parent(s): dcaee93

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +82 -43
app.py CHANGED
@@ -6,6 +6,7 @@ import time
6
  from collections import defaultdict
7
  import json
8
  import os
 
9
  from datetime import datetime, timedelta, time as dt_time
10
  import io
11
  import warnings
@@ -22,6 +23,7 @@ from itertools import combinations
22
  from dotenv import load_dotenv
23
  load_dotenv() # 加载本地 .env 文件
24
 
 
25
  # --- 全局配置和常量 ---
26
  TOKEN_FILE = 'token_data.json'
27
  # --- 环境变量获取 (替代硬编码) ---
@@ -1326,79 +1328,118 @@ def generate_schedule_check_logs(schedule_list, date_str):
1326
  def check_tms_file_availability(schedule_list, tms_data, date_str):
1327
  """
1328
  对比排片表和TMS数据,检查影厅是否缺失对应的影片文件
 
1329
  """
1330
  if not schedule_list:
1331
- return ["未获取到排片数据,无法检查。"]
1332
 
1333
  if not tms_data:
1334
- return ["未获取到 TMS 数据,无法检查。"]
1335
-
1336
- # 1. 预处理 TMS 数据:建立 { '影厅号(纯数字)': [影片名列表] } 的映射
1337
- # tms_data 结构: {'1号厅': [{'content_name':..., 'details': {'assert_name':...}}], ...}
1338
- tms_map = defaultdict(list)
1339
-
1340
- import re
1341
- def get_hall_num(name):
1342
- # 提取影厅名称中的数字,例如 "1号厅" -> "1", "IMAX厅" -> "IMAX" (如果没数字)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1343
  nums = re.findall(r'\d+', str(name))
1344
  return nums[0] if nums else str(name)
1345
 
 
 
 
 
 
 
1346
  for hall_name, movies in tms_data.items():
1347
- hall_key = get_hall_num(hall_name)
1348
  for movie in movies:
1349
- # 收集 assert_name (显示名) 和 content_name (文件名)
1350
- # 转为大写方便不区分大小写匹配
1351
  if movie.get('details', {}).get('assert_name'):
1352
- tms_map[hall_key].append(str(movie['details']['assert_name']).upper())
 
 
 
 
 
 
1353
  if movie.get('content_name'):
1354
- tms_map[hall_key].append(str(movie['content_name']).upper())
1355
 
1356
  # 2. 遍历排片数据进行检查
1357
- missing_files_log = []
1358
- # 用于缓存已经检查过的 (影厅, 影片) 组合,避免重复报错
1359
  checked_combinations = set()
1360
 
1361
  for item in schedule_list:
1362
- # 排片数据字段可能不同,做一下兼容
1363
  hall_raw = item.get('hallName') or item.get('Hall')
1364
  movie_raw = item.get('movieName') or item.get('Movie')
1365
 
1366
  if not hall_raw or not movie_raw:
1367
  continue
1368
 
1369
- hall_num = get_hall_num(hall_raw)
 
 
1370
 
1371
- # 清洗影片名,去掉版本后缀,获取核心片名 (使用现有的 clean_movie_title 逻辑)
1372
- # 这里为了匹配更宽泛,我们直接取 cleaning 后的基础名,并不依赖 canonical_names (因为可能还在预售没通过API获取到)
1373
- movie_clean = clean_movie_title(movie_raw).upper()
1374
 
1375
- # 组合键
1376
- combo_key = (hall_num, movie_clean)
1377
  if combo_key in checked_combinations:
1378
  continue
1379
  checked_combinations.add(combo_key)
1380
 
1381
- # 开始检查
1382
  if hall_num not in tms_map:
1383
- # 如果 TMS 里甚至没读到这个厅的数据(可能是坏了或者网络问题),视情况报错,这里先提示
1384
- # missing_files_log.append(f"⚠️ 影厅异常:TMS 中未找到【{hall_raw}】的数据,无法检查该厅《{movie_raw}》。")
1385
  continue
1386
 
1387
- # 核心匹配逻辑:只要 TMS 列表中有一个文件名包含了排片名的核心词,就认为有片
1388
- # 例如:排片 "抓娃娃",TMS 有 "Zhuawawa_..." 或 "抓娃娃(数字2D)..." -> 匹配成功
 
 
1389
  has_file = False
1390
  tms_files = tms_map[hall_num]
1391
 
 
 
1392
  for tms_file in tms_files:
1393
- if movie_clean in tms_file:
1394
  has_file = True
1395
  break
1396
 
1397
  if not has_file:
1398
- missing_files_log.append(
1399
- f"❌ 缺片警告:【{hall_raw}】排映《{movie_raw}》,但服务器未检测到包含“{movie_clean}”的文件。")
 
 
 
 
 
 
 
 
 
1400
 
1401
- return missing_files_log
1402
 
1403
  # --- 5. UI 渲染与交互逻辑 ---
1404
 
@@ -1760,8 +1801,7 @@ def main():
1760
  check_date_str = check_date.strftime('%Y-%m-%d')
1761
 
1762
  with st.spinner(f"正在获取 {check_date_str} 的排片数据并连接 TMS 服务器..."):
1763
- # 1. 获取次日排片 (如果之前没获取过)
1764
- # 注意:为了确保数据最新,这里重新快速获取一次原始数据
1765
  schedule_data, _ = get_api_data_with_token_management(check_date_str)
1766
 
1767
  if not schedule_data:
@@ -1769,24 +1809,23 @@ def main():
1769
  else:
1770
  try:
1771
  # 2. 获取 TMS 数据
1772
- # 提取排片中出现的所有影片名作为优先查询关键词,加快 TMS 搜索速度 (虽然后台是全量拉取)
1773
  df_sched = pd.DataFrame(schedule_data)
1774
  priority_titles = df_sched[
1775
  'movieName'].unique().tolist() if 'movieName' in df_sched.columns else []
1776
 
1777
  tms_hall_data, _ = fetch_and_process_server_movies(priority_titles)
1778
 
1779
- # 3. 执行比对
1780
- missing_logs = check_tms_file_availability(schedule_data, tms_hall_data,
1781
- check_date_str)
1782
 
1783
- if not missing_logs:
1784
  st.success(
1785
  f"✅ 核对完成:{check_date_str} 所有排映影片在对应影厅服务器中均存在关联文件。")
1786
  else:
1787
- st.error(f"⚠️ 发现 {len(missing_logs)} 个潜在缺片风险!")
1788
- for log in missing_logs:
1789
- st.code(log)
1790
 
1791
  except Exception as e:
1792
  st.error(f"核对过程中发生错误: {e}")
 
6
  from collections import defaultdict
7
  import json
8
  import os
9
+ import re
10
  from datetime import datetime, timedelta, time as dt_time
11
  import io
12
  import warnings
 
23
  from dotenv import load_dotenv
24
  load_dotenv() # 加载本地 .env 文件
25
 
26
+
27
  # --- 全局配置和常量 ---
28
  TOKEN_FILE = 'token_data.json'
29
  # --- 环境变量获取 (替代硬编码) ---
 
1328
  def check_tms_file_availability(schedule_list, tms_data, date_str):
1329
  """
1330
  对比排片表和TMS数据,检查影厅是否缺失对应的影片文件
1331
+ 优化:仅匹配核心片名(去除版本后缀),优化影厅名显示,合并日志输出
1332
  """
1333
  if not schedule_list:
1334
+ return "未获取到排片数据,无法检查。"
1335
 
1336
  if not tms_data:
1337
+ return "未获取到 TMS 数据,无法检查。"
1338
+
1339
+ # --- 内部辅助函数 ---
1340
+ def get_core_movie_name(raw_name):
1341
+ """
1342
+ 获取核心片名用于匹配:
1343
+ 1. 先执行标准的 clean_movie_title (统一命名)
1344
+ 2. 再去除所有括号及括号内的内容 (去除版本/制式信息)
1345
+ 例如:'疯狂动物城2(数字3D)' -> '疯狂动物城2'
1346
+ """
1347
+ # 1. 基础清洗 (利用现有的逻辑处理中英文/特殊后缀)
1348
+ # 注意:这里我们不传入 canonical_names,只做规则清洗
1349
+ name = clean_movie_title(raw_name)
1350
+ # 2. 正则去除中文全角括号及内容 (...)
1351
+ name = re.sub(r'(.*?)', '', name)
1352
+ # 3. 正则去除英文半角括号及内容 (...)
1353
+ name = re.sub(r'\(.*?\)', '', name)
1354
+ return name.strip()
1355
+
1356
+ def clean_hall_display_name(raw_name):
1357
+ """去除影厅名两端多余的 【】 [] 符号"""
1358
+ return str(raw_name).strip('【】[] ')
1359
+
1360
+ def get_hall_key_num(name):
1361
+ """提取影厅数字ID用于数据匹配 (如 '1号厅' -> '1')"""
1362
  nums = re.findall(r'\d+', str(name))
1363
  return nums[0] if nums else str(name)
1364
 
1365
+ # ------------------
1366
+
1367
+ # 1. 预处理 TMS 数据
1368
+ # 结构: {'1': ['Zootopia2', '疯狂动物城2', ...], ...}
1369
+ tms_map = defaultdict(set) # 使用 set 提高查找效率
1370
+
1371
  for hall_name, movies in tms_data.items():
1372
+ hall_key = get_hall_key_num(hall_name)
1373
  for movie in movies:
1374
+ # 收集 Assert Name (显示名)
 
1375
  if movie.get('details', {}).get('assert_name'):
1376
+ # 同样对 TMS 里的名字取核心名,提高匹配率
1377
+ core_tms_name = get_core_movie_name(str(movie['details']['assert_name']))
1378
+ tms_map[hall_key].add(core_tms_name.upper())
1379
+ # 保留原始 Assert Name 用于兜底匹配
1380
+ tms_map[hall_key].add(str(movie['details']['assert_name']).upper())
1381
+
1382
+ # 收集 Content Name (文件名/UUID)
1383
  if movie.get('content_name'):
1384
+ tms_map[hall_key].add(str(movie['content_name']).upper())
1385
 
1386
  # 2. 遍历排片数据进行检查
1387
+ missing_logs = []
 
1388
  checked_combinations = set()
1389
 
1390
  for item in schedule_list:
 
1391
  hall_raw = item.get('hallName') or item.get('Hall')
1392
  movie_raw = item.get('movieName') or item.get('Movie')
1393
 
1394
  if not hall_raw or not movie_raw:
1395
  continue
1396
 
1397
+ # 准备数据
1398
+ hall_num = get_hall_key_num(hall_raw)
1399
+ hall_display = clean_hall_display_name(hall_raw) # 清洗后的影厅名
1400
 
1401
+ # 获取排片的核心片名 (去掉版本后缀)
1402
+ target_movie_core = get_core_movie_name(movie_raw).upper()
 
1403
 
1404
+ # 组合键去重 (同一厅同一部片只报一次)
1405
+ combo_key = (hall_num, target_movie_core)
1406
  if combo_key in checked_combinations:
1407
  continue
1408
  checked_combinations.add(combo_key)
1409
 
1410
+ # 检查逻辑
1411
  if hall_num not in tms_map:
1412
+ # 找不到影厅数据暂不报错,可能是未映射或设备离线,避免刷屏
 
1413
  continue
1414
 
1415
+ # 核心匹配:检查 TMS 集合中是否包含核心片名
1416
+ # 方式A:精确匹配核心名 (推荐,最准)
1417
+ # 方式B:模糊包含 (target in tms_file)
1418
+
1419
  has_file = False
1420
  tms_files = tms_map[hall_num]
1421
 
1422
+ # 策略:只要 TMS 中有一个文件名 包含 我们的核心排片名,就视为有片
1423
+ # 例如:排片 core='疯狂动物城2',TMS='疯狂动物城2_IMAX' -> 匹配成功
1424
  for tms_file in tms_files:
1425
+ if target_movie_core in tms_file:
1426
  has_file = True
1427
  break
1428
 
1429
  if not has_file:
1430
+ # 记录日志,使用清洗后的影厅名和排片原名
1431
+ missing_logs.append(f"{hall_display}】排映《{movie_raw}》,但服务器未检测到包含“{target_movie_core}”的文件。")
1432
+
1433
+ # 3. 格式化输出
1434
+ if not missing_logs:
1435
+ return None # 返回 None 表示一切正常
1436
+
1437
+ # 生成带编号的字符串
1438
+ formatted_output = []
1439
+ for idx, log in enumerate(missing_logs, 1):
1440
+ formatted_output.append(f"{idx}. ❌ 缺片警告:{log}")
1441
 
1442
+ return "\n".join(formatted_output)
1443
 
1444
  # --- 5. UI 渲染与交互逻辑 ---
1445
 
 
1801
  check_date_str = check_date.strftime('%Y-%m-%d')
1802
 
1803
  with st.spinner(f"正在获取 {check_date_str} 的排片数据并连接 TMS 服务器..."):
1804
+ # 1. 获取次日排片
 
1805
  schedule_data, _ = get_api_data_with_token_management(check_date_str)
1806
 
1807
  if not schedule_data:
 
1809
  else:
1810
  try:
1811
  # 2. 获取 TMS 数据
 
1812
  df_sched = pd.DataFrame(schedule_data)
1813
  priority_titles = df_sched[
1814
  'movieName'].unique().tolist() if 'movieName' in df_sched.columns else []
1815
 
1816
  tms_hall_data, _ = fetch_and_process_server_movies(priority_titles)
1817
 
1818
+ # 3. 执行比对 (使用新函数)
1819
+ logs_text = check_tms_file_availability(schedule_data, tms_hall_data,
1820
+ check_date_str)
1821
 
1822
+ if logs_text is None:
1823
  st.success(
1824
  f"✅ 核对完成:{check_date_str} 所有排映影片在对应影厅服务器中均存在关联文件。")
1825
  else:
1826
+ st.warning("⚠️ 发现潜在缺片风险!请检查以下影厅服务器:")
1827
+ # 这里使用 st.code 展示多行带编号的文本
1828
+ st.code(logs_text, language="text")
1829
 
1830
  except Exception as e:
1831
  st.error(f"核对过程中发生错误: {e}")