Skip to content

Commit

Permalink
Give MPV stream URLs rather than relying on ytdl_hook to fetch
Browse files Browse the repository at this point in the history
This is an initial implementation of #3 however it doesn't add all the
metadata that ytdl_hook does.
  • Loading branch information
Douile committed Sep 10, 2023
1 parent 4163914 commit 1f87f95
Showing 1 changed file with 43 additions and 8 deletions.
51 changes: 43 additions & 8 deletions friends_queue/video_queue.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@ class VideoQueueItem:
uploader: str = None
duration: int = None
duration_str: str = None
stream_url: str = None
video_url: str = None
audio_url: str = None
thumbnail: str = None


# TODO: Lock queue
# TODO: Async ytdl fetch
class VideoQueue(List[VideoQueueItem]):
def __init__(
self, player: mpv.MPV, ytdl: yt_dlp.YoutubeDL, thumbnails: ThumbnailCache
Expand All @@ -36,10 +36,17 @@ def __init__(
def append(self, item: VideoQueueItem):
assert item is not None
super().append(item)
self._player.loadfile(item.url, mode="append-play")

args = {}
if item.audio_url is not None:
args["audio_file"] = item.audio_url
if item.title is not None:
args["force_media_title"] = item.title
self._player.loadfile(item.video_url or item.url, mode="append-play", **args)

def append_url(self, url: str):
self.append(fetch_video(self._ytdl, self._thumbs, url))
"""Fetch video URL and asyncronously append to queue"""
fetch_video(self._ytdl, self._thumbs, self, url)

def move(self, item: int, to: int):
assert item >= 0 and item < len(self)
Expand Down Expand Up @@ -70,35 +77,63 @@ def choose_thumbnail(thumbnails):
return None


def get_stream_urls(info):
video = None
audio = None

streams = info.get("requested_formats")
if streams is not None:
for stream in streams:
if stream.get("video_ext", "none") != "none":
video = stream
elif stream.get("audio_ext", "none") != "none":
audio = stream

return (video, audio)


class FetchVideoThread(Thread):
def __init__(
self, ytdl: yt_dlp.YoutubeDL, thumbnails: ThumbnailCache, item: VideoQueueItem
self,
ytdl: yt_dlp.YoutubeDL,
thumbnails: ThumbnailCache,
queue: VideoQueue,
item: VideoQueueItem,
):
super().__init__(daemon=True)
self._ytdl = ytdl
self._thumbs = thumbnails
self._queue = queue
self._item = item

def run(self):
# Fetch video info
info = self._ytdl.extract_info(self._item.url, download=False)
self._item.title = info.get("fulltitle")
self._item.uploader = info.get("uploader")
self._item.stream_url = None # TODO
self._item.duration = info.get("duration")
self._item.duration_str = info.get("duration_string")

video, audio = get_stream_urls(info)
self._item.video_url = video.get("url")
self._item.audio_url = audio.get("url")
# TODO: Add other metadata added by ytdl_hook e.g. subtitles, chapters, bitrate

# Append before fetching thumbnail as that requires another request and is not required to
# play the video
self._queue.append(self._item)

# Fetch video thumbnail (as base64)
thumbnail = choose_thumbnail(info.get("thumbnails"))
if thumbnail is not None:
self._item.thumbnail = self._thumbs.cache_thumbnail(thumbnail)


def fetch_video(
ytdl: yt_dlp.YoutubeDL, thumbnails: ThumbnailCache, url: str
ytdl: yt_dlp.YoutubeDL, thumbnails: ThumbnailCache, queue: VideoQueue, url: str
) -> VideoQueueItem:
item = VideoQueueItem(url)

FetchVideoThread(ytdl, thumbnails, item).start()
FetchVideoThread(ytdl, thumbnails, queue, item).start()

return item

0 comments on commit 1f87f95

Please sign in to comment.