Kodi.plugin.audio.subsonic/addon.py

415 lines
12 KiB
Python

import os
import sys
import urllib
import urlparse
import xbmc
import xbmcgui
import xbmcaddon
import xbmcplugin
# Make sure library folder is on the path
addon = xbmcaddon.Addon("plugin.audio.subsonic")
sys.path.append(xbmc.translatePath(os.path.join(
addon.getAddonInfo("path"), "lib")))
import libsonic_extra
class Plugin(object):
"""
Plugin container
"""
def __init__(self, addon_url, addon_handle, addon_args):
self.addon_url = addon_url
self.addon_handle = addon_handle
self.addon_args = addon_args
# Retrieve plugin settings
self.url = addon.getSetting("subsonic_url")
self.username = addon.getSetting("username")
self.password = addon.getSetting("password")
self.random_count = addon.getSetting("random_count")
self.bitrate = addon.getSetting("bitrate")
self.trans_format = addon.getSetting("trans_format")
# Create connection
self.connection = libsonic_extra.Connection(
self.url, self.username, self.password)
def build_url(self, query):
"""
"""
parts = list(urlparse.urlparse(self.addon_url))
parts[4] = urllib.urlencode(query)
return urlparse.urlunparse(parts)
def walk_genres(self):
"""
Request Subsonic's genres list and iterate each item.
"""
response = self.connection.getGenres()
for genre in response["genres"]["genre"]:
yield genre
def walk_artists(self):
"""
Request SubSonic's index and iterate each item.
"""
response = self.connection.getArtists()
for index in response["artists"]["index"]:
for artist in index["artist"]:
yield artist
def walk_album_list2_genre(self, genre):
"""
"""
offset = 0
while True:
response = self.connection.getAlbumList2(
ltype="byGenre", genre=genre, size=500, offset=offset)
if not response["albumList2"]["album"]:
break
for album in response["albumList2"]["album"]:
yield album
offset += 500
def walk_album(self, album_id):
"""
Request Album and iterate each song.
"""
response = self.connection.getAlbum(album_id)
for song in response["album"]["song"]:
yield song
def walk_playlists(self):
"""
Request SubSonic's playlists and iterate over each item.
"""
response = self.connection.getPlaylists()
for child in response["playlists"]["playlist"]:
yield child
def walk_playlist(self, playlist_id):
"""
Request SubSonic's playlist items and iterate over each item.
"""
response = self.connection.getPlaylist(playlist_id)
for order, child in enumerate(response["playlist"]["entry"], start=1):
child["order"] = order
yield child
def walk_directory(self, directory_id):
"""
Request a SubSonic music directory and iterate over each item.
"""
response = self.connection.getMusicDirectory(directory_id)
for child in response["directory"]["child"]:
if child.get("isDir"):
for child in self.walk_directory(child["id"]):
yield child
else:
yield child
def walk_artist(self, artist_id):
"""
Request a SubSonic artist and iterate over each album.
"""
response = self.connection.getArtist(artist_id)
for child in response["artist"]["album"]:
yield child
def walk_random_songs(self, size, genre=None, from_year=None,
to_year=None):
"""
"""
response = self.connection.getRandomSongs(
size=size, genre=genre, fromYear=from_year, toYear=to_year)
for song in response["randomSongs"]["song"]:
song["id"] = int(song["id"])
yield song
def route(self):
mode = self.addon_args.get("mode", ["main_page"])[0]
getattr(self, mode)()
def add_track(self, track, show_artist=False):
"""
"""
cover_art_url = self.connection.getCoverArtUrl(track["id"])
url = self.connection.streamUrl(
sid=track["id"], maxBitRate=self.bitrate,
tformat=self.trans_format)
if show_artist:
li = xbmcgui.ListItem(track["artist"] + " - " + track["title"])
else:
li = xbmcgui.ListItem(track["title"])
li.setIconImage(cover_art_url)
li.setThumbnailImage(cover_art_url)
li.setProperty("fanart_image", cover_art_url)
li.setProperty("IsPlayable", "true")
li.setInfo(type="Music", infoLabels={
"Artist": track["artist"],
"Title": track["title"],
"Year": track.get("year"),
"Duration": track.get("duration"),
"Genre": track.get("genre")})
xbmcplugin.addDirectoryItem(
handle=self.addon_handle, url=url, listitem=li)
def add_album(self, album, show_artist=False):
cover_art_url = self.connection.getCoverArtUrl(album["id"])
url = self.build_url({
"mode": "track_list",
"album_id": album["id"]})
if show_artist:
li = xbmcgui.ListItem(album["artist"] + " - " + album["name"])
else:
li = xbmcgui.ListItem(album["name"])
li.setIconImage(cover_art_url)
li.setThumbnailImage(cover_art_url)
li.setProperty("fanart_image", cover_art_url)
xbmcplugin.addDirectoryItem(
handle=self.addon_handle, url=url, listitem=li, isFolder=True)
def main_page(self):
"""
Display main menu.
"""
menu = [
{"mode": "playlists_list", "foldername": "Playlists"},
{"mode": "artist_list", "foldername": "Artists"},
{"mode": "genre_list", "foldername": "Genres"},
{"mode": "random_list", "foldername": "Random songs"}]
for entry in menu:
url = self.build_url(entry)
li = xbmcgui.ListItem(entry["foldername"])
xbmcplugin.addDirectoryItem(
handle=self.addon_handle, url=url, listitem=li, isFolder=True)
xbmcplugin.endOfDirectory(self.addon_handle)
def playlists_list(self):
"""
Display playlists.
"""
for playlist in self.walk_playlists():
cover_art_url = self.connection.getCoverArtUrl(
playlist["coverArt"])
url = self.build_url({
"mode": "playlist_list", "playlist_id": playlist["id"]})
li = xbmcgui.ListItem(playlist["name"], iconImage=cover_art_url)
xbmcplugin.addDirectoryItem(
handle=self.addon_handle, url=url, listitem=li, isFolder=True)
xbmcplugin.endOfDirectory(self.addon_handle)
def playlist_list(self):
"""
Display playlist tracks.
"""
playlist_id = self.addon_args["playlist_id"][0]
for track in self.walk_playlist(playlist_id):
self.add_track(track, show_artist=True)
xbmcplugin.setContent(self.addon_handle, "songs")
xbmcplugin.endOfDirectory(self.addon_handle)
def genre_list(self):
"""
Display list of genres menu.
"""
for genre in self.walk_genres():
url = self.build_url({
"mode": "albums_by_genre_list",
"foldername": genre["value"].encode("utf-8")})
li = xbmcgui.ListItem(genre["value"])
xbmcplugin.addDirectoryItem(
handle=self.addon_handle, url=url, listitem=li, isFolder=True)
xbmcplugin.endOfDirectory(self.addon_handle)
def albums_by_genre_list(self):
"""
Display album list by genre menu.
"""
genre = self.addon_args["foldername"][0].decode("utf-8")
for album in self.walk_album_list2_genre(genre):
self.add_album(album, show_artist=True)
xbmcplugin.setContent(self.addon_handle, "albums")
xbmcplugin.endOfDirectory(self.addon_handle)
def artist_list(self):
"""
Display artist list
"""
for artist in self.walk_artists():
cover_art_url = self.connection.getCoverArtUrl(artist["id"])
url = self.build_url({
"mode": "album_list",
"artist_id": artist["id"]})
li = xbmcgui.ListItem(artist["name"])
li.setIconImage(cover_art_url)
li.setThumbnailImage(cover_art_url)
li.setProperty("fanart_image", cover_art_url)
xbmcplugin.addDirectoryItem(
handle=self.addon_handle, url=url, listitem=li, isFolder=True)
xbmcplugin.setContent(self.addon_handle, "artists")
xbmcplugin.endOfDirectory(self.addon_handle)
def album_list(self):
"""
Display list of albums for certain artist.
"""
artist_id = self.addon_args["artist_id"][0]
for album in self.walk_artist(artist_id):
self.add_album(album)
xbmcplugin.setContent(self.addon_handle, "albums")
xbmcplugin.endOfDirectory(self.addon_handle)
def track_list(self):
"""
Display track list.
"""
album_id = self.addon_args["album_id"][0]
for track in self.walk_album(album_id):
self.add_track(track)
xbmcplugin.setContent(self.addon_handle, "songs")
xbmcplugin.endOfDirectory(self.addon_handle)
def random_list(self):
"""
Display random options.
"""
menu = [
{"mode": "random_by_genre_list", "foldername": "By genre"},
{"mode": "random_by_year_list", "foldername": "By year"}]
for entry in menu:
url = self.build_url(entry)
li = xbmcgui.ListItem(entry["foldername"])
xbmcplugin.addDirectoryItem(
handle=self.addon_handle, url=url, listitem=li, isFolder=True)
xbmcplugin.endOfDirectory(self.addon_handle)
def random_by_genre_list(self):
"""
Display random genre list.
"""
for genre in self.walk_genres():
url = self.build_url({
"mode": "random_by_genre_track_list",
"foldername": genre["value"].encode("utf-8")})
li = xbmcgui.ListItem(genre["value"])
xbmcplugin.addDirectoryItem(
handle=self.addon_handle, url=url, listitem=li, isFolder=True)
xbmcplugin.endOfDirectory(self.addon_handle)
def random_by_genre_track_list(self):
"""
Display random tracks by genre
"""
genre = self.addon_args["foldername"][0].decode("utf-8")
for track in self.walk_random_songs(
size=self.random_count, genre=genre):
self.add_track(track, show_artist=True)
xbmcplugin.setContent(self.addon_handle, "songs")
xbmcplugin.endOfDirectory(self.addon_handle)
def random_by_year_list(self):
"""
Display random tracks by year.
"""
from_year = xbmcgui.Dialog().input(
"From year", type=xbmcgui.INPUT_NUMERIC)
to_year = xbmcgui.Dialog().input(
"To year", type=xbmcgui.INPUT_NUMERIC)
for track in self.walk_random_songs(
size=self.random_count, from_year=from_year, to_year=to_year):
self.add_track(track, show_artist=True)
xbmcplugin.setContent(self.addon_handle, "songs")
xbmcplugin.endOfDirectory(self.addon_handle)
def main():
"""
Entry point for this plugin.
"""
addon_url = sys.argv[0]
addon_handle = int(sys.argv[1])
addon_args = urlparse.parse_qs(sys.argv[2][1:])
# Route request to action
Plugin(addon_url, addon_handle, addon_args).route()
# Start plugin from Kodi
if __name__ == "__main__":
main()