76 lines
2.3 KiB
Python
76 lines
2.3 KiB
Python
#!/usr/bin/env python3
|
|
import argparse
|
|
import os
|
|
import sys
|
|
import json
|
|
from pathlib import Path
|
|
|
|
try:
|
|
import pyktok as pyk # type: ignore
|
|
except Exception as e:
|
|
print(
|
|
f"Error: pyktok not installed. Run: pip install -r requirements.txt\n{e}",
|
|
file=sys.stderr,
|
|
)
|
|
sys.exit(1)
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description="Download TikTok video using Pyktok")
|
|
parser.add_argument('--url', required=True, help='TikTok share URL')
|
|
parser.add_argument('--out', default='downloads', help='Output directory (default: downloads)')
|
|
args = parser.parse_args()
|
|
|
|
out_dir = Path(args.out).resolve()
|
|
out_dir.mkdir(parents=True, exist_ok=True)
|
|
|
|
# Change CWD to output dir so pyktok saves files here
|
|
os.chdir(out_dir.as_posix())
|
|
|
|
# Save video and a metadata CSV in the output directory
|
|
meta_csv = out_dir / 'tiktok_metadata.csv'
|
|
try:
|
|
pyk.save_tiktok(args.url, True, meta_csv.as_posix())
|
|
except Exception as e:
|
|
print(f"Error: download failed: {e}", file=sys.stderr)
|
|
sys.exit(3)
|
|
|
|
# Find the most recent mp4 in the output dir
|
|
mp4s = sorted(out_dir.glob('*.mp4'), key=lambda p: p.stat().st_mtime, reverse=True)
|
|
if not mp4s:
|
|
print('No video found', file=sys.stderr)
|
|
sys.exit(4)
|
|
|
|
# Attempt to retrieve description via JSON
|
|
description = ''
|
|
try:
|
|
data = pyk.alt_get_tiktok_json(args.url)
|
|
# recursive search for 'desc' or 'description'
|
|
def find_desc(obj):
|
|
if isinstance(obj, dict):
|
|
for k, v in obj.items():
|
|
if isinstance(k, str) and k.lower() in ('desc', 'description', 'title') and isinstance(v, str):
|
|
return v
|
|
found = find_desc(v)
|
|
if found:
|
|
return found
|
|
elif isinstance(obj, list):
|
|
for it in obj:
|
|
found = find_desc(it)
|
|
if found:
|
|
return found
|
|
return None
|
|
d = find_desc(data)
|
|
if isinstance(d, str):
|
|
description = d
|
|
except Exception:
|
|
description = ''
|
|
|
|
print(json.dumps({"video_path": mp4s[0].as_posix(), "description": description}, ensure_ascii=False))
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|
|
|
|
|