Replace old trickplay support with new official support.

This commit is contained in:
Izzie Walton 2024-05-13 17:17:24 -04:00
parent 6660a7f181
commit 2234b0082e
5 changed files with 62 additions and 153 deletions

View File

@ -1,53 +1,7 @@
#!/usr/bin/env python3
import struct
from io import BytesIO
from PIL import Image
BIF_MAGIC = b"\x89BIF\r\n\x1a\n"
BIF_SUPPORTED = 0
def decode_file(filename):
with open(filename, "rb") as fh:
return decode(fh)
def _read_i32(fh):
return struct.unpack("<I", fh.read(4))[0]
def decode(fh):
if fh.read(8) != BIF_MAGIC:
raise ValueError("Data provided is not a BIF file.")
bif_version = _read_i32(fh)
if bif_version != BIF_SUPPORTED:
raise ValueError(f"BIF version {bif_version} is not supported.")
image_count = _read_i32(fh)
multiplier = _read_i32(fh)
fh.read(44) # unused data
index = [] # timestamp, offset
for _ in range(image_count):
index.append((_read_i32(fh), _read_i32(fh)))
images = []
for i in range(len(index)):
timestamp, offset = index[i]
if i != timestamp:
raise ValueError("BIF file is not contiguous.")
fh.seek(offset)
if i + 1 == len(index):
images.append(fh.read())
else:
images.append(fh.read(index[i + 1][1] - offset))
return {"multiplier": multiplier, "images": images}
def decompress_tiles(width, height, tile_width, tile_height, count, tiles, fh):
image_count = 0
@ -97,21 +51,3 @@ def decompress_bif(images, fh):
fh.write(image.tobytes())
return {"count": image_count, "height": height, "width": width}
if __name__ == "__main__":
import sys
bif_data = decode_file(sys.argv[1])
print(f"Images: {len(bif_data['images'])}")
print(f"Multiplier: {bif_data['multiplier']}")
# for timestamp, image in enumerate(bif_data["images"]):
# with open(f"{timestamp}.jpg", "wb") as fh:
# fh.write(image)
with open("raw_images.bin", "wb") as fh:
bif_size_info = decompress_bif(bif_data["images"], fh)
print(f"Width: {bif_size_info['width']}")
print(f"Height: {bif_size_info['height']}")

View File

@ -130,7 +130,6 @@ class Settings(SettingsBase):
skip_intro_always: bool = False
skip_intro_prompt: bool = False
thumbnail_enable: bool = True
thumbnail_jellyscrub: bool = False
thumbnail_osc_builtin: bool = True
thumbnail_preferred_size: int = 320

View File

@ -271,42 +271,29 @@ class Video(object):
yield data.getvalue()
def get_hls_tile_images(self, width, count):
for i in range(1, count + 1):
for i in range(0, count):
data = BytesIO()
self.client.jellyfin._get_stream(
f"Trickplay/{self.media_source['Id']}/{width}/{i}.jpg", data
f"Videos/{self.item['Id']}/Trickplay/{width}/{i}.jpg?MediaSourceId={self.media_source['Id']}", data
)
yield data.getvalue()
def get_bif(self, prefer_width=320):
# requires JellyScrub plugin
manifest = self.client.jellyfin._get(
f"Trickplay/{self.media_source['Id']}/GetManifest"
)
manifest = self.item.get("Trickplay")
print(manifest)
if (
manifest is not None
and manifest.get("WidthResolutions") is not None
and len(manifest["WidthResolutions"]) > 0
and manifest.get(self.media_source['Id']) is not None
and len(manifest[self.media_source['Id']]) > 0
):
available_widths = manifest["WidthResolutions"]
if type(manifest["WidthResolutions"]) is dict:
available_widths = [int(x) for x in manifest["WidthResolutions"].keys()]
available_widths = [int(x) for x in manifest[self.media_source['Id']].keys()]
if prefer_width is not None:
width = min(available_widths, key=lambda x: abs(x - prefer_width))
else:
width = max(available_widths)
if type(manifest["WidthResolutions"]) is dict:
return manifest["WidthResolutions"][str(width)]
else:
data = BytesIO()
self.client.jellyfin._get_stream(
f"Trickplay/{self.media_source['Id']}/{width}/GetBIF", data
)
data.seek(0)
return data
return manifest[self.media_source['Id']][str(width)]
else:
return None

View File

@ -558,9 +558,6 @@ class OSDMenu(object):
self.get_settings_toggle(
_("Enable thumbnail previews"), "thumbnail_enable"
),
self.get_settings_toggle(
_("Use JellyScrub thumbnails"), "thumbnail_jellyscrub"
),
],
)

View File

@ -50,77 +50,67 @@ class TrickPlay(threading.Thread):
continue
video = self.player.get_video()
if settings.thumbnail_jellyscrub:
try:
data = video.get_bif(settings.thumbnail_preferred_size)
try:
data = video.get_bif(settings.thumbnail_preferred_size)
if (
not self.player.has_video()
or video != self.player.get_video()
):
# Video changed while we were getting the bif file
continue
if data:
with open(img_file, "wb") as fh:
img_count = math.ceil(
data["ThumbnailCount"]
/ data["TileWidth"]
/ data["TileHeight"]
)
bifdecode.decompress_tiles(
data["Width"],
data["Height"],
data["TileWidth"],
data["TileHeight"],
data["ThumbnailCount"],
video.get_hls_tile_images(
data["Width"], img_count
),
fh,
)
bif_meta = {
"count": data["ThumbnailCount"],
"multiplier": data["Interval"],
"width": data["Width"],
"height": data["Height"],
}
if (
not self.player.has_video()
or video != self.player.get_video()
):
# Video changed while we were getting the bif file
# Video changed while we were decompressing the bif file
continue
if data:
if type(data) is not dict:
bif = bifdecode.decode(data)
with open(img_file, "wb") as fh:
bif_meta = bifdecode.decompress_bif(
bif["images"], fh
)
bif_meta["multiplier"] = bif["multiplier"]
else:
with open(img_file, "wb") as fh:
img_count = math.ceil(
data["TileCount"]
/ data["TileWidth"]
/ data["TileHeight"]
)
bifdecode.decompress_tiles(
data["Width"],
data["Height"],
data["TileWidth"],
data["TileHeight"],
data["TileCount"],
video.get_hls_tile_images(
data["Width"], img_count
),
fh,
)
bif_meta = {
"count": data["TileCount"],
"multiplier": data["Interval"],
"width": data["Width"],
"height": data["Height"],
}
if (
not self.player.has_video()
or video != self.player.get_video()
):
# Video changed while we were decompressing the bif file
continue
self.player.script_message(
"shim-trickplay-bif",
str(bif_meta["count"]),
str(bif_meta["multiplier"]),
str(bif_meta["width"]),
str(bif_meta["height"]),
img_file,
)
log.info(
f"Collected {bif_meta['count']} bif preview images"
)
continue
else:
log.warning("No bif file available")
except:
log.error(
"Could not get bif file. Do you have the plugin installed?",
exc_info=True,
self.player.script_message(
"shim-trickplay-bif",
str(bif_meta["count"]),
str(bif_meta["multiplier"]),
str(bif_meta["width"]),
str(bif_meta["height"]),
img_file,
)
log.info(
f"Collected {bif_meta['count']} trickplay preview images"
)
continue
else:
log.warning("No trickplay data available")
except:
log.error(
"Could not get trickplay data.",
exc_info=True,
)
chapter_data = video.get_chapters()