kaledonya clips: a Discord-friendly clip site on top of Zipline
Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
commit
e6f8905377
34 files changed
+2917
No files matched your search
@@ -0,0 +1,38 @@
|
||||
"""Size and a still frame of a clip, read straight from Zipline with ffprobe/ffmpeg, for Discord's link preview."""
|
||||
import json
|
||||
import subprocess
|
||||
import threading
|
||||
from functools import lru_cache
|
||||
|
||||
# /v/ and /_site/thumb need no login: cap how many ffmpeg/ffprobe processes they can start at once
|
||||
SLOTS = threading.BoundedSemaphore(2)
|
||||
|
||||
|
||||
@lru_cache(maxsize=256)
|
||||
def video_size(url: str, length: str) -> tuple[int, int] | None:
|
||||
"""(width, height) of the first video stream; `length` is only part of the cache key (a reused name)."""
|
||||
cmd = ["ffprobe", "-v", "error", "-select_streams", "v:0",
|
||||
"-show_entries", "stream=width,height", "-of", "json", url]
|
||||
try:
|
||||
with SLOTS:
|
||||
result = subprocess.run(cmd, capture_output=True, timeout=10)
|
||||
stream = json.loads(result.stdout)["streams"][0]
|
||||
return int(stream["width"]), int(stream["height"])
|
||||
except (OSError, subprocess.TimeoutExpired, ValueError, KeyError, IndexError):
|
||||
return None
|
||||
|
||||
|
||||
@lru_cache(maxsize=64)
|
||||
def still_jpeg(url: str, length: str) -> bytes | None:
|
||||
"""One frame (1 s in, or the first one for very short clips) as a JPEG at most 720 px tall."""
|
||||
for seek in ("1", "0"):
|
||||
cmd = ["ffmpeg", "-v", "error", "-ss", seek, "-i", url, "-frames:v", "1",
|
||||
"-vf", "scale=-2:'min(720,ih)'", "-f", "image2", "-c:v", "mjpeg", "pipe:1"]
|
||||
try:
|
||||
with SLOTS:
|
||||
result = subprocess.run(cmd, capture_output=True, timeout=30)
|
||||
except (OSError, subprocess.TimeoutExpired):
|
||||
return None
|
||||
if result.returncode == 0 and result.stdout:
|
||||
return result.stdout
|
||||
return None
|
||||
Reference in new issue
Block a user