commit 919b9004acb8b5fee70c7c72a2c1cb13a6407afb
parent 9471e6dc61aea0a1f56304d513eaccb621753a2f
Author: david cochran <about.trout@gmail.com>
Date: Sun, 8 Sep 2024 11:17:40 -0700
download stream chunk with aiohttp rather than ffmpeg
Diffstat:
1 file changed, 28 insertions(+), 9 deletions(-)
diff --git a/ppboatwatch/stream_sampler.py b/ppboatwatch/stream_sampler.py
@@ -5,20 +5,28 @@ import logging
import os
import random
import subprocess
-import tempfile
import time
+from tempfile import mkstemp
+
DEFAULT_HEADERS = {
- "User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0",
+ "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:129.0) Gecko/20100101 Firefox/129.0",
+ "Accept": "*/*",
+ "Accept-Language": "en-US,en;q=0.5",
+ "Accept-Encoding": "gzip, deflate, br, zstd",
"Origin": "https://www.surfline.com",
- "Referer": "https://www.surfline.com/",
"DNT": "1",
+ "Referer": "https://www.surfline.com/",
+ "Sec-Fetch-Dest": "empty",
+ "Sec-Fetch-Mode": "cors",
+ "Sec-Fetch-Site": "cross-site",
+ "TE": "trailers",
}
class StreamSampler:
def __init__(self, cam_name, data_dir="./data"):
- self.base_url = f"https://cams.cdn-surfline.com/cdn-wc/wc-{cam_name}"
+ self.base_url = f"https://hls.cdn-surfline.com/oregon/wc-{cam_name}"
self.cam_name = cam_name
self.data_dir = data_dir
@@ -29,25 +37,36 @@ class StreamSampler:
headers=DEFAULT_HEADERS,
) as session:
chunk_url = await self.__get_recent_chunk_url(session)
- return self.__extract_frames(chunk_url)
+ chunk_file = await self.__get_recent_chunk(session, chunk_url)
+ return self.__extract_frames(chunk_file)
async def __get_recent_chunk_url(self, session):
- async with session.get(f"{self.base_url}/chunklist.m3u8") as res:
+ url = f"{self.base_url}/playlist.m3u8"
+ async with session.get(url) as res:
chunklist = await res.text()
chunk = next(l for l in chunklist.splitlines() if not l.startswith("#"))
return f"{self.base_url}/{chunk}"
- def __extract_frames(self, chunk_url):
+ async def __get_recent_chunk(self, session, chunk_url):
+ async with session.get(chunk_url) as res:
+ bytes = await res.read()
+ fd, chunk_file = mkstemp()
+ with os.fdopen(fd, "wb") as f:
+ f.write(bytes)
+ return chunk_file
+
+ def __extract_frames(self, chunk_file):
dt = datetime.datetime.now()
day, hour, ts = dt.strftime("%m%d%Y"), dt.strftime("%H"), dt.strftime("%s")
frames_dir = f"{self.data_dir}/{self.cam_name}/{day}/{hour}"
if not os.path.exists(frames_dir):
os.makedirs(frames_dir)
subprocess.run(["ffmpeg",
- "-hide_banner", "-loglevel", "0",
- "-i", chunk_url,
+ "-hide_banner", "-loglevel", "3",
+ "-i", chunk_file,
"-vf", "select=eq(pict_type\,I)",
"-vsync", "vfr",
f"{frames_dir}/{ts}-thumb-%04d.jpg"])
+ os.remove(chunk_file) # cleanup
# Return filenames of (ffmpeg generated) frames to caller.
return [f for f in os.scandir(frames_dir) if f.name.startswith(f"{ts}-thumb")]