181
scripts/upgrade_fansly_to_4k.py
Normal file
181
scripts/upgrade_fansly_to_4k.py
Normal file
@@ -0,0 +1,181 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Check Fansly attachments for 4K variants and upgrade if available.
|
||||
|
||||
This script:
|
||||
1. Finds all non-4K video attachments from Fansly Direct
|
||||
2. Re-fetches media info from the Fansly API
|
||||
3. Checks if a higher resolution variant is available
|
||||
4. Updates the attachment URL and resets for re-download if upgrade found
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import sys
|
||||
import os
|
||||
|
||||
# Add project to path
|
||||
sys.path.insert(0, '/opt/media-downloader')
|
||||
|
||||
# Bootstrap PostgreSQL adapter before any database imports
|
||||
from modules.db_bootstrap import bootstrap_database
|
||||
bootstrap_database()
|
||||
|
||||
from modules.paid_content.fansly_direct_client import FanslyDirectClient
|
||||
from modules.paid_content.db_adapter import PaidContentDB
|
||||
|
||||
|
||||
async def check_and_upgrade_attachments():
|
||||
"""Check all non-4K Fansly attachments for upgrades."""
|
||||
|
||||
db = PaidContentDB('/opt/media-downloader/database/media_downloader.db')
|
||||
|
||||
# Get Fansly auth token
|
||||
service = db.get_service('fansly_direct')
|
||||
if not service or not service.get('session_cookie'):
|
||||
print("ERROR: No Fansly auth token configured")
|
||||
return
|
||||
|
||||
auth_token = service['session_cookie']
|
||||
client = FanslyDirectClient(auth_token)
|
||||
|
||||
# Find non-4K video attachments from Fansly Direct
|
||||
# 4K is 3840x2160 or 2160x3840 (portrait)
|
||||
query = """
|
||||
SELECT a.id, a.name, a.width, a.height, a.status, p.post_id, p.id as db_post_id
|
||||
FROM paid_content_attachments a
|
||||
JOIN paid_content_posts p ON a.post_id = p.id
|
||||
JOIN paid_content_creators c ON p.creator_id = c.id
|
||||
WHERE c.service_id = 'fansly_direct'
|
||||
AND a.file_type = 'video'
|
||||
AND a.width IS NOT NULL
|
||||
AND a.height IS NOT NULL
|
||||
AND NOT (
|
||||
(a.width >= 3840 AND a.height >= 2160) OR
|
||||
(a.width >= 2160 AND a.height >= 3840)
|
||||
)
|
||||
AND p.post_id NOT LIKE 'manual_%'
|
||||
AND p.post_id NOT LIKE 'import_%'
|
||||
AND p.post_id NOT LIKE '20%-%'
|
||||
ORDER BY a.id
|
||||
"""
|
||||
|
||||
cursor = db.conn.execute(query)
|
||||
attachments = cursor.fetchall()
|
||||
|
||||
print(f"Found {len(attachments)} non-4K video attachments to check")
|
||||
print("-" * 80)
|
||||
|
||||
upgrades_found = 0
|
||||
errors = 0
|
||||
already_best = 0
|
||||
|
||||
for att in attachments:
|
||||
att_id, name, width, height, status, post_id, db_post_id = att
|
||||
current_res = f"{width}x{height}"
|
||||
|
||||
print(f"\nChecking: {name} (ID: {att_id}, current: {current_res})")
|
||||
|
||||
try:
|
||||
# Extract media ID from filename (e.g., "12345.mp4" -> "12345")
|
||||
media_id = name.replace('.mp4', '').replace('.mov', '')
|
||||
|
||||
# Fetch media info from Fansly API
|
||||
# We need to get the account media for this post
|
||||
async with client:
|
||||
# Get the post to find media info
|
||||
posts, _, media_dict, account_media_dict, bundle_dict = await client._fetch_timeline_page(
|
||||
account_id=None, # We'll search by post ID
|
||||
before=str(int(post_id) + 1), # Get this post
|
||||
account={}
|
||||
)
|
||||
|
||||
# Find media in the dictionaries
|
||||
found_4k = False
|
||||
best_width = width
|
||||
best_height = height
|
||||
best_url = None
|
||||
|
||||
# Check account_media_dict for this media
|
||||
for am_id, am_data in account_media_dict.items():
|
||||
media = am_data.get('media', {})
|
||||
if str(media.get('id')) == media_id:
|
||||
# Found the media, check variants
|
||||
variants = media.get('variants', [])
|
||||
print(f" Found media with {len(variants)} variants")
|
||||
|
||||
for v in variants:
|
||||
v_w = v.get('width', 0) or 0
|
||||
v_h = v.get('height', 0) or 0
|
||||
v_locs = v.get('locations', [])
|
||||
|
||||
# Check if this is a higher resolution
|
||||
if v_w * v_h > best_width * best_height:
|
||||
for loc in v_locs:
|
||||
loc_url = loc.get('location', '')
|
||||
# Prefer streaming formats for 4K
|
||||
if '.m3u8' in loc_url or '.mp4' in loc_url or '.mov' in loc_url:
|
||||
best_width = v_w
|
||||
best_height = v_h
|
||||
|
||||
# Construct signed URL if metadata present
|
||||
metadata = loc.get('metadata', {})
|
||||
if metadata:
|
||||
params = []
|
||||
for key in ['Key-Pair-Id', 'Signature', 'Policy']:
|
||||
if key in metadata:
|
||||
params.append(f"{key}={metadata[key]}")
|
||||
if params:
|
||||
best_url = loc_url + '?' + '&'.join(params)
|
||||
else:
|
||||
best_url = loc_url
|
||||
else:
|
||||
best_url = loc_url
|
||||
|
||||
if v_w >= 3840 or v_h >= 3840:
|
||||
found_4k = True
|
||||
break
|
||||
break
|
||||
|
||||
if found_4k and best_url:
|
||||
print(f" ✓ UPGRADE FOUND: {best_width}x{best_height}")
|
||||
upgrades_found += 1
|
||||
|
||||
# Update the attachment
|
||||
db.conn.execute("""
|
||||
UPDATE paid_content_attachments
|
||||
SET download_url = ?,
|
||||
width = ?,
|
||||
height = ?,
|
||||
status = 'pending',
|
||||
download_attempts = 0,
|
||||
error_message = NULL,
|
||||
local_path = NULL,
|
||||
local_filename = NULL
|
||||
WHERE id = ?
|
||||
""", (best_url, best_width, best_height, att_id))
|
||||
db.conn.commit()
|
||||
print(f" → Updated and queued for re-download")
|
||||
|
||||
elif best_width > width or best_height > height:
|
||||
print(f" ~ Better quality available: {best_width}x{best_height} (not 4K)")
|
||||
else:
|
||||
print(f" - Already at best available quality")
|
||||
already_best += 1
|
||||
|
||||
except Exception as e:
|
||||
print(f" ✗ Error: {e}")
|
||||
errors += 1
|
||||
|
||||
# Rate limiting
|
||||
await asyncio.sleep(0.5)
|
||||
|
||||
print("\n" + "=" * 80)
|
||||
print(f"Summary:")
|
||||
print(f" Upgrades found and queued: {upgrades_found}")
|
||||
print(f" Already at best quality: {already_best}")
|
||||
print(f" Errors: {errors}")
|
||||
print(f" Total checked: {len(attachments)}")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
asyncio.run(check_and_upgrade_attachments())
|
||||
Reference in New Issue
Block a user