firetools/shotscraper

98 lines
2.7 KiB
Text
Executable file

#!/usr/bin/env -S uv run --script
# /// script
# dependencies = ["shot-scraper"]
# ///
"""
shot-scraper wrapper that uses Firefox cookies via cookiefire.
Usage:
shotscraper https://example.com -o out.png
shotscraper -P jtm https://private.com -o private.png
"""
import json
import os
import subprocess
import sys
import tempfile
def parse_netscape_cookies(cookie_text):
"""Convert Netscape cookie format to Playwright storage_state format."""
cookies = []
for line in cookie_text.strip().split('\n'):
if line.startswith('#') or not line.strip():
continue
parts = line.split('\t')
if len(parts) >= 7:
domain, _, path, secure, expires, name, value = parts[:7]
# playwright requires -1 (session) or positive unix timestamp in seconds
# firefox stores milliseconds, so divide by 1000
exp = float(expires)
if exp <= 0:
exp = -1
elif exp > 9999999999: # looks like milliseconds
exp = exp / 1000
cookies.append({
"name": name,
"value": value,
"domain": domain,
"path": path,
"expires": exp,
"httpOnly": False,
"secure": secure.upper() == "TRUE",
"sameSite": "Lax",
})
return {"cookies": cookies, "origins": []}
def main():
args = sys.argv[1:]
profile = "jtm"
passthrough = []
# extract -P profile from args
i = 0
while i < len(args):
if args[i] == "-P" and i + 1 < len(args):
next_arg = args[i + 1]
# don't treat URLs as profile names
if next_arg.startswith("http://") or next_arg.startswith("https://"):
passthrough.append(next_arg)
i += 2
else:
profile = next_arg
i += 2
else:
passthrough.append(args[i])
i += 1
# get cookies from firefox
try:
cookie_text = subprocess.check_output(
["cookiefire", profile],
text=True
)
except subprocess.CalledProcessError as e:
print(f"cookiefire failed: {e}", file=sys.stderr)
sys.exit(1)
storage_state = parse_netscape_cookies(cookie_text)
# write to temp file
with tempfile.NamedTemporaryFile(
mode='w', suffix='.json', delete=False
) as f:
json.dump(storage_state, f)
auth_file = f.name
try:
cmd = ["shot-scraper", "--auth", auth_file] + passthrough
result = subprocess.run(cmd)
sys.exit(result.returncode)
finally:
os.unlink(auth_file)
if __name__ == "__main__":
main()