From df0b6f8678d62f26c1c878e3fffabbcb8e3ad136 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=AE=D1=80=D0=B8=D0=B9=20=D0=A7=D0=B5=D1=80=D0=BD=D0=B5?= =?UTF-8?q?=D0=BD=D0=BA=D0=BE?= Date: Tue, 11 Nov 2025 15:14:29 +0300 Subject: [PATCH] =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=B0=20=D0=B1=D0=B8=D0=B1=D0=BB=D0=B8=D0=BE=D1=82=D0=B5?= =?UTF-8?q?=D0=BA=D0=B0=20nasio?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 3 +- __pycache__/get_data.cpython-312.pyc | Bin 35583 -> 34617 bytes __pycache__/smb_excel.cpython-312.pyc | Bin 4922 -> 0 bytes function.py | 41 ------- get_data.py | 47 ++------ requirements.txt | 4 +- smb_excel.py | 154 -------------------------- 7 files changed, 16 insertions(+), 233 deletions(-) delete mode 100644 __pycache__/smb_excel.cpython-312.pyc delete mode 100644 function.py delete mode 100644 smb_excel.py diff --git a/.gitignore b/.gitignore index c48f48e..7d196de 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .env /.venv /logs/* -/__pycache__ \ No newline at end of file +/__pycache__/* +*.pyc \ No newline at end of file diff --git a/__pycache__/get_data.cpython-312.pyc b/__pycache__/get_data.cpython-312.pyc index 85bfb8a5dc6aff0009631ea0ff6ac7f7b987ee3b..fd6f266818f02e296a7403f5bdfa469f1ef5d093 100644 GIT binary patch delta 6241 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 pd.DataFrame: - """ - Скачивает Synology Office .osheet через Drive API (делает экспорт в xlsx под капотом) - и возвращает pandas.DataFrame для указанного листа. - file_path: путь вида '/GFX/…/MATCH.osheet' (шара должна быть Team Folder в Drive). - """ - - drv = SynologyDrive(SYNO_USERNAME, SYNO_PASSWORD, SYNO_HOST, SYNO_PORT, https=True, dsm_version="7") - try: - # вернёт BytesIO c xlsx - bio = drv.download_synology_office_file(file_path) - df = pd.read_excel(bio, sheet_name=sheet) - return df - except SynologyException as e: - # Часто: {"code":1000,"message":"get file information failed"} — Drive не видит путь (нет Team Folder/прав) - raise RuntimeError( - "Не удалось экспортировать .osheet через Synology Drive. " - "Проверь, что шара включена в Drive Admin Console → Team Folder, " - "и у пользователя есть права. Исходная ошибка: " + str(e) - ) - finally: - try: - drv.logout() - except Exception: - pass - -load_osheet(file_path="/GFX/Hockey/KHL/Soft/MATCH.osheet", sheet="TEAMS") \ No newline at end of file diff --git a/get_data.py b/get_data.py index fa21e2b..cba2592 100644 --- a/get_data.py +++ b/get_data.py @@ -10,8 +10,8 @@ import uvicorn from threading import Thread, Event, Lock import time from contextlib import asynccontextmanager -#from smb_excel import read_excel_from_smb, fetch_smb_file import numpy as np +import nasio # --- Глобальные переменные --- @@ -36,13 +36,10 @@ api_user = os.getenv("API_USER") api_pass = os.getenv("API_PASS") league = os.getenv("LEAGUE") POLL_SEC = int(os.getenv("GAME_POLL_SECONDS")) -SERVER_NAME = os.getenv("SERVER_NAME") -SERVER_IP = os.getenv("SERVER_IP") -SHARE = os.getenv("SHARE") -PATH_IN_SHARE = os.getenv("PATH_IN_SHARE") -USER = os.getenv("USER") -PASSWORD = os.getenv("PASSWORD") -DOMAIN = os.getenv("DOMAIN") +SERVER_NAME = os.getenv("SYNO_URL") +USER = os.getenv("SYNO_USERNAME") +PASSWORD = os.getenv("SYNO_PASSWORD") +PATH = "/team-folders/GFX/Hockey/KHL/Soft/MATCH.xlsm" @@ -652,25 +649,6 @@ def _build_all_stats(payload: dict) -> dict: }) return result -def xl(): - df = read_excel_from_smb( - server_name=SERVER_NAME, - server_ip=SERVER_IP, - share_name=SHARE, - file_path_in_share=PATH_IN_SHARE, - username=USER, - password=PASSWORD, - domain=DOMAIN, - client_machine_name="KHL_SOFT", - sheet_name="TEAMS", # или None, или список листов - ) - df = df.replace([float("inf"), float("-inf")], pd.NA) - columns_to_keep = [ - "Team", "Logo", "Short", "HexPodl", # ← укажи свои - ] - df = df.loc[:, [c for c in columns_to_keep if c in df.columns]] - json_text = df.to_json(orient="records", force_ascii=False) # NaN/NA -> null - return Response(content=json_text, media_type="application/json; charset=utf-8") @app.get("/teams/stats") async def teams_stats( @@ -756,16 +734,13 @@ async def info(): away_name = str(row.get("visitorName_en", "")).strip() # 3) Подтягиваем справочник команд из Excel (лист TEAMS) - teams_df = read_excel_from_smb( - server_name=SERVER_NAME, - server_ip=SERVER_IP, - share_name=SHARE, - file_path_in_share=PATH_IN_SHARE, - username=USER, + teams_df = nasio.load_formatted( + user=USER, password=PASSWORD, - domain=DOMAIN, - client_machine_name="KHL_SOFT", - sheet_name="TEAMS", + nas_ip=SERVER_NAME, + nas_port="443", + path=PATH, + sheet="TEAMS" ) # Оставляем только полезные поля (подгони под свой файл) diff --git a/requirements.txt b/requirements.txt index f91e978..8d1f591 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,4 +7,6 @@ requests>=2.31.0 python-telegram-handler python-dotenv>=1.1.0 lxml -python-dotenv \ No newline at end of file +python-dotenv +--extra-index-url https://git.tvstart.ru/api/packages/lexx/pypi/simple +nasio \ No newline at end of file diff --git a/smb_excel.py b/smb_excel.py deleted file mode 100644 index acb7b85..0000000 --- a/smb_excel.py +++ /dev/null @@ -1,154 +0,0 @@ -# smb_excel.py (обновлённый фрагмент) -from io import BytesIO -from typing import Optional, Union, Any, Dict -#from smb.SMBConnection import SMBConnection -import pandas as pd -import re - -class SMBDownloadError(Exception): - pass - -def _normalize_path(p: str) -> str: - """Убирает случайные r"..."/"...", лишние кавычки и ставит прямые слэши.""" - if p is None: - return p - # уберём обрамляющие кавычки/префикс r"..." - m = re.fullmatch(r"""r?["'](.*)["']""", p.strip()) - if m: - p = m.group(1) - # заменим \ на / - p = p.replace("\\", "/").lstrip("/") # путь внутри шары не должен начинаться с / - return p - -def _try_connect( - remote_name: str, - server_ip: str, - username: str, - password: str, - *, - client_machine_name: str, - domain: str, - port: int -) -> Optional[SMBConnection]: - conn = SMBConnection( - username, - password, - client_machine_name, - remote_name, # ВАЖНО: remote_name — имя сервера (или IP как fallback) - domain=domain, - use_ntlm_v2=True, - is_direct_tcp=True - ) - try: - if conn.connect(server_ip, port): - return conn - except Exception: - pass - return None - -def _connect_smb( - server_name: str, - server_ip: str, - username: str, - password: str, - *, - client_machine_name: str = "client", - domain: str = "", - port: int = 445, -) -> SMBConnection: - """ - Пробуем два варианта remote_name: (1) реальное имя сервера, (2) IP. - """ - for remote_name in (server_name, server_ip): - if not remote_name: - continue - conn = _try_connect( - remote_name=remote_name, - server_ip=server_ip, - username=username, - password=password, - client_machine_name=client_machine_name, - domain=domain, - port=port, - ) - if conn: - return conn - raise SMBDownloadError( - f"Не удалось подключиться к SMB {server_ip}:{port}. " - f"Проверь server_name (реальное имя хоста), домен/логин и доступность порта 445." - ) - -def fetch_smb_file( - *, - server_name: str, - server_ip: str, - share_name: str, - file_path_in_share: str, - username: str, - password: str, - client_machine_name: str = "client", - domain: str = "", - port: int = 445, -) -> BytesIO: - """ - Возвращает содержимое файла из SMB как BytesIO. - """ - file_path_in_share = _normalize_path(file_path_in_share) - conn: Optional[SMBConnection] = None - try: - conn = _connect_smb( - server_name=server_name, - server_ip=server_ip, - username=username, - password=password, - client_machine_name=client_machine_name, - domain=domain, - port=port, - ) - # Быстрая проверка существования каталога/файла - parent = "/".join(file_path_in_share.split("/")[:-1]) or "" - # listPath кидает исключение, если каталога/шары нет — получим понятную ошибку - if parent: - conn.listPath(share_name, parent) - - buf = BytesIO() - conn.retrieveFile(share_name, file_path_in_share, buf) - buf.seek(0) - return buf - except Exception as e: - raise SMBDownloadError( - f"Ошибка скачивания {share_name}/{file_path_in_share}: {e}" - ) from e - finally: - if conn: - try: - conn.close() - except Exception: - pass - -def read_excel_from_smb( - *, - server_name: str, - server_ip: str, - share_name: str, - file_path_in_share: str, - username: str, - password: str, - client_machine_name: str = "client", - domain: str = "", - port: int = 445, - sheet_name: Optional[Union[str, int, list]] = None, - **read_excel_kwargs: Dict[str, Any], -) -> pd.DataFrame: - file_obj = fetch_smb_file( - server_name=server_name, - server_ip=server_ip, - share_name=share_name, - file_path_in_share=file_path_in_share, - username=username, - password=password, - client_machine_name=client_machine_name, - domain=domain, - port=port, - ) - return pd.read_excel(file_obj, sheet_name=sheet_name, **read_excel_kwargs)