Merge csv_uploader into xb_seed_status as --upload-csv mode

This commit is contained in:
constantprojects
2026-02-17 15:30:51 -07:00
parent e7dd24de73
commit cb63e66d50
3 changed files with 120 additions and 228 deletions

View File

@@ -306,14 +306,18 @@ Examples:
# CSV mode - just output a file:
%(prog)s --id-folder ./torrents --bt-backup /path/to/BT_backup --csv-only
# Upload a CSV generated by someone else:
%(prog)s --upload-csv seeds.csv --nocodb-url https://noco.example.com \\
--table-id tblXXXXX --api-token xc-xxxx
"""
)
parser.add_argument('--id-folder', required=True, type=Path,
parser.add_argument('--id-folder', type=Path,
help='Path to folder containing {id}.torrent files')
parser.add_argument('--bt-backup', required=True, type=Path,
parser.add_argument('--bt-backup', type=Path,
help="Path to qBittorrent's BT_backup folder")
# NocoDB API options
parser.add_argument('--nocodb-url', type=str, default=None,
help='NocoDB base URL (e.g., http://localhost:8080)')
@@ -321,33 +325,115 @@ Examples:
help='NocoDB table ID (starts with "tbl")')
parser.add_argument('--api-token', type=str, default=None,
help='NocoDB API token (xc-token)')
# CSV fallback
# CSV fallback
parser.add_argument('--csv-only', action='store_true',
help='Skip API, just output CSV')
parser.add_argument('--output', type=Path, default=Path('seeding_update.csv'),
help='Output CSV path (default: seeding_update.csv)')
parser.add_argument('--upload-csv', type=Path, default=None,
help='Upload a CSV file to NocoDB (skip torrent scanning)')
parser.add_argument('--debug', action='store_true',
help='Print debug info for API calls')
args = parser.parse_args()
# Validate paths
if not args.id_folder.exists():
print(f"Error: ID folder does not exist: {args.id_folder}", file=sys.stderr)
sys.exit(1)
if not args.bt_backup.exists():
print(f"Error: BT_backup folder does not exist: {args.bt_backup}", file=sys.stderr)
sys.exit(1)
# Validate args based on mode
if args.upload_csv:
if not args.upload_csv.exists():
print(f"Error: CSV file not found: {args.upload_csv}", file=sys.stderr)
sys.exit(1)
if not all([args.nocodb_url, args.table_id, args.api_token]):
print("Error: --upload-csv requires --nocodb-url, --table-id, and --api-token", file=sys.stderr)
sys.exit(1)
else:
if not args.id_folder or not args.bt_backup:
print("Error: --id-folder and --bt-backup are required (unless using --upload-csv)", file=sys.stderr)
sys.exit(1)
if not args.id_folder.exists():
print(f"Error: ID folder does not exist: {args.id_folder}", file=sys.stderr)
sys.exit(1)
if not args.bt_backup.exists():
print(f"Error: BT_backup folder does not exist: {args.bt_backup}", file=sys.stderr)
sys.exit(1)
# Determine mode
use_api = not args.csv_only
# --- Upload CSV mode ---
if args.upload_csv:
print("=" * 50)
print("Seed Tracker — CSV Upload")
print("=" * 50)
# Read CSV
with open(args.upload_csv, 'r', newline='', encoding='utf-8') as f:
reader = csv.DictReader(f)
rows = list(reader)
print(f"Loaded {len(rows)} rows from {args.upload_csv}")
noco = NocoDBClient(
args.nocodb_url, args.table_id, args.api_token,
args.debug
)
print("Testing connection...")
try:
noco._request("GET", params={"limit": "1"})
print(" ✓ Connected!")
except Exception as e:
print(f" ✗ Connection failed: {e}", file=sys.stderr)
sys.exit(1)
print(f"\nUpdating records...")
stats = {'updated': 0, 'already': 0, 'not_found': 0, 'failed': 0}
for i, row in enumerate(rows, 1):
record_id = row.get('Id') or row.get('id')
username = row.get('seeding_users') or row.get('Seeding_Users')
if not record_id or not username:
continue
record = noco.get_record(record_id)
if record is None:
print(f" ? {record_id}: not found")
stats['not_found'] += 1
continue
current = parse_multiselect(record.get(noco.SEEDING_FIELD))
if username in current:
print(f" = {record_id}: already listed")
stats['already'] += 1
continue
current.add(username)
if noco.update_record(record["Id"], format_multiselect(current)):
print(f" + {record_id}: added {username}")
stats['updated'] += 1
else:
print(f" ! {record_id}: failed")
stats['failed'] += 1
if i % 3 == 0:
time.sleep(1)
print(f"\nDone!")
print(f" Updated: {stats['updated']}")
print(f" Already: {stats['already']}")
print(f" Not found: {stats['not_found']}")
print(f" Failed: {stats['failed']}")
return
# Show banner
print("=" * 50)
print("Seed Tracker")
print("=" * 50)
print(f"Mode: {'NocoDB API' if use_api else 'CSV output'}")
if use_api:
if not all([args.nocodb_url, args.table_id, args.api_token]):
print("Error: API mode requires --nocodb-url, --table-id, and --api-token", file=sys.stderr)