diff --git a/argondjbot.py b/argondjbot.py index 832a6d7..49744f0 100644 --- a/argondjbot.py +++ b/argondjbot.py @@ -1,9 +1,10 @@ import asyncio import configparser -#import datetime +import datetime import isodate import logging import re +import time from apiclient.discovery import build @@ -13,10 +14,13 @@ from yaboli.utils import * class Video: DURATION_RE = r"P(\d+Y)?(\d+" + DELAY = 2 + def __init__(self, vid, title, duration, blocked): - self.id = vid, + self.id = vid self.title = title - self.duration = isodate.parse_duration(duration) + self.raw_duration = isodate.parse_duration(duration) + self.duration = self.raw_duration + datetime.timedelta(seconds=self.DELAY) self.blocked = blocked class YouTube: @@ -48,16 +52,92 @@ class Playlist: self.playing_video = None self.playing_until = None - def add(self, video): + # formatting functions + + @staticmethod + def format_duration(dt): + seconds = int(dt.total_seconds()) + + hours = seconds // (60*60) + seconds -= hours * (60*60) + + minutes = seconds // 60 + seconds -= minutes * 60 + + return f"{hours:02}:{minutes:02}:{seconds:02}" + + @staticmethod + def format_queue_list_entry(video, position, played_in): + played_in = Playlist.format_duration(played_in) + return f"[{position:2}] {video.title!r} will be played in [{played_in}]" + + @staticmethod + def format_play(video, player): + raw_duration = Playlist.format_duration(video.raw_duration) + player = mention(player, ping=False) + lines = [ + f"[{raw_duration}] {video.title!r} from {player}", + f"!play youtube.com/watch?v={video.id}", + ] + return "\n".join(lines) + + # commands regarding currently playing video + + def play(self, room): + if self.playing_task is None or self.playing_task.done(): + self.playing_task = asyncio.ensure_future(self._play(room)) + #asyncio.ensure_future(self._play(room)) + + async def _play(self, room): + while self.waiting: + video, player = self.waiting.pop() + duration = video.duration.total_seconds() + + self.playing_video = video + self.playing_until = time.time() + duration + + message = self.format_play(video, player) + await room.send(message) + + await asyncio.sleep(duration) + + self.playing_task = None + self.playing_video = None + self.playing_until = None + + # commands modifying the playlist + + def queue(self, video, player): position = len(self.waiting) - self.waiting.append(video) + self.waiting.append((video, player)) return position + # playlist info + + def items(self): + return enumerate(self.waiting) + + def playtime_left(self): + if self.playing_until: + seconds = self.playing_until - time.time() + return datetime.timedelta(seconds=seconds) + else: + return datetime.timedelta() + + def playtime_until(self, position=None): + if position is None: + videos = self.waiting + else: + videos = self.waiting[:position] + + video_sum = sum((video.duration for video in videos), datetime.timedelta()) + return self.playtime_left() + video_sum + class ArgonDJBot(yaboli.Bot): SHORT_HELP = "Short help placeholder" LONG_HELP = "Long help placeholder" - VIDEO_ID_RE = r"[a-zA-Z_-]{11}" + VIDEO_ID_RE = r"[a-zA-Z0-9_-]{11}" # group 5: video id YOUTUBE_RE = r"((https?://)?(www\.)?(youtube\.com/(watch\?v=|embed/)|youtu\.be/))?(" + VIDEO_ID_RE + ")" YOUTUBE_RE_GROUP = 6 @@ -111,18 +191,24 @@ class ArgonDJBot(yaboli.Bot): for vid in video_ids: video = videos.get(vid) if video: - position = self.playlist.add(video) - info = f"[{position:2}] {video.title!r} will be played in " + position = self.playlist.queue(video, message.sender.nick) + until = self.playlist.playtime_until(position) + + info = Playlist.format_queue_list_entry(video, position, until) lines.append(info) text = "\n".join(lines) await room.send(text, message.mid) + self.playlist.play(room) + @yaboli.command("list", "l") async def command_list(self, room, message, argstr): pass def main(configfile): + #asyncio.get_event_loop().set_debug(True) + #logging.basicConfig(level=logging.DEBUG) logging.basicConfig(level=logging.INFO) config = configparser.ConfigParser(allow_no_value=True)