From 1309b5e455b480a82f4f3582523e0cacd45829c3 Mon Sep 17 00:00:00 2001 From: Leonardo Cervo Date: Tue, 24 Mar 2015 18:25:07 -0300 Subject: [PATCH] Youtube support Play songs in Youtube --- GoogleMusicActions.py | 117 ++++++++++++++++++++++++++++----------- GoogleMusicNavigation.py | 36 +++++++----- addon.xml | 1 + utils.py | 21 +++++-- 4 files changed, 124 insertions(+), 51 deletions(-) diff --git a/GoogleMusicActions.py b/GoogleMusicActions.py index f28ea3c..19f4893 100644 --- a/GoogleMusicActions.py +++ b/GoogleMusicActions.py @@ -1,4 +1,4 @@ -import os, xbmc, utils +import os, xbmc, xbmcgui, utils import GoogleMusicApi class GoogleMusicActions(): @@ -11,6 +11,9 @@ def __init__(self): def executeAction(self, action, params): if (action == "play_all"): self.playAll(params) + elif (action == "play_all_yt"): + titles = [song[23] for song in self._getSongs(params)] + self.playYoutube(titles) elif (action == "update_playlist"): self.api.getPlaylistSongs(params["playlist_id"], True) elif (action == "update_playlists"): @@ -32,12 +35,11 @@ def executeAction(self, action, params): elif (action == "del_from_playlist"): self.api.delFromPlaylist(params["playlist_id"], params["song_id"]) elif (action == "update_library"): - try: - self.api.clearCache() - xbmc.executebuiltin("XBMC.RunPlugin(%s)" % utils.addon_url) + try: self.api.clearCache() except Exception as e: utils.log(repr(e)) self.notify(self.lang(30106)) + xbmc.executebuiltin("XBMC.RunPlugin(%s)" % utils.addon_url) elif (action == "export_library"): if utils.addon.getSetting('export_path'): self.exportLibrary(utils.addon.getSetting('export_path')) @@ -52,11 +54,12 @@ def executeAction(self, action, params): self.playAll({'radio_id': self.api.startRadio(keyboard.getText(), params["song_id"])}) xbmc.executebuiltin("ActivateWindow(10500)") #xbmc.executebuiltin("XBMC.RunPlugin(%s?path=station&id=%s)" % (sys.argv[0],radio_id)) - elif (action == "youtube"): - try: - xbmc.executebuiltin("ActivateWindow(10025,plugin://plugin.video.youtube/kodion/search/query/?q=%s)" % params['title']) - except: - self.notify(self.lang(30109)) + elif (action == "search_yt"): + xbmc.executebuiltin("ActivateWindow(10025,plugin://plugin.video.youtube/kodion/search/query/?q=%s)" % params['title']) + elif (action == "play_yt"): + self.playYoutube([params.get('title')]) + elif (action == "search"): + xbmc.executebuiltin("ActivateWindow(10501,%s/?path=search_result&query=%s)" % (utils.addon_url, params.get('filter_criteria'))) else: utils.log("Invalid action: " + action) @@ -64,26 +67,7 @@ def notify(self, text): xbmc.executebuiltin("XBMC.Notification(%s,%s,5000,%s)" % (utils.plugin, text, self.icon)) def playAll(self, params={}): - get = params.get - - if get('playlist_id'): - utils.log("Loading playlist: " + get('playlist_id')) - songs = self.api.getPlaylistSongs(get('playlist_id')) - elif get('album_id'): - utils.log("Loading album: " + get('album_id')) - songs = self.api.getAlbum(get('album_id')) - elif get('share_token'): - import urllib - utils.log("Loading shared playlist: " + get('share_token')) - songs = self.api.getSharedPlaylist(urllib.unquote_plus(get('share_token'))) - elif get('artist_id'): - utils.log("Loading artist top tracks: " + get('artist_id')) - songs = self.api.getArtist(get('artist_id')) - elif get('radio_id'): - utils.log("Loading radio: " + get('radio_id')) - songs = self.api.getStationTracks(get('radio_id')) - else: - songs = self.api.getFilterSongs(get('filter_type'), get('filter_criteria'), albums='') + songs = self._getSongs(params) player = xbmc.Player() if (player.isPlaying()): @@ -100,8 +84,28 @@ def playAll(self, params={}): xbmc.executebuiltin('playlist.playoffset(music , 0)') + def playYoutube(self, titles): + #print repr(titles) + + player = xbmc.Player() + if (player.isPlaying()): + player.stop() + + playlist = xbmc.PlayList(xbmc.PLAYLIST_VIDEO) + playlist.clear() + + dp = None + if len(titles) > 1: + dp = xbmcgui.DialogProgress(); + dp.create('Fetching video IDs', str(len(titles))+' '+self.lang(30213).lower(), self.lang(30404)) + + ytaddonurl = "plugin://plugin.video.youtube/play/?video_id=%s" + for videoid, title in self._getVideoIDs(titles, dp): + playlist.add(ytaddonurl % videoid, xbmcgui.ListItem(title)) + + xbmc.executebuiltin('playlist.playoffset(video , 0)') + def addToPlaylist (self, song_id): - import xbmcgui playlists = self.api.getPlaylistsByType('user') plist = [pl_name for pl_id, pl_name in playlists] selected = xbmcgui.Dialog().select(self.lang(30401) , plist) @@ -125,7 +129,6 @@ def addFavourite(self, name, params): print line, def exportLibrary(self, path): - import xbmcgui songs = self.api.getPlaylistSongs('all_songs') dp = xbmcgui.DialogProgress(); dp.create(self.lang(30403), str(len(songs))+' '+self.lang(30213).lower(), self.lang(30404)) @@ -155,5 +158,53 @@ def exportLibrary(self, path): def _sanitizePath(self, name): name = "".join(i for i in name if i not in "\/:*?<>|,;$%\"\'.`") if len(name) > 50: name = name[:50] - return unicode(name.decode('utf8')).strip() - #return ("".join([i if i.isalnum() else " " for i in name.strip()])).strip() \ No newline at end of file + return utils.tryEncode(name).strip() + + def _getSongs(self, params): + get = params.get + + if get('playlist_id'): + utils.log("Loading playlist: " + get('playlist_id')) + songs = self.api.getPlaylistSongs(get('playlist_id')) + elif get('album_id'): + utils.log("Loading album: " + get('album_id')) + songs = self.api.getAlbum(get('album_id')) + elif get('share_token'): + import urllib + utils.log("Loading shared playlist: " + get('share_token')) + songs = self.api.getSharedPlaylist(urllib.unquote_plus(get('share_token'))) + elif get('artist_id'): + utils.log("Loading artist top tracks: " + get('artist_id')) + songs = self.api.getArtist(get('artist_id')) + elif get('radio_id'): + utils.log("Loading radio: " + get('radio_id')) + songs = self.api.getStationTracks(get('radio_id')) + else: + songs = self.api.getFilterSongs(get('filter_type'), get('filter_criteria'), albums='') + + return songs + + def _getVideoIDs(self, titles, progress_dialog=None): + import urllib, urllib2, re + + videoids = [] + opener = urllib2.build_opener() + userAgent = "Mozilla/5.0 (Windows NT 6.1; rv:30.0) Gecko/20100101 Firefox/30.0" + opener.addheaders = [('User-Agent', userAgent)] + url = "http://gdata.youtube.com/feeds/api/videos?q=%s+-interview+-cover+-remix+-album&category=Music&max-results=1&start-index=1&orderby=relevance&time=all_time&v=2" + + count = 0 + for title in titles: + if progress_dialog: + if progress_dialog.iscanceled(): + progress_dialog.close() + return videoids + count = count +1 + progress_dialog.update(int(count * 100 / len(titles))) + content = opener.open(url % urllib.quote_plus(utils.tryEncode(title.lower()))).read() + match=re.compile('(.+?)', re.DOTALL).findall(content) + if match: + #print match[0]+' '+repr(title) + videoids.append([match[0], title]) + + return videoids diff --git a/GoogleMusicNavigation.py b/GoogleMusicNavigation.py index a440e34..dff5eca 100644 --- a/GoogleMusicNavigation.py +++ b/GoogleMusicNavigation.py @@ -106,7 +106,7 @@ def getMenuItems(self, items): elif 'playlist_type' in params: cm = self.getPlaylistsContextMenuItems(menu_item['title'], params['playlist_type']) elif params['path'] == 'library': - cm.append(('Export', "XBMC.RunPlugin(%s?action=export_library)" % utils.addon_url)) + cm.append((self.lang(30314), "XBMC.RunPlugin(%s?action=export_library)" % utils.addon_url)) cm.append((self.lang(30305), "XBMC.RunPlugin(%s?action=update_library)" % utils.addon_url)) cm.append((self.lang(30306), "XBMC.RunPlugin(%s?action=add_favourite&path=library&title=%s)" % (utils.addon_url,menu_item['title']))) elif 'criteria' in params: @@ -145,7 +145,8 @@ def getPlaylists(self, playlist_type): if playlist_type == 'radio': icon = utils.addon.getAddonInfo('icon') for rs in self.api.getStations(): - append(addFolder(rs['name'], {'path':"station",'id':rs['id']}, album_art_url=rs.get('imageUrl', icon))) + cm = self.getRadioContextMenuItems(rs['name'], rs['id']) + append(addFolder(rs['name'], {'path':"station",'id':rs['id']}, cm, album_art_url=rs.get('imageUrl', icon))) else: for pl_id, pl_name in self.api.getPlaylistsByType(playlist_type): cm = self.getPlayAllContextMenuItems(pl_name, pl_id) @@ -204,29 +205,41 @@ def createItem(self, song, song_type): def getSongContextMenu(self, song_id, title, song_type): cm = [] + if song_id.startswith('T'): + cm.append((self.lang(30309), "XBMC.RunPlugin(%s?action=add_library&song_id=%s)" % (utils.addon_url,song_id))) if song_type == 'library': cm.append((self.lang(30307),"XBMC.RunPlugin(%s?action=add_playlist&song_id=%s)" % (utils.addon_url,song_id))) elif song_type.startswith('playlist'): cm.append((self.lang(30308), "XBMC.RunPlugin(%s?action=del_from_playlist&song_id=%s&playlist_id=%s)" % (utils.addon_url, song_id, song_type[8:]))) - if song_id.startswith('T'): - cm.append((self.lang(30309), "XBMC.RunPlugin(%s?action=add_library&song_id=%s)" % (utils.addon_url,song_id))) + cm.append((self.lang(30313), "XBMC.RunPlugin(%s?action=play_yt&title=%s)" % (utils.addon_url,title))) + cm.append((self.lang(30311), "XBMC.RunPlugin(%s?action=search_yt&title=%s)" % (utils.addon_url,title))) cm.append((self.lang(30310), "XBMC.RunPlugin(%s?action=start_radio&song_id=%s)" % (utils.addon_url,song_id))) - cm.append((self.lang(30311), "XBMC.RunPlugin(%s?action=youtube&title=%s)" % (utils.addon_url,title))) + return cm + + def getRadioContextMenuItems(self, name, radio_id): + cm = [] + cm.append((self.lang(30301), "XBMC.RunPlugin(%s?action=play_all&radio_id=%s)" % (utils.addon_url, radio_id))) + cm.append((self.lang(30302), "XBMC.RunPlugin(%s?action=play_all&radio_id=%s&shuffle=true)" % (utils.addon_url, radio_id))) + cm.append((self.lang(30312), "XBMC.RunPlugin(%s?action=play_all_yt&radio_id=%s)" % (utils.addon_url, radio_id))) + cm.append((self.lang(30306), "XBMC.RunPlugin(%s?action=add_favourite&path=playlist&radio_id=%s&title=%s)" % (utils.addon_url, radio_id, name))) return cm def getPlayAllContextMenuItems(self, name, playlist): cm = [] cm.append((self.lang(30301), "XBMC.RunPlugin(%s?action=play_all&playlist_id=%s)" % (utils.addon_url, playlist))) cm.append((self.lang(30302), "XBMC.RunPlugin(%s?action=play_all&playlist_id=%s&shuffle=true)" % (utils.addon_url, playlist))) + cm.append((self.lang(30312), "XBMC.RunPlugin(%s?action=play_all_yt&playlist_id=%s)" % (utils.addon_url, playlist))) cm.append((self.lang(30303), "XBMC.RunPlugin(%s?action=update_playlist&playlist_id=%s)" % (utils.addon_url, playlist))) cm.append((self.lang(30306), "XBMC.RunPlugin(%s?action=add_favourite&path=playlist&playlist_id=%s&title=%s)" % (utils.addon_url, playlist, name))) return cm def getFilterContextMenuItems(self, filter_type, filter_criteria): cm = [] + cm.append((self.lang(30306), "XBMC.RunPlugin(%s?action=add_favourite&path=%s&name=%s&title=%s)" % (utils.addon_url, filter_type, filter_criteria, filter_criteria))) cm.append((self.lang(30301), "XBMC.RunPlugin(%s?action=play_all&filter_type=%s&filter_criteria=%s)" % (utils.addon_url, filter_type, filter_criteria))) cm.append((self.lang(30302), "XBMC.RunPlugin(%s?action=play_all&filter_type=%s&filter_criteria=%s&shuffle=true)" % (utils.addon_url, filter_type, filter_criteria))) - cm.append((self.lang(30306), "XBMC.RunPlugin(%s?action=add_favourite&path=%s&name=%s&title=%s)" % (utils.addon_url, filter_type, filter_criteria, filter_criteria))) + cm.append((self.lang(30312), "XBMC.RunPlugin(%s?action=play_all_yt&filter_type=%s&filter_criteria=%s)" % (utils.addon_url, filter_type, filter_criteria))) + cm.append((self.lang(30208), "XBMC.RunPlugin(%s?action=search&filter_type=%s&filter_criteria=%s)" % (utils.addon_url, filter_type, filter_criteria))) return cm def getPlaylistsContextMenuItems(self, name, playlist_type): @@ -242,7 +255,7 @@ def listAlbumsResults(): listItems.append(self.createFolder('[COLOR orange]*** '+self.lang(30206)+' ***[/COLOR]',{'path':'none'})) cm = [] for album in result['albums']: - params = {'path':"search_result",'query':self.tryEncode(album[0])} + params = {'path':"search_result",'query':utils.tryEncode(album[0])} if len(album) > 3: cm = [(self.lang(30301), "XBMC.RunPlugin(%s?action=play_all&album_id=%s)" % (utils.addon_url, album[3]))] params['albumid'] = album[3] @@ -255,7 +268,7 @@ def listAlbumsResults(): listItems.append(self.createFolder('[COLOR orange]*** '+self.lang(30205)+' ***[/COLOR]',{'path':'none'})) cm = [] for artist in result['artists']: - params = {'path':"search_result",'query':self.tryEncode(artist[0])} + params = {'path':"search_result",'query':utils.tryEncode(artist[0])} if len(artist) > 2: cm = [(self.lang(30301), "XBMC.RunPlugin(%s?action=play_all&artist_id=%s)" % (utils.addon_url, artist[2]))] params['artistid'] = artist[2] @@ -275,10 +288,5 @@ def listAlbumsResults(): listItems.extend(self.getSearch(unquote_plus(query['query']))) return listItems - def tryEncode(self, text, encoding='utf8'): - try: - return text.encode(encoding) - except: - utils.log(" ENCODING FAIL!!!@ "+encoding) - return repr(text) + diff --git a/addon.xml b/addon.xml index 4f33ed8..1041e8f 100644 --- a/addon.xml +++ b/addon.xml @@ -6,6 +6,7 @@ + diff --git a/utils.py b/utils.py index 48145dd..a332e64 100644 --- a/utils.py +++ b/utils.py @@ -22,8 +22,9 @@ def paramsToDict(parameters): paramPairs = parameters[1:].split('&') for paramsPair in paramPairs: paramSplits = paramsPair.split('=') - if len(paramSplits) == 2: + try: paramDict[paramSplits[0]] = paramSplits[1] + except: pass return paramDict def createItem(title, thumb): @@ -40,11 +41,23 @@ def setResolvedUrl(listItem): xbmcplugin.setResolvedUrl(handle=handle, succeeded=True, listitem=listItem) def setDirectory(listItems, content, sortMethods): - if handle < 0: return + #if handle < 0: return xbmcplugin.addDirectoryItems(handle, listItems) - xbmcplugin.setContent(handle, content) + if handle > 0: + xbmcplugin.setContent(handle, content) for sorts in sortMethods: xbmcplugin.addSortMethod(int(sys.argv[1]), sorts) - xbmcplugin.endOfDirectory(handle, succeeded=True) \ No newline at end of file + xbmcplugin.endOfDirectory(handle, succeeded=True) + +def tryEncode(text, encoding='utf8'): + try: + text = text.decode(encoding) + return unicode(text) + except: pass + try: + return text.encode(encoding) + except: + log(" ENCODING FAIL!!! "+encoding+" "+repr(text)) + return repr(text) \ No newline at end of file