# -*- coding: utf-8 -*- # # Copyright (C) 2014 Thomas Amland, Arne Svenson # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. from __future__ import unicode_literals import sys import traceback import urllib import xbmc import xbmcgui import xbmcplugin from xbmcgui import ListItem from requests import HTTPError from resources.lib.tidalapi.models import Quality, Category, SubscriptionType from resources.lib.koditidal import plugin, addon, _addon_id, _T, _P, log, ALBUM_PLAYLIST_TAG, KODI_VERSION from resources.lib.koditidal2 import FolderItem2, TidalSession2 as TidalSession # This is the Tidal Session session = TidalSession() session.load_session() add_items = session.add_list_items add_directory = session.add_directory_item CONTENT_FOR_TYPE = {'artists': 'artists', 'albums': 'albums', 'playlists': 'albums', 'tracks': 'songs', 'videos': 'musicvideos', 'files': 'files'} HOMEPAGE_ITEM_TYPES = {'PLAYLIST_LIST': 'playlists', 'ALBUM_LIST': 'albums', 'TRACK_LIST': 'tracks', 'VIDEO_LIST': 'videos', 'MIX_LIST': 'mix'} @plugin.route('/') def root(): if session.is_logged_in: add_directory(_T(30201), my_music) add_directory(_T(30212), plugin.url_for(homepage_items)) add_directory(_T(30202), featured_playlists) if getattr(session._config, 'cache_albums', False): add_directory(_T(30509), plugin.url_for(albums_with_videos)) categories = Category.groups() for item in categories: add_directory(_T(item), plugin.url_for(category, group=item)) add_directory(_T(30206), search) add_directory(_T(30027), settings, isFolder=False) if session.is_logged_in: add_directory(_T(30207), logout, end=True, isFolder=False) else: add_directory(_T(30208), login, end=True, isFolder=False) @plugin.route('/settings') def settings(): xbmc.executebuiltin('Addon.OpenSettings("%s")' % _addon_id) @plugin.route('/homepage_items') def homepage_items(): params = { 'locale': session._config.locale, 'deviceType': 'BROWSER' } apiPaths = [] items = [] r = session.request('GET', 'pages/home', params=params) if r.ok: json_obj = r.json() for row in json_obj['rows']: for module in row['modules']: try: item_type = module['type'] if item_type in HOMEPAGE_ITEM_TYPES: apiPath = module['pagedList']['dataApiPath'] item = FolderItem2(module['title'], plugin.url_for(homepage_item, item_type, urllib.quote_plus(apiPath))) items.append(item) apiPaths.append(apiPath) else: log('Unknown Homepage Item "%s": %s' % (item_type, module.get('title', 'Unknown')), level=xbmc.LOGDEBUG) except: pass r = session.request('GET', 'pages/videos', params=params) if r.ok: json_obj = r.json() for row in json_obj['rows']: for module in row['modules']: try: item_type = module['type'] if item_type in HOMEPAGE_ITEM_TYPES: apiPath = module['pagedList']['dataApiPath'] item = FolderItem2(module['title'], plugin.url_for(homepage_item, item_type, urllib.quote_plus(apiPath))) if not apiPath in apiPaths: if item_type == 'MIX_LIST': item.name = item.name + ' (' + _P('videos') + ')' items.insert(1, item) else: items.append(item) apiPaths.append(apiPath) else: log('Unknown Homepage Item "%s": %s' % (item_type, module.get('title', 'Unknown')), level=xbmc.LOGDEBUG) except: pass session.add_list_items(items, end=True) @plugin.route('/homepage_item/<item_type>/<path>') def homepage_item(item_type, path): path = urllib.unquote_plus(path).decode('utf-8').strip() rettype = HOMEPAGE_ITEM_TYPES.get(item_type, 'NONE') if rettype <> 'NONE': params = { 'locale': session._config.locale, 'deviceType': 'BROWSER', 'offset': 0, 'limit': 50 } items = session._map_request(url=path, method='GET', params=params, ret=rettype) session.add_list_items(items, content=CONTENT_FOR_TYPE.get(rettype, 'files'), end=True) @plugin.route('/albums_with_videos') def albums_with_videos(): add_items(session.albums_with_videos(), content=CONTENT_FOR_TYPE.get('albums')) @plugin.route('/category/<group>') def category(group): promoGroup = {'rising': 'RISING', 'discovery': 'DISCOVERY', 'featured': 'NEWS'}.get(group, None) items = session.get_category_items(group) totalCount = 0 for item in items: totalCount += len(item.content_types) if totalCount == 1: # Show Single content directly (Movies and TV Shows) for item in items: content_types = item.content_types for content_type in content_types: category_content(group, item.path, content_type, offset=0) return xbmcplugin.setContent(plugin.handle, 'files') if promoGroup and totalCount > 10: # Add Promotions as Folder on the Top if more than 10 Promotions available add_directory(_T(30120), plugin.url_for(featured, group=promoGroup)) add_directory('Master %s (MQA)' % _T(30107), plugin.url_for(master_albums, offset=0)) add_directory('Master %s (MQA)' % _T(30108), plugin.url_for(master_playlists, offset=0)) # Add Category Items as Folders add_items(items, content=None, end=not(promoGroup and totalCount <= 10)) if promoGroup and totalCount <= 10: # Show up to 10 Promotions as single Items promoItems = session.get_featured(promoGroup, types=['ALBUM', 'PLAYLIST', 'VIDEO']) if promoItems: add_items(promoItems, end=True) @plugin.route('/category/<group>/<path>') def category_item(group, path): items = session.get_category_items(group) path_items = [] for item in items: if item.path == path: item._force_subfolders = True path_items.append(item) add_items(path_items, content=CONTENT_FOR_TYPE.get('files')) @plugin.route('/category/<group>/<path>/<content_type>/<offset>') def category_content(group, path, content_type, offset): items = session.get_category_content(group, path, content_type, offset=int('0%s' % offset), limit=session._config.pageSize) add_items(items, content=CONTENT_FOR_TYPE.get(content_type, 'songs'), withNextPage=True) @plugin.route('/master_albums/<offset>') def master_albums(offset): items = session.master_albums(offset=int('0%s' % offset), limit=session._config.pageSize) add_items(items, content=CONTENT_FOR_TYPE.get('albums'), withNextPage=True) @plugin.route('/master_playlists/<offset>') def master_playlists(offset): items = session.master_playlists(offset=int('0%s' % offset), limit=session._config.pageSize) add_items(items, content=CONTENT_FOR_TYPE.get('albums'), withNextPage=True) @plugin.route('/track_radio/<track_id>') def track_radio(track_id): add_items(session.get_track_radio(track_id, limit=session._config.pageSize), content=CONTENT_FOR_TYPE.get('tracks')) @plugin.route('/recommended/tracks/<track_id>') def recommended_tracks(track_id): add_items(session.get_recommended_items('tracks', track_id, limit=session._config.pageSize), content=CONTENT_FOR_TYPE.get('tracks')) @plugin.route('/recommended/videos/<video_id>') def recommended_videos(video_id): add_items(session.get_recommended_items('videos', video_id, limit=session._config.pageSize), content=CONTENT_FOR_TYPE.get('videos')) @plugin.route('/featured/<group>') def featured(group): items = session.get_featured(group, types=['ALBUM', 'PLAYLIST', 'VIDEO']) add_items(items, content=CONTENT_FOR_TYPE.get('files')) @plugin.route('/featured_playlists') def featured_playlists(): items = session.get_featured() add_items(items, content=CONTENT_FOR_TYPE.get('albums')) @plugin.route('/my_music') def my_music(): add_directory(_T(30213), user_playlists) add_directory(_T(30214), plugin.url_for(favorites, content_type='artists')) add_directory(_T(30215), plugin.url_for(favorites, content_type='albums')) add_directory(_T(30216), plugin.url_for(favorites, content_type='playlists')) add_directory(_T(30217), plugin.url_for(favorites, content_type='tracks')) add_directory(_T(30218), plugin.url_for(favorites, content_type='videos'), end=True) @plugin.route('/album/<album_id>') def album_view(album_id): xbmcplugin.addSortMethod(plugin.handle, xbmcplugin.SORT_METHOD_TRACKNUM) album = session.get_album(album_id) if album and album.numberOfVideos > 0: add_directory(_T(30110), plugin.url_for(album_videos, album_id=album_id)) add_items(session.get_album_tracks(album_id), content=CONTENT_FOR_TYPE.get('tracks')) @plugin.route('/album_videos/<album_id>') def album_videos(album_id): xbmcplugin.addSortMethod(plugin.handle, xbmcplugin.SORT_METHOD_TRACKNUM) add_items(session.get_album_items(album_id, ret='videos'), content=CONTENT_FOR_TYPE.get('videos')) @plugin.route('/artist/<artist_id>') def artist_view(artist_id): if session.is_logged_in: session.user.favorites.load_all() artist = session.get_artist(artist_id) xbmcplugin.setContent(plugin.handle, 'albums') add_directory(_T(30225), plugin.url_for(artist_bio, artist_id), thumb=artist.image, fanart=artist.fanart, isFolder=False) add_directory(_T(30226), plugin.url_for(top_tracks, artist_id), thumb=artist.image, fanart=artist.fanart) add_directory(_T(30110), plugin.url_for(artist_videos, artist_id), thumb=artist.image, fanart=artist.fanart) add_directory(_T(30227), plugin.url_for(artist_radio, artist_id), thumb=artist.image, fanart=artist.fanart) add_directory(_T(30228), plugin.url_for(artist_playlists, artist_id), thumb=artist.image, fanart=artist.fanart) add_directory(_T(30229), plugin.url_for(similar_artists, artist_id), thumb=artist.image, fanart=artist.fanart) if session.is_logged_in: if session.user.favorites.isFavoriteArtist(artist_id): add_directory(_T(30220), plugin.url_for(favorites_remove, content_type='artists', item_id=artist_id), thumb=artist.image, fanart=artist.fanart, isFolder=False) else: add_directory(_T(30219), plugin.url_for(favorites_add, content_type='artists', item_id=artist_id), thumb=artist.image, fanart=artist.fanart, isFolder=False) albums = session.get_artist_albums(artist_id) + \ session.get_artist_albums_ep_singles(artist_id) + \ session.get_artist_albums_other(artist_id) add_items(albums, content=None) @plugin.route('/artist/<artist_id>/bio') def artist_bio(artist_id): artist = session.get_artist(artist_id) info = session.get_artist_info(artist_id) text = '' if info.get('summary', None): text += '%s:\n\n' % _T(30230) + info.get('summary') + '\n\n' if info.get('text', None): text += '%s:\n\n' % _T(30225) + info.get('text') if text: xbmcgui.Dialog().textviewer(artist.name, text) @plugin.route('/artist/<artist_id>/top') def top_tracks(artist_id): add_items(session.get_artist_top_tracks(artist_id, limit=session._config.pageSize), content=CONTENT_FOR_TYPE.get('tracks')) @plugin.route('/artist/<artist_id>/radio') def artist_radio(artist_id): add_items(session.get_artist_radio(artist_id, limit=session._config.pageSize), content=CONTENT_FOR_TYPE.get('tracks')) @plugin.route('/artist/<artist_id>/videos') def artist_videos(artist_id): add_items(session.get_artist_videos(artist_id), content=CONTENT_FOR_TYPE.get('videos')) @plugin.route('/artist/<artist_id>/playlists') def artist_playlists(artist_id): add_items(session.get_artist_playlists(artist_id), content=CONTENT_FOR_TYPE.get('albums')) @plugin.route('/artist/<artist_id>/similar') def similar_artists(artist_id): add_items(session.get_artist_similar(artist_id), content=CONTENT_FOR_TYPE.get('artists')) @plugin.route('/mix/<mix_id>') def mix_view(mix_id): params = { 'locale': session._config.locale, 'deviceType': 'BROWSER', 'mixId': mix_id } r = session.request('GET', 'pages/mix', params=params) if r.ok: json_obj = r.json() for row in json_obj['rows']: for module in row['modules']: try: item_type = module['type'] if item_type in HOMEPAGE_ITEM_TYPES: api_path = module['pagedList']['dataApiPath'] homepage_item(item_type, api_path) break except: pass @plugin.route('/playlist/<playlist_id>/items/<offset>') def playlist_view(playlist_id, offset): add_items(session.get_playlist_items(playlist_id, offset=int('0%s' % offset), limit=session._config.pageSize), content=CONTENT_FOR_TYPE.get('tracks'), withNextPage=True) @plugin.route('/playlist/<playlist_id>/tracks/<offset>') def playlist_tracks(playlist_id, offset): add_items(session.get_playlist_tracks(playlist_id, offset=int('0%s' % offset), limit=session._config.pageSize), content=CONTENT_FOR_TYPE.get('tracks'), withNextPage=True) @plugin.route('/playlist/<playlist_id>/albums/<offset>') def playlist_albums(playlist_id, offset): add_items(session.get_playlist_albums(playlist_id, offset=int('0%s' % offset), limit=session._config.pageSize), content=CONTENT_FOR_TYPE.get('albums'), withNextPage=True) @plugin.route('/user_playlists') def user_playlists(): items = session.user.playlists() # Find Default Playlists via title if ID is not available anymore all_ids = session.user.playlists_cache.keys() for what in ['track', 'album', 'video']: playlist_id = addon.getSetting('default_%splaylist_id' % what).decode('utf-8') playlist_title = addon.getSetting('default_%splaylist_title' % what).decode('utf-8') if playlist_id and playlist_title and playlist_id not in all_ids: for playlist_id in all_ids: if session.user.playlists_cache.get(playlist_id).get('title', '') == playlist_title: addon.setSetting('default_%splaylist_id' % what, playlist_id) addon.setSetting('default_%splaylist_title' % what, playlist_title) break add_items(items, content=CONTENT_FOR_TYPE.get('albums')) @plugin.route('/user_playlist/rename/<playlist_id>') def user_playlist_rename(playlist_id): playlist = session.get_playlist(playlist_id) ok = session.user.renamePlaylistDialog(playlist) if ok: xbmc.executebuiltin('Container.Refresh()') @plugin.route('/user_playlist/clear/<playlist_id>') def user_playlist_clear(playlist_id): dialog = xbmcgui.Dialog() playlist = session.get_playlist(playlist_id) ok = dialog.yesno(_T(30258), _T(30259).format(name=playlist.title, count=playlist.numberOfItems)) if ok: session.show_busydialog(_T(30258), playlist.name) try: session.user.remove_all_playlist_entries(playlist_id) except Exception, e: log(str(e), level=xbmc.LOGERROR) traceback.print_exc() session.hide_busydialog() xbmc.executebuiltin('Container.Refresh()') @plugin.route('/user_playlist/delete/<playlist_id>') def user_playlist_delete(playlist_id): dialog = xbmcgui.Dialog() playlist = session.get_playlist(playlist_id) ok = dialog.yesno(_T(30235), _T(30236).format(name=playlist.title, count=playlist.numberOfItems)) if ok: session.show_busydialog(_T(30235), playlist.name) try: session.user.delete_playlist(playlist_id) except Exception, e: log(str(e), level=xbmc.LOGERROR) traceback.print_exc() session.hide_busydialog() xbmc.executebuiltin('Container.Refresh()') @plugin.route('/user_playlist/add/<item_type>/<item_id>') def user_playlist_add_item(item_type, item_id): if item_type == 'playlist': srcPlaylist = session.get_playlist(item_id) if not srcPlaylist: return items = session.get_playlist_items(playlist=srcPlaylist) # Sort Items by Artist, Title sortMode = 'ALBUM' if ALBUM_PLAYLIST_TAG in srcPlaylist.description else 'LABEL' items.sort(key=lambda line: line.getSortText(mode=sortMode).upper(), reverse=False) items = ['%s' % item.id for item in items if item.available] elif item_type.startswith('album'): # Add First Track of the Album tracks = session.get_album_items(item_id) for track in tracks: if track.available: item_id = track.id break items = ['%s' % item_id] else: items = [item_id] playlist = session.user.selectPlaylistDialog(allowNew=True) if playlist: session.show_busydialog(_T(30263), playlist.name) try: session.user.add_playlist_entries(playlist=playlist, item_ids=items) except Exception, e: log(str(e), level=xbmc.LOGERROR) traceback.print_exc() session.hide_busydialog() xbmc.executebuiltin('Container.Refresh()') @plugin.route('/user_playlist/remove/<playlist_id>/<entry_no>') def user_playlist_remove_item(playlist_id, entry_no): item_no = int('0%s' % entry_no) + 1 playlist = session.get_playlist(playlist_id) ok = xbmcgui.Dialog().yesno(_T(30247).format(name=playlist.name), _T(30241).format(entry=item_no)) if ok: session.show_busydialog(_T(30264), playlist.name) try: session.user.remove_playlist_entry(playlist, entry_no=entry_no) except Exception, e: log(str(e), level=xbmc.LOGERROR) traceback.print_exc() session.hide_busydialog() xbmc.executebuiltin('Container.Refresh()') @plugin.route('/user_playlist/remove_id/<playlist_id>/<item_id>') def user_playlist_remove_id(playlist_id, item_id): playlist = session.get_playlist(playlist_id) ok = xbmcgui.Dialog().yesno(_T(30247).format(name=playlist.name), _T(30246)) if ok: session.show_busydialog(_T(30264), playlist.name) try: session.user.remove_playlist_entry(playlist, item_id=item_id) except Exception, e: log(str(e), level=xbmc.LOGERROR) traceback.print_exc() session.hide_busydialog() xbmc.executebuiltin('Container.Refresh()') @plugin.route('/user_playlist/remove_album/<playlist_id>/<item_id>') def user_playlist_remove_album(playlist_id, item_id, dialog=True): playlist = session.get_playlist(playlist_id) ok = True if dialog: ok = xbmcgui.Dialog().yesno(_T(30247).format(name=playlist.name), _T(30246)) if ok: session.show_busydialog(_T(30264), playlist.name) try: items = session.get_playlist_tracks(playlist) for item in items: if '%s' % item.album.id == '%s' % item_id: session.user.remove_playlist_entry(playlist, entry_no=item._playlist_pos) break # Remove only one Item except Exception, e: log(str(e), level=xbmc.LOGERROR) traceback.print_exc() session.hide_busydialog() xbmc.executebuiltin('Container.Refresh()') @plugin.route('/user_playlist/move/<playlist_id>/<entry_no>/<item_id>') def user_playlist_move_entry(playlist_id, entry_no, item_id): dialog = xbmcgui.Dialog() playlist = session.user.selectPlaylistDialog(headline=_T(30248), allowNew=True) if playlist and playlist.id <> playlist_id: session.show_busydialog(_T(30265), playlist.name) try: ok = session.user.add_playlist_entries(playlist=playlist, item_ids=[item_id]) if ok: ok = session.user.remove_playlist_entry(playlist_id, entry_no=entry_no) else: dialog.notification(plugin.name, _T('API Call Failed'), xbmcgui.NOTIFICATION_ERROR) except Exception, e: log(str(e), level=xbmc.LOGERROR) traceback.print_exc() session.hide_busydialog() xbmc.executebuiltin('Container.Refresh()') @plugin.route('/user_playlist_set_default/<item_type>/<playlist_id>') def user_playlist_set_default(item_type, playlist_id): item = session.get_playlist(playlist_id) if item: if item_type.lower().find('track') >= 0: addon.setSetting('default_trackplaylist_id', item.id) addon.setSetting('default_trackplaylist_title', item.title) elif item_type.lower().find('video') >= 0: addon.setSetting('default_videoplaylist_id', item.id) addon.setSetting('default_videoplaylist_title', item.title) elif item_type.lower().find('album') >= 0: addon.setSetting('default_albumplaylist_id', item.id) addon.setSetting('default_albumplaylist_title', item.title) xbmc.executebuiltin('Container.Refresh()') @plugin.route('/user_playlist_reset_default/<item_type>') def user_playlist_reset_default(item_type): if item_type.lower().find('track') >= 0: addon.setSetting('default_trackplaylist_id', '') addon.setSetting('default_trackplaylist_title', '') elif item_type.lower().find('video') >= 0: addon.setSetting('default_videoplaylist_id', '') addon.setSetting('default_videoplaylist_title', '') elif item_type.lower().find('album') >= 0: addon.setSetting('default_albumplaylist_id', '') addon.setSetting('default_albumplaylist_title', '') xbmc.executebuiltin('Container.Refresh()') @plugin.route('/user_playlist_toggle') def user_playlist_toggle(): if not session.is_logged_in: return url = xbmc.getInfoLabel( "ListItem.FilenameandPath" ) if not _addon_id in url: return if 'play_track/' in url: item_type = 'track' userpl_id = addon.getSetting('default_trackplaylist_id').decode('utf-8') userpl_name = addon.getSetting('default_trackplaylist_title').decode('utf-8') item_id = url.split('play_track/')[1] item_id = item_id.split('/')[0] item = session.get_track(item_id) elif 'play_video/' in url: item_type = 'video' userpl_id = addon.getSetting('default_videoplaylist_id').decode('utf-8') userpl_name = addon.getSetting('default_videoplaylist_title').decode('utf-8') item_id = url.split('play_video/')[1] item_id = item_id.split('/')[0] item = session.get_video(item_id) elif 'album/' in url: item_type = 'album' userpl_id = addon.getSetting('default_albumplaylist_id').decode('utf-8') userpl_name = addon.getSetting('default_albumplaylist_title').decode('utf-8') item_id = url.split('album/')[1] item_id = int('0%s' % item_id.split('/')[0]) item = session.get_album(item_id) if userpl_id: if item._userplaylists and userpl_id in item._userplaylists: user_playlist_remove_album(userpl_id, item.id, dialog=False) return tracks = session.get_album_items(item.id) for track in tracks: if track.available: item.id = track.id # Add First Track of Album break else: return try: if not userpl_id: # Dialog Mode if default Playlist not set user_playlist_add_item(item_type, '%s' % item_id) return if item._userplaylists and userpl_id in item._userplaylists: session.show_busydialog(_T(30264), userpl_name) session.user.remove_playlist_entry(playlist=userpl_id, item_id=item.id) else: session.show_busydialog(_T(30263), userpl_name) session.user.add_playlist_entries(playlist=userpl_id, item_ids=['%s' % item.id]) except Exception, e: log(str(e), level=xbmc.LOGERROR) traceback.print_exc() session.hide_busydialog() xbmc.executebuiltin('Container.Refresh()') @plugin.route('/favorites/<content_type>') def favorites(content_type): items = session.user.favorites.get(content_type, limit=100 if content_type == 'videos' else 9999) if content_type in ['playlists', 'artists']: items.sort(key=lambda line: line.name, reverse=False) else: items.sort(key=lambda line: '%s - %s' % (line.artist.name, line.title), reverse=False) add_items(items, content=CONTENT_FOR_TYPE.get(content_type, 'songs')) @plugin.route('/favorites/add/<content_type>/<item_id>') def favorites_add(content_type, item_id): ok = session.user.favorites.add(content_type, item_id) if ok: xbmcgui.Dialog().notification(heading=plugin.name, message=_T(30231).format(what=_T(content_type)), icon=xbmcgui.NOTIFICATION_INFO) xbmc.executebuiltin('Container.Refresh()') @plugin.route('/favorites/remove/<content_type>/<item_id>') def favorites_remove(content_type, item_id): ok = session.user.favorites.remove(content_type, item_id) if ok: xbmcgui.Dialog().notification(heading=plugin.name, message=_T(30232).format(what=_T(content_type)), icon=xbmcgui.NOTIFICATION_INFO) xbmc.executebuiltin('Container.Refresh()') @plugin.route('/lock_artist/<artist_id>') def lock_artist(artist_id): session.user.favorites.setLockedArtist(artist_id, True) xbmc.executebuiltin('Container.Refresh()') @plugin.route('/unlock_artist/<artist_id>') def unlock_artist(artist_id): session.user.favorites.setLockedArtist(artist_id, False) xbmc.executebuiltin('Container.Refresh()') @plugin.route('/cache_reset') def cache_reset(): if not session.is_logged_in: return session.user.delete_cache() session.user.favorites.delete_cache() @plugin.route('/cache_reset_confirmed') def cache_reset_confirmed(): if xbmcgui.Dialog().yesno(_T(30507), _T(30508)): cache_reset() @plugin.route('/cache_reload') def cache_reload(): if not session.is_logged_in: return session.user.favorites.load_all(force_reload=True) session.user.load_cache() session.user.playlists() @plugin.route('/favorite_toggle') def favorite_toggle(): if not session.is_logged_in: return path = xbmc.getInfoLabel('Container.FolderPath').decode('utf-8') url = xbmc.getInfoLabel( "ListItem.FileNameAndPath" ).decode('utf-8') if not _addon_id in url or '/favorites/' in path: return try: isFavorite = False content_type = None if 'artist/' in url: item_id = url.split('artist/')[1] item_id = int('0%s' % item_id.split('/')[0]) if not '/' in item_id: content_type = 'artists' isFavorite = session.user.favorites.isFavoriteArtist(item_id) elif 'album/' in url: item_id = url.split('album/')[1] item_id = item_id.split('/')[0] if not '/' in item_id: content_type = 'albums' isFavorite = session.user.favorites.isFavoriteAlbum(item_id) elif 'play_track/' in url: item_id = url.split('play_track/')[1] item_id = item_id.split('/')[0] # Remove album_id behind the track_id if not '/' in item_id: content_type = 'tracks' isFavorite = session.user.favorites.isFavoriteTrack(item_id) elif 'playlist/' in url: item_id = url.split('playlist/')[1] item_id = item_id.split('/')[0] # Remove offset behind playlist_id if not '/' in item_id: content_type = 'playlists' isFavorite = session.user.favorites.isFavoritePlaylist(item_id) elif 'play_video/' in url: item_id = url.split('play_video/')[1] if not '/' in item_id: content_type = 'videos' isFavorite = session.user.favorites.isFavoriteVideo(item_id) if content_type == None: return if isFavorite: favorites_remove(content_type, item_id) else: favorites_add(content_type, item_id) except: pass @plugin.route('/search') def search(): addon.setSetting('last_search_field', '') addon.setSetting('last_search_text', '') add_directory(_T(30106), plugin.url_for(search_type, field='artist')) add_directory(_T(30107), plugin.url_for(search_type, field='album')) add_directory(_T(30108), plugin.url_for(search_type, field='playlist')) add_directory(_T(30109), plugin.url_for(search_type, field='track')) add_directory(_T(30110), plugin.url_for(search_type, field='video'), end=True) @plugin.route('/search_type/<field>') def search_type(field): last_field = addon.getSetting('last_search_field').decode('utf-8') search_text = addon.getSetting('last_search_text').decode('utf-8') if last_field <> field or not search_text: addon.setSetting('last_search_field', field) keyboard = xbmc.Keyboard('', _T(30206)) keyboard.doModal() if keyboard.isConfirmed(): search_text = keyboard.getText() else: search_text = '' addon.setSetting('last_search_text', search_text) if search_text: searchresults = session.search(field, search_text) add_items(searchresults.artists, content=CONTENT_FOR_TYPE.get('files'), end=False) add_items(searchresults.albums, end=False) add_items(searchresults.playlists, end=False) add_items(searchresults.tracks, end=False) add_items(searchresults.videos, end=True) else: #xbmcplugin.setContent(plugin.handle, content='files') xbmcplugin.endOfDirectory(plugin.handle, succeeded=False, updateListing=False) @plugin.route('/login') def login(): username = addon.getSetting('username') password = addon.getSetting('password') subscription_type = [SubscriptionType.hifi, SubscriptionType.premium][int('0' + addon.getSetting('subscription_type'))] if not username or not password: # Ask for username/password dialog = xbmcgui.Dialog() username = dialog.input(_T(30008), username) if not username: return password = dialog.input(_T(30009), option=xbmcgui.ALPHANUM_HIDE_INPUT) if not password: return selected = dialog.select(_T(30010), [SubscriptionType.hifi, SubscriptionType.premium]) if selected < 0: return subscription_type = [SubscriptionType.hifi, SubscriptionType.premium][selected] ok = session.login(username, password, subscription_type) if ok and (not addon.getSetting('username') or not addon.getSetting('password')): # Ask about remembering username/password dialog = xbmcgui.Dialog() if dialog.yesno(plugin.name, _T(30209)): addon.setSetting('username', username) addon.setSetting('password', password) else: addon.setSetting('password', '') if not ok: xbmcgui.Dialog().notification(plugin.name, _T(30253) , icon=xbmcgui.NOTIFICATION_ERROR) xbmc.executebuiltin('Container.Refresh()') @plugin.route('/logout') def logout(): session.logout() xbmc.executebuiltin('Container.Refresh()') @plugin.route('/play_track/<track_id>/<album_id>') def play_track(track_id, album_id): media_url = session.get_media_url(track_id, album_id=album_id) log("Playing: %s" % media_url) disableInputstreamAddon = False if not media_url.startswith('http://') and not media_url.startswith('https://') and \ not 'app=' in media_url.lower() and not 'playpath=' in media_url.lower(): # Rebuild RTMP URL if KODI_VERSION >= (17, 0): media_url = 'rtmp://%s' % media_url disableInputstreamAddon = True else: host, tail = media_url.split('/', 1) app, playpath = tail.split('/mp4:', 1) media_url = 'rtmp://%s app=%s playpath=mp4:%s' % (host, app, playpath) li = ListItem(path=media_url) if disableInputstreamAddon: # Krypton can play RTMP Audio Streams without inputstream.rtmp Addon li.setProperty('inputstreamaddon', '') mimetype = 'audio/flac' if session._config.quality == Quality.lossless and session.is_logged_in else 'audio/mpeg' li.setProperty('mimetype', mimetype) xbmcplugin.setResolvedUrl(plugin.handle, True, li) @plugin.route('/play_track_cut/<track_id>/<cut_id>/<album_id>') def play_track_cut(track_id, cut_id, album_id): media_url = session.get_media_url(track_id, cut_id=cut_id, album_id=album_id) log("Playing Cut %s: %s" % (cut_id, media_url)) disableInputstreamAddon = False if not media_url.startswith('http://') and not media_url.startswith('https://') and \ not 'app=' in media_url.lower() and not 'playpath=' in media_url.lower(): # Rebuild RTMP URL if KODI_VERSION >= (17, 0): media_url = 'rtmp://%s' % media_url disableInputstreamAddon = True else: host, tail = media_url.split('/', 1) app, playpath = tail.split('/mp4:', 1) media_url = 'rtmp://%s app=%s playpath=mp4:%s' % (host, app, playpath) li = ListItem(path=media_url) if disableInputstreamAddon: # Krypton can play RTMP Audio Streams without inputstream.rtmp Addon li.setProperty('inputstreamaddon', '') mimetype = 'audio/flac' if session._config.quality == Quality.lossless and session.is_logged_in else 'audio/mpeg' li.setProperty('mimetype', mimetype) xbmcplugin.setResolvedUrl(plugin.handle, True, li) @plugin.route('/play_video/<video_id>') def play_video(video_id): media = session.get_video_url(video_id) if media: log("Playing: %s" % media.url) li = ListItem(path=media.url) li.setProperty('mimetype', 'video/mp4') xbmcplugin.setResolvedUrl(plugin.handle, True, li) @plugin.route('/stream_locked') def stream_locked(): xbmcgui.Dialog().notification(heading=plugin.name, message=_T(30242), icon=xbmcgui.NOTIFICATION_INFO) if __name__ == '__main__': try: # Remove last slash for folder paths newargv = sys.argv newargv[0] = newargv[0].rstrip('/') plugin.run(argv=newargv) except HTTPError as e: r = e.response if r.status_code in [401, 403]: msg = _T(30210) else: msg = r.reason try: msg = r.json().get('userMessage') except: pass xbmcgui.Dialog().notification('%s Error %s' % (plugin.name, r.status_code), msg, xbmcgui.NOTIFICATION_ERROR) traceback.print_exc()