Add playfox script
This commit is contained in:
parent
3c1a347fa3
commit
7251334639
1 changed files with 108 additions and 0 deletions
108
playfox
Executable file
108
playfox
Executable file
|
|
@ -0,0 +1,108 @@
|
|||
#!/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()
|
||||
Loading…
Reference in a new issue