88 lines
3.0 KiB
Python
88 lines
3.0 KiB
Python
import os
|
|
import psycopg2
|
|
import binascii
|
|
|
|
# Connection settings from docker-compose.yml
|
|
# DATABASE_URL=postgresql://postgres:password@db:5432/fitbit_garmin_sync
|
|
# We are running this INSIDE the container, so 'db' host resolves.
|
|
# OR we are running on host, so 'localhost' and port 5433 using the exposed port.
|
|
|
|
# We will try to detect if we are in the container or not, or just try both.
|
|
# Actually, I will plan to run this via `docker compose exec app python inspect_activity.py`
|
|
# so I should use the internal container settings.
|
|
# Internal: host='db', port=5432
|
|
|
|
DB_HOST = "db"
|
|
DB_NAME = "fitbit_garmin_sync"
|
|
DB_USER = "postgres"
|
|
DB_PASSWORD = "password"
|
|
ACTIVITY_ID = "21342551924"
|
|
|
|
try:
|
|
conn = psycopg2.connect(
|
|
host=DB_HOST,
|
|
database=DB_NAME,
|
|
user=DB_USER,
|
|
password=DB_PASSWORD
|
|
)
|
|
print("Connected to database.")
|
|
cur = conn.cursor()
|
|
|
|
query = "SELECT file_type, file_content FROM activities WHERE garmin_activity_id = %s"
|
|
cur.execute(query, (ACTIVITY_ID,))
|
|
row = cur.fetchone()
|
|
|
|
if row:
|
|
file_type = row[0]
|
|
content = row[1]
|
|
print(f"Stored file_type: {file_type}")
|
|
|
|
if content is None:
|
|
print("Activity found, but file_content is NULL.")
|
|
else:
|
|
if isinstance(content, memoryview):
|
|
content = bytes(content)
|
|
|
|
print(f"Content Type: {type(content)}")
|
|
print(f"Content Length: {len(content)} bytes")
|
|
|
|
# Print first 50 bytes in hex
|
|
print(f"First 50 bytes (hex): {binascii.hexlify(content[:50])}")
|
|
print(f"First 50 bytes (repr): {repr(content[:50])}")
|
|
|
|
# Check for common signatures
|
|
if content.startswith(b'PK'):
|
|
print("Signature matches ZIP file.")
|
|
elif content.startswith(b'\x0e\x10') or b'.FIT' in content[:20]:
|
|
print("Signature might be FIT file.")
|
|
elif content.startswith(b'<?xml'):
|
|
print("Signature matches XML (TCX/GPX).")
|
|
elif content.strip().startswith(b'{'):
|
|
print("Signature matches JSON.")
|
|
|
|
# Check if it looks like base64
|
|
try:
|
|
# Try decoding as utf-8 first
|
|
s = content.decode('utf-8')
|
|
# Check if characters are base64-ish
|
|
import base64
|
|
try:
|
|
decoded = base64.b64decode(s)
|
|
print("This looks like Base64 encoded data.")
|
|
print(f"Decoded first 20 bytes: {decoded[:20]}")
|
|
if decoded.startswith(b'PK'):
|
|
print("Decoded data matches ZIP signature.")
|
|
except Exception as e:
|
|
print(f"Not valid Base64: {e}")
|
|
except UnicodeDecodeError:
|
|
print("Not UTF-8 text, likely binary.")
|
|
|
|
else:
|
|
print(f"No activity found with garmin_activity_id {ACTIVITY_ID}")
|
|
|
|
cur.close()
|
|
conn.close()
|
|
|
|
except Exception as e:
|
|
print(f"Error: {e}")
|