fediplug/fediplay/queue.py

88 lines
2.5 KiB
Python
Raw Normal View History

2018-03-17 23:06:43 +01:00
'''The play queue.'''
2018-07-20 18:06:11 +02:00
from os import path
2018-03-17 23:06:43 +01:00
import shlex
from subprocess import run
from threading import Thread, Lock
2018-04-03 02:09:25 +02:00
import click
2018-07-20 18:06:11 +02:00
from youtube_dl import YoutubeDL, utils
2018-03-17 23:06:43 +01:00
2018-03-18 01:04:04 +01:00
import fediplay.env as env
2018-07-20 17:57:00 +02:00
2018-03-17 23:06:43 +01:00
class Queue(object):
'''The play queue.'''
# pylint: disable=too-few-public-methods
2018-07-20 18:06:11 +02:00
def __init__(self, cache_dir):
2018-03-17 23:06:43 +01:00
self.lock = Lock()
self.playing = False
self.queue = []
2018-07-20 18:06:11 +02:00
self.cache_dir = cache_dir
2018-03-17 23:06:43 +01:00
def add(self, url):
'''Fetches the url and adds the resulting audio to the play queue.'''
2018-07-20 19:18:09 +02:00
filenames = Getter(self.cache_dir).get(url)
2018-03-17 23:06:43 +01:00
with self.lock:
self.queue.extend(filenames)
2018-03-17 23:06:43 +01:00
if not self.playing:
self._play(self.queue.pop(0), self._play_finished)
def _play(self, filename, cb_complete):
self.playing = True
def _run_thread(filename, cb_complete):
play_command = build_play_command(filename)
2018-04-03 02:09:25 +02:00
click.echo('==> Playing {} with {}'.format(filename, play_command))
2018-03-17 23:06:43 +01:00
run(play_command, shell=True)
2018-04-03 02:09:25 +02:00
click.echo('==> Playback complete')
2018-03-17 23:06:43 +01:00
cb_complete()
thread = Thread(target=_run_thread, args=(filename, cb_complete))
thread.start()
def _play_finished(self):
with self.lock:
self.playing = False
if self.queue:
self._play(self.queue.pop(0), self._play_finished)
class Getter(object):
'''Fetches music from a url.'''
# pylint: disable=too-few-public-methods
2018-07-20 18:06:11 +02:00
def __init__(self, cache_dir):
2018-03-17 23:06:43 +01:00
self.filename = None
self.filenames = []
2018-07-20 18:06:11 +02:00
self.cache_dir = cache_dir
2018-03-17 23:06:43 +01:00
def _progress_hook(self, progress):
if progress['status'] == 'downloading' and progress['filename'] not in self.filenames:
self.filenames.append(progress['filename'])
2018-03-17 23:06:43 +01:00
def get(self, url):
'''Fetches music from the given url.'''
options = {
'format': 'mp3/mp4',
2018-03-18 01:04:04 +01:00
'nocheckcertificate': env.no_check_certificate(),
2018-07-20 18:06:11 +02:00
'outtmpl': path.join(self.cache_dir, utils.DEFAULT_OUTTMPL),
2018-03-17 23:06:43 +01:00
'progress_hooks': [self._progress_hook]
}
with YoutubeDL(options) as downloader:
downloader.download([url])
return self.filenames
2018-03-17 23:06:43 +01:00
def build_play_command(filename):
'''Builds a play command for the given filename.'''
escaped_filename = shlex.quote(filename)
2018-03-18 01:04:04 +01:00
template = env.play_command()
2018-03-17 23:06:43 +01:00
return template.format(filename=escaped_filename)