feat: optimized autoplay with Lartz

This commit is contained in:
Terry Geng 2020-03-08 21:25:30 +08:00
parent e1a00bf236
commit 22ba308b14
6 changed files with 60 additions and 76 deletions

View File

@ -11,7 +11,7 @@ import variables as var
from librb import radiobrowser
from database import SettingsDatabase, MusicDatabase
from media.item import item_builders, item_loaders, item_id_generators, dict_to_item, dicts_to_items
from media.playlist import get_item_wrapper, get_item_wrapper_by_id, get_item_wrappers_by_tags
from media.playlist import get_item_wrapper_from_scrap, get_item_wrapper_by_id, get_item_wrappers_by_tags
from media.file import FileItem
from media.url_from_playlist import PlaylistURLItem, get_playlist_info
from media.url import URLItem
@ -197,7 +197,7 @@ def cmd_play_file(bot, user, text, command, parameter, do_not_refresh_cache=Fals
# return
if parameter in var.cache.files:
music_wrapper = get_item_wrapper(bot, type='file', path=parameter, user=user)
music_wrapper = get_item_wrapper_from_scrap(bot, type='file', path=parameter, user=user)
var.playlist.append(music_wrapper)
log.info("cmd: add to playlist: " + music_wrapper.format_debug_string())
bot.send_msg(constants.strings('file_added', item=music_wrapper.format_song_string()), text)
@ -301,7 +301,7 @@ def cmd_play_url(bot, user, text, command, parameter):
url = util.get_url_from_input(parameter)
if url:
music_wrapper = get_item_wrapper(bot, type='url', url=url, user=user)
music_wrapper = get_item_wrapper_from_scrap(bot, type='url', url=url, user=user)
var.playlist.append(music_wrapper)
log.info("cmd: add to playlist: " + music_wrapper.format_debug_string())
@ -328,7 +328,7 @@ def cmd_play_playlist(bot, user, text, command, parameter):
items = get_playlist_info(url=url, start_index=offset, user=user)
if len(items) > 0:
items = var.playlist.extend(list(map(
lambda item: get_item_wrapper(bot, **item), items)))
lambda item: get_item_wrapper_from_scrap(bot, **item), items)))
for music in items:
log.info("cmd: add to playlist: " + music.format_debug_string())
else:
@ -353,7 +353,7 @@ def cmd_play_radio(bot, user, text, command, parameter):
parameter = parameter.split()[0]
url = util.get_url_from_input(parameter)
if url:
music_wrapper = get_item_wrapper(bot, type='radio', url=url)
music_wrapper = get_item_wrapper_from_scrap(bot, type='radio', url=url)
var.playlist.append(music_wrapper)
log.info("cmd: add to playlist: " + music_wrapper.format_debug_string())
@ -452,7 +452,7 @@ def cmd_rb_play(bot, user, text, command, parameter):
url = radiobrowser.geturl_byid(parameter)
if url != "-1":
log.info('cmd: Found url: ' + url)
music_wrapper = get_item_wrapper(bot, type='radio', url=url, name=stationname, user=user)
music_wrapper = get_item_wrapper_from_scrap(bot, type='radio', url=url, name=stationname, user=user)
var.playlist.append(music_wrapper)
log.info("cmd: add to playlist: " + music_wrapper.format_debug_string())
bot.async_download_next()
@ -966,7 +966,7 @@ def cmd_shortlist(bot, user, text, command, parameter):
if 1 <= index <= len(song_shortlist):
kwargs = song_shortlist[index - 1]
kwargs['user'] = user
music_wrapper = get_item_wrapper(bot, **kwargs)
music_wrapper = get_item_wrapper_from_scrap(bot, **kwargs)
var.playlist.append(music_wrapper)
log.info("cmd: add to playlist: " + music_wrapper.format_debug_string())
msgs.append("<li><b>{}</b></li>".format(music_wrapper.item().title))
@ -984,7 +984,7 @@ def cmd_shortlist(bot, user, text, command, parameter):
if 1 <= index <= len(song_shortlist):
kwargs = song_shortlist[index - 1]
kwargs['user'] = user
music_wrapper = get_item_wrapper(bot, **kwargs)
music_wrapper = get_item_wrapper_from_scrap(bot, **kwargs)
var.playlist.append(music_wrapper)
log.info("cmd: add to playlist: " + music_wrapper.format_debug_string())
bot.send_msg(constants.strings('file_added', item=music_wrapper.format_song_string()), text)

View File

@ -33,6 +33,7 @@ comment = Hi, I'm here to play radio, local music or youtube/soundcloud music. H
volume = 0.1
# playback mode should be one of "one-shot", "loop", "random", "autoplay"
playback_mode = one-shot
autoplay_length = 5
# target version, stable or testing (testing need to bot installed with git)
target_version = stable

View File

@ -32,7 +32,9 @@ port = 64738
# it should be one of "one-shot" (remove item once played), "repeat" (looping through the playlist),
# or "random" (randomize the playlist), "autoplay" (randomly grab something from the music library).
# This option will be overridden by value in the database.
# 'autoplay_length': how many songs the autoplay mode fills the playlist
#playback_mode = one-shot
#autoplay_length = 5
# target version, stable or testing (testing need to bot installed with git)
# stable will use simple bash with curl command to get releases, testing will follow github master branch with git commands

View File

@ -217,27 +217,15 @@ class MusicDatabase:
"WHERE %s" % condition_str, filler).fetchall()
conn.close()
if len(results) > 0:
music_dicts = []
for result in results:
music_dict = json.loads(result[3])
music_dict['type'] = result[1]
music_dict['title'] = result[2]
music_dict['tags'] = result[4].strip(",").split(",")
music_dict['id'] = result[0]
music_dicts.append(music_dict)
return music_dicts
else:
return None
return self._result_to_dict(results)
def query_music_by_keywords(self, keywords):
condition = []
filler = []
for keyword in keywords:
condition.append('title LIKE ?')
filler.append("%{:s}%".format(keyword))
condition.append('LOWER(title) LIKE ?')
filler.append("%{:s}%".format(keyword.lower()))
condition_str = " AND ".join(condition)
@ -248,30 +236,15 @@ class MusicDatabase:
"WHERE %s" % condition_str, filler).fetchall()
conn.close()
if len(results) > 0:
music_dicts = []
for result in results:
music_dict = json.loads(result[3])
music_dict['type'] = result[1]
music_dict['title'] = result[2]
music_dict['id'] = result[0]
music_dict['tags'] = result[4].strip(",").split(",")
if not music_dict['tags'][0]:
music_dict['tags'] = []
music_dicts.append(music_dict)
return music_dicts
else:
return None
return self._result_to_dict(results)
def query_music_by_tags(self, tags):
condition = []
filler = []
for tag in tags:
condition.append('tags LIKE ?')
filler.append("%{:s},%".format(tag))
condition.append('LOWER(tags) LIKE ?')
filler.append("%{:s},%".format(tag.lower()))
condition_str = " AND ".join(condition)
@ -282,22 +255,7 @@ class MusicDatabase:
"WHERE %s" % condition_str, filler).fetchall()
conn.close()
if len(results) > 0:
music_dicts = []
for result in results:
music_dict = json.loads(result[3])
music_dict['type'] = result[1]
music_dict['title'] = result[2]
music_dict['id'] = result[0]
music_dict['tags'] = result[4].strip(",").split(",")
if not music_dict['tags'][0]:
music_dict['tags'] = []
music_dicts.append(music_dict)
return music_dicts
else:
return None
return self._result_to_dict(results)
def query_tags_by_id(self, id):
conn = sqlite3.connect(self.db_path)
@ -313,6 +271,34 @@ class MusicDatabase:
else:
return None
def query_random_music(self, count):
conn = sqlite3.connect(self.db_path)
cursor = conn.cursor()
results = cursor.execute("SELECT id, type, title, metadata, tags FROM music "
"WHERE id IN (SELECT id FROM music ORDER BY RANDOM() LIMIT ?)", (count,)).fetchall()
conn.close()
return self._result_to_dict(results)
def _result_to_dict(self, results):
if len(results) > 0:
music_dicts = []
for result in results:
music_dict = json.loads(result[3])
music_dict['type'] = result[1]
music_dict['title'] = result[2]
music_dict['id'] = result[0]
music_dict['tags'] = result[4].strip(",").split(",")
if not music_dict['tags'][0]:
music_dict['tags'] = []
music_dicts.append(music_dict)
return music_dicts
else:
return None
def delete_music(self, **kwargs):
condition = []
filler = []

View File

@ -10,7 +10,7 @@ import shutil
from werkzeug.utils import secure_filename
import errno
import media
from media.playlist import get_item_wrapper, get_item_wrapper_by_id, get_item_wrappers_by_tags
from media.playlist import get_item_wrapper_from_scrap, get_item_wrapper_by_id, get_item_wrappers_by_tags
import logging
import time
@ -238,7 +238,7 @@ def post():
elif 'add_url' in request.form:
music_wrapper = get_item_wrapper(var.bot, type='url', url=request.form['add_url'], user=user)
music_wrapper = get_item_wrapper_from_scrap(var.bot, type='url', url=request.form['add_url'], user=user)
var.playlist.append(music_wrapper)
log.info("web: add to playlist: " + music_wrapper.format_debug_string())
@ -248,7 +248,7 @@ def post():
elif 'add_radio' in request.form:
url = request.form['add_radio']
music_wrapper = get_item_wrapper(var.bot, type='radio', url=url, user=user)
music_wrapper = get_item_wrapper_from_scrap(var.bot, type='radio', url=url, user=user)
var.playlist.append(music_wrapper)
log.info("cmd: add to playlist: " + music_wrapper.format_debug_string())

View File

@ -6,6 +6,7 @@ import random
import variables as var
from media.file import FileItem
from media.item import dict_to_item
from media.url import URLItem
from media.url_from_playlist import PlaylistURLItem
from media.radio import RadioItem
@ -96,12 +97,17 @@ class PlaylistItemWrapper:
# Remember!!! Using these three get wrapper functions will automatically add items into the cache!
def get_item_wrapper(bot, **kwargs):
def get_item_wrapper_from_scrap(bot, **kwargs):
item = var.cache.get_item(bot, **kwargs)
if 'user' not in kwargs:
raise KeyError("Which user added this song?")
return PlaylistItemWrapper(var.cache, item.id, kwargs['type'], kwargs['user'])
def get_item_wrapper_from_dict(bot, dict_from_db, user):
item = dict_to_item(bot, dict_from_db)
var.cache[dict_from_db['id']] = item
return PlaylistItemWrapper(var.cache, item.id, item.type, user)
def get_item_wrapper_by_id(bot, id, user):
item = var.cache.get_item_by_id(bot, id)
if item:
@ -441,16 +447,14 @@ class RandomPlaylist(BasePlaylist):
return self[0]
class AutoPlaylist(BasePlaylist):
class AutoPlaylist(OneshotPlaylist):
def __init__(self):
super().__init__()
self.mode = "autoplay"
def refresh(self):
_list = []
ids = var.music_db.query_all_ids()
for _ in range(20):
_list.append(get_item_wrapper_by_id(var.bot, ids[random.randint(0, len(ids)-1)], 'AutoPlay'))
dicts = var.music_db.query_random_music(var.config.getint("bot", "autoplay_length", fallback=5))
_list = [get_item_wrapper_from_dict(var.bot, _dict, "AutoPlay") for _dict in dicts]
self.from_list(_list, -1)
# def from_list(self, _list, current_index):
@ -465,14 +469,5 @@ class AutoPlaylist(BasePlaylist):
def next(self):
if len(self) == 0:
self.refresh()
return False
return super().next()
self.version += 1
if self.current_index < len(self) - 1:
self.current_index += 1
return self[self.current_index]
else:
self.refresh()
self.current_index = 0
return self[0]