Add Windows card reader, code-signing helpers and playlist diagnostics

- windows/win_card_reader.py: Windows-native card reader via the Raw Input API
  with a low-level keyboard-hook fallback.
- windows/sign_exe.ps1: sign the built executable with a .pfx certificate.
- windows/create_self_signed_cert.ps1: generate a self-signed cert for local
  testing (not trusted by Smart App Control).
- windows/verify_sendinput_fix.py: verification helper for the SendInput
  foreground-unlock fix in run_win.py.
- documentation/CODE_SIGNING_SMART_APP_CONTROL.md: signing guidance.
- working_files/execute_playlist_retrieve.py,
  working_files/raw_server_playlist.json: playlist retrieval diagnostics.

Note: windows/archive_list.txt and windows/build_last.txt are build output and
were committed by request rather than by convention.
This commit is contained in:
ske087
2026-09-10 16:44:12 +03:00
parent a0704efa3c
commit 5d9aa02c07
7 changed files with 1371 additions and 0 deletions
+107
View File
@@ -0,0 +1,107 @@
#!/usr/bin/env python3
"""
Execute the exact server playlist retrieval flow the player performs:
1. Load config/app_config.json (player code: screen_name + quickconnect_key)
2. Authenticate with the server (POST /api/auth/player)
3. Fetch playlist using the player_id + auth_code (GET /api/playlists/{player_id})
4. Print the RAW JSON exactly as received (before any local processing)
"""
import os
import sys
import json
import traceback
# Resolve the real src directory (script lives in working_files/, source is in src/)
HERE = os.path.dirname(os.path.abspath(__file__))
SRC_DIR = os.path.join(os.path.dirname(HERE), 'src')
sys.path.insert(0, SRC_DIR)
from get_playlists_v2 import get_auth_instance # noqa: E402
from player_auth import PlayerAuth # noqa: E402
CONFIG_PATH = os.path.join(os.path.dirname(HERE), 'config', 'app_config.json')
def main():
print("=" * 80)
print("EXECUTE SERVER PLAYLIST RETRIEVAL (player flow)")
print("=" * 80)
# 1. Load the player config
with open(CONFIG_PATH, 'r') as f:
config = json.load(f)
print(f"\n[1] Player config loaded from: {CONFIG_PATH}")
print(f" server_ip : {config.get('server_ip')}")
print(f" port : {config.get('port')}")
print(f" screen_name : {config.get('screen_name')} <- player code")
print(f" quickconnect_key: {config.get('quickconnect_key')} <- player quick-connect code")
print(f" use_https : {config.get('use_https')}")
print(f" verify_ssl : {config.get('verify_ssl')}")
# 2. Build server URL the same way ensure_authenticated() does
import re
server_ip = config.get("server_ip", "")
port = config.get("port", "")
use_https = config.get("use_https", True)
ip_pattern = r'^\d+\.\d+\.\d+\.\d+$'
if re.match(ip_pattern, server_ip):
if use_https:
server_url = f'https://{server_ip}:{port}' if port else f'https://{server_ip}'
else:
server_url = f'http://{server_ip}:{port}' if port else f'http://{server_ip}'
else:
server_url = f'https://{server_ip}' if use_https else f'http://{server_ip}'
print(f"\n[2] Server URL used: {server_url}")
# 3. Authenticate with the player code
auth = get_auth_instance(
config_file=os.path.join(SRC_DIR, 'player_auth.json'),
use_https=config.get('use_https', True),
verify_ssl=config.get('verify_ssl', True)
)
print(f"\n[3] Authenticating player '{config.get('screen_name')}' with quickconnect code...")
success, error = auth.authenticate(
server_url=server_url,
hostname=config.get('screen_name', ''),
quickconnect_code=config.get('quickconnect_key', '')
)
if not success:
print(f" AUTH FAILED: {error}")
print(" Cannot retrieve playlist without a valid player code/auth.")
return
print(f" Authenticated as: {auth.get_player_name()} (player_id={auth.get_player_id()}, "
f"playlist_id={auth.auth_data.get('playlist_id')})")
# 4. Fetch the playlist (GET /api/playlists/{player_id})
print(f"\n[4] Fetching playlist from: {server_url}/api/playlists/{auth.get_player_id()}")
playlist_data = auth.get_playlist()
if playlist_data is None:
print(" PLAYLIST FETCH FAILED")
return
# 5. Print the RAW JSON exactly as received from the server
print(f"\n[5] RAW JSON received from server (status 200):\n")
print(json.dumps(playlist_data, indent=2, ensure_ascii=False))
# 6. Save the raw response for inspection
out_path = os.path.join(HERE, 'raw_server_playlist.json')
with open(out_path, 'w', encoding='utf-8') as f:
json.dump(playlist_data, f, indent=2, ensure_ascii=False)
print(f"\n[6] Raw server response saved to: {out_path}")
# 7. Summary
print("\n" + "=" * 80)
print(f"SUMMARY: playlist_version={playlist_data.get('playlist_version')}, "
f"count={playlist_data.get('count')}, items={len(playlist_data.get('playlist', []))}")
print("=" * 80)
if __name__ == '__main__':
try:
main()
except Exception:
traceback.print_exc()
sys.exit(1)