Skip to content

Instantly share code, notes, and snippets.

@Summertime
Last active May 7, 2025 16:11
Show Gist options
  • Save Summertime/eb00afb0c94d688e67cb2efe769be1e9 to your computer and use it in GitHub Desktop.
Save Summertime/eb00afb0c94d688e67cb2efe769be1e9 to your computer and use it in GitHub Desktop.
#!/usr/bin/env python
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('-n', '--count', metavar='TIMES', default=None, type=int)
parser.add_argument('-e', '--every', metavar='SECONDS', default=5, type=float)
parser.add_argument('-o', '--stdout', action='store_true')
parser.add_argument('-H', '--header', dest='headers', metavar=('KEY', 'VALUE'), action='append', default=[], nargs=2)
parser.add_argument('-t', '--template', default='%Y-%m-%dT%H:%M:%S.%f%:z')
parser.add_argument('--timeout', metavar='SECONDS', default=60, type=float)
parser.add_argument('url')
args = parser.parse_args()
# Imagine paying 1s to run `prog -h`, couldn't be me.
import contextlib
from datetime import datetime, timedelta, UTC
from zoneinfo import ZoneInfo
import requests
import urllib3
from itertools import repeat
from time import monotonic, sleep
import sys
@contextlib.contextmanager
def uncontext(item):
yield item
def every(delay, iterable=repeat(None)):
yielded_at = -delay
for i in iterable:
sleep(max(0, yielded_at + delay - monotonic()))
yielded_at = monotonic()
yield i
session = requests.Session()
session.headers['User-Agent'] = urllib3.util.SKIP_HEADER
for key,value in args.headers:
session.headers[key] = value
for _ in every(args.every, repeat(None) if args.count is None else repeat(None, args.count)):
fn = datetime.now(UTC).strftime(args.template)
try:
with session.get(args.url, timeout=args.timeout, stream=True) as response:
with ( uncontext(sys.stdout.buffer) if args.stdout else open(fn, 'wb') ) as fd:
for chunk in response.iter_content(chunk_size=2**20):
fd.write(chunk)
except Exception as e:
print(e, file=sys.stderr)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment