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:
@@ -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)
|
||||
Reference in New Issue
Block a user