Queue videos
The only command actually working so far is !q. The rest will come soon, including the most important one: !dskip
This commit is contained in:
parent
30db2c7bf3
commit
89faef224e
1 changed files with 94 additions and 8 deletions
102
argondjbot.py
102
argondjbot.py
|
|
@ -1,9 +1,10 @@
|
||||||
import asyncio
|
import asyncio
|
||||||
import configparser
|
import configparser
|
||||||
#import datetime
|
import datetime
|
||||||
import isodate
|
import isodate
|
||||||
import logging
|
import logging
|
||||||
import re
|
import re
|
||||||
|
import time
|
||||||
|
|
||||||
from apiclient.discovery import build
|
from apiclient.discovery import build
|
||||||
|
|
||||||
|
|
@ -13,10 +14,13 @@ from yaboli.utils import *
|
||||||
|
|
||||||
class Video:
|
class Video:
|
||||||
DURATION_RE = r"P(\d+Y)?(\d+"
|
DURATION_RE = r"P(\d+Y)?(\d+"
|
||||||
|
DELAY = 2
|
||||||
|
|
||||||
def __init__(self, vid, title, duration, blocked):
|
def __init__(self, vid, title, duration, blocked):
|
||||||
self.id = vid,
|
self.id = vid
|
||||||
self.title = title
|
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
|
self.blocked = blocked
|
||||||
|
|
||||||
class YouTube:
|
class YouTube:
|
||||||
|
|
@ -48,16 +52,92 @@ class Playlist:
|
||||||
self.playing_video = None
|
self.playing_video = None
|
||||||
self.playing_until = 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)
|
position = len(self.waiting)
|
||||||
self.waiting.append(video)
|
self.waiting.append((video, player))
|
||||||
return position
|
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):
|
class ArgonDJBot(yaboli.Bot):
|
||||||
SHORT_HELP = "Short help placeholder"
|
SHORT_HELP = "Short help placeholder"
|
||||||
LONG_HELP = "Long 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
|
# group 5: video id
|
||||||
YOUTUBE_RE = r"((https?://)?(www\.)?(youtube\.com/(watch\?v=|embed/)|youtu\.be/))?(" + VIDEO_ID_RE + ")"
|
YOUTUBE_RE = r"((https?://)?(www\.)?(youtube\.com/(watch\?v=|embed/)|youtu\.be/))?(" + VIDEO_ID_RE + ")"
|
||||||
YOUTUBE_RE_GROUP = 6
|
YOUTUBE_RE_GROUP = 6
|
||||||
|
|
@ -111,18 +191,24 @@ class ArgonDJBot(yaboli.Bot):
|
||||||
for vid in video_ids:
|
for vid in video_ids:
|
||||||
video = videos.get(vid)
|
video = videos.get(vid)
|
||||||
if video:
|
if video:
|
||||||
position = self.playlist.add(video)
|
position = self.playlist.queue(video, message.sender.nick)
|
||||||
info = f"[{position:2}] {video.title!r} will be played in <beep>"
|
until = self.playlist.playtime_until(position)
|
||||||
|
|
||||||
|
info = Playlist.format_queue_list_entry(video, position, until)
|
||||||
lines.append(info)
|
lines.append(info)
|
||||||
|
|
||||||
text = "\n".join(lines)
|
text = "\n".join(lines)
|
||||||
await room.send(text, message.mid)
|
await room.send(text, message.mid)
|
||||||
|
|
||||||
|
self.playlist.play(room)
|
||||||
|
|
||||||
@yaboli.command("list", "l")
|
@yaboli.command("list", "l")
|
||||||
async def command_list(self, room, message, argstr):
|
async def command_list(self, room, message, argstr):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def main(configfile):
|
def main(configfile):
|
||||||
|
#asyncio.get_event_loop().set_debug(True)
|
||||||
|
#logging.basicConfig(level=logging.DEBUG)
|
||||||
logging.basicConfig(level=logging.INFO)
|
logging.basicConfig(level=logging.INFO)
|
||||||
|
|
||||||
config = configparser.ConfigParser(allow_no_value=True)
|
config = configparser.ConfigParser(allow_no_value=True)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue