firetools/playfox
2026-01-12 15:48:12 -05:00

108 lines
2.9 KiB
Text
Executable file

#!/usr/bin/env -S uv run --script
# /// script
# dependencies = ["playwright"]
# ///
"""
Headless Firefox with your cookies via cookiefire.
Usage:
playfox https://twitter.com
playfox -P jtm https://private.site
playfox --interactive https://site.com
"""
import subprocess
import sys
from playwright.sync_api import sync_playwright
def parse_netscape_cookies(cookie_text):
"""Convert cookiefire output to Playwright 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]
exp = float(expires)
if exp <= 0:
exp = -1
elif exp > 9999999999:
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
def main():
args = sys.argv[1:]
profile = "jtm"
url = None
dump = False
interactive = False
i = 0
while i < len(args):
if args[i] == "-P" and i + 1 < len(args):
profile = args[i + 1]
i += 2
elif args[i] == "--dump":
dump = True
i += 1
elif args[i] == "--interactive" or args[i] == "-i":
interactive = True
i += 1
elif args[i].startswith("http"):
url = args[i]
i += 1
else:
i += 1
if not url:
print("Usage: playfox [-P profile] [--dump] [--interactive] URL", file=sys.stderr)
sys.exit(1)
# get cookies
cookie_text = subprocess.check_output(["cookiefire", profile], text=True)
cookies = parse_netscape_cookies(cookie_text)
with sync_playwright() as p:
browser = p.firefox.launch(headless=True)
context = browser.new_context()
context.add_cookies(cookies)
page = context.new_page()
# logging
page.on("console", lambda msg: print(f"[console] {msg.text}"))
page.on("pageerror", lambda err: print(f"[error] {err}"))
page.on("request", lambda req: print(f"[req] {req.method} {req.url}"))
page.goto(url)
if dump:
print(page.content())
if interactive:
print("\n--- interactive mode ---")
print("page object available as 'page'")
print("ctrl-d to exit\n")
import code
code.interact(local={"page": page, "context": context, "browser": browser})
browser.close()
if __name__ == "__main__":
main()