def playYoutubeVid(id, meta=None, poster=None): if meta is None: #Create an empty meta, so we can fill it with the information grabbed from youtube meta = {} if 'title' not in meta: meta['title'] = v.title #Store the youtube title in the meta if poster is None: poster = 'Default.png' #YDStreamExtractor.disableDASHVideo(True) #Kodi (XBMC) only plays the video for DASH streams, so you don't want these normally. Of course these are the only 1080p streams on YouTube try: #url = id #a youtube ID will work as well and of course you could pass the url of another site vid = YDStreamExtractor.getVideoInfo( id, quality=1) #quality is 0=SD, 1=720p, 2=1080p and is a maximum stream_url = vid.streamURL() #This is what Kodi (XBMC) will play except: dev.log('Failed to get a valid stream_url!') return False #Failed to grab a video title #xbmc.Player().play(v.getbest().url) #Play this video liz = xbmcgui.ListItem(meta['title'], iconImage=poster, thumbnailImage=poster) liz.setInfo(type="Video", infoLabels=meta) liz.setPath(stream_url) return xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, liz)
def delete_playlist(id, type=''): #Grab the settings from this playlist settings = m_xml.xml_get_elem('playlists/playlist', 'playlist', {'id': id}, type=type) #Grab the xml settings for this playlist if settings is None: dev.log('deletePlaylist: Could not find playlist '+id+' in the '+dev.typeXml(type)+' file', True) return False else: i = xbmcgui.Dialog().yesno("Delete Playlist", "Are you sure you want to delete this playlist?") if i == 0: editPlaylist(id, type=type) else: if m_xml.xml_remove_playlist(id, type=type) is True: #Remove the episodenr xml file to file = os.path.join(vars.settingsPath+dev.typeEpnr(type), id+'.xml' ) if os.path.isfile(file): success = os.remove(file) #Remove the episodenr xml file xbmcgui.Dialog().ok('Removed Playlist', 'Succesfully removed playlist '+id) i = xbmcgui.Dialog().yesno('Delete from library', 'Do you also want to delete the videos from your library?') if i != 0: #Check in which folder the show resides folder = settings.find('overwritefolder').text if folder is None or folder == '': folder = dev.legal_filename(settings.find('title').text) #Overwrite folder is not set in settings.xml, so set the folder to the title of the show else: folder = dev.legal_filename(folder) movieLibrary = vars.tv_folder #Use the directory from the addon settings if type == 'musicvideo': movieLibrary = vars.musicvideo_folder elif type == 'movies': movieLibrary = vars.movies_folder dir = os.path.join(movieLibrary, folder) #Set the folder to the maindir/dir success = shutil.rmtree(dir, ignore_errors=True) #Remove the directory xbmcgui.Dialog().ok('Removed from library', 'Deleted the videos from your library (You should clean your library, otherwise they will still show in your library)')
def refresh_artwork(id, type=''): response = ytube.yt_get_playlist_info(id) res = response['items'][0]['snippet'] thumbnail = dev.best_thumbnail(res) #Grab the channel information response = ytube.yt_get_channel_info(res['channelId']) snippet = response['items'][0]['snippet'] brand = response['items'][0]['brandingSettings'] #Check if we can do a better thumbnail better_thumbnail = dev.best_thumbnail(snippet) if(better_thumbnail != False): thumbnail = better_thumbnail if thumbnail == False: thumbnail = '' dev.log('The thumbnail now: '+thumbnail) bannerTv = brand['image']['bannerImageUrl'] if 'bannerTvImageUrl' in brand['image']: bannerTv = brand['image']['bannerTvImageUrl'] m_xml.xml_update_playlist_setting(id, 'thumb', thumbnail, type=type) #Save the new setting m_xml.xml_update_playlist_setting(id, 'banner', brand['image']['bannerImageUrl'], type=type) #Save the new setting m_xml.xml_update_playlist_setting(id, 'fanart', bannerTv, type=type) #Save the new setting settings = m_xml.xml_get_elem('playlists/playlist', 'playlist', {'id': id}, type=type) #Grab the xml settings for this playlist id = vars.args['id'][0] update_playlist(id, type=type)
def playlist_add_episode(playlist, season, id, season_tag='season', type=''): dev.log('playlist_add_episode(' + season + ',' + id + ', type=' + type + ')') #Check if this playlist isnt in the xml file yet #if xml_get_elem('season', 'episode', {'id' : id}, playlist=playlist) is None: #Build the playlist #doc = playlist_xml_get(playlist) #s = doc.find("season[@number='"+season+"']") s = xml_get_elem(season_tag, season_tag, {'number': season}, playlist=playlist, type=type) if s is None: playlist_add_season(playlist, season, type=type) #doc = playlist_xml_get(playlist) #s = doc.find("season[@number='"+season+"']") s = xml_get_elem(season_tag, season_tag, {'number': season}, playlist=playlist, type=type) #doc = playlist_xml_get(playlist) global playlistdocument attr = {'id': id} elem = Element('episode', attr) s.insert(0, elem) root = playlistdocument.getroot() write_xml(root, dir=dev.typeEpnr(type), output=playlist + '.xml') dev.log('Added the episode ' + id + ' to ' + season_tag + ': ' + season + ' in ' + dev.typeEpnr(type) + '/' + playlist + '.xml')
def number_of_episodes(playlist, season, season_tag='season', type=''): s = xml_get_elem(season_tag, season_tag, {'number': season}, playlist=playlist, type=type) if s == None: dev.log('number_of_episodes('+type+'): Could not find '+season_tag+' '+season+' in playlist '+playlist) return None dev.log('number_of_episodes('+type+'): Found '+str(len(s))+' episodes in '+season_tag+' '+season) return len(s)
def hms_to_sec(hms): hms = hms.strip(' \t\n\r') #dev.log('hms_to_sec('+hms+')') m = re.search(r'(?i)((\d+)h)?((\d+)m)?((\d+)s)?', hms) if m: if m.group(2) is None and m.group(4) is None and m.group(6) == None: #if hms.count(':') == 2: m = re.search(r'(?i)((\d)+:)?((\d+))?(:(\d)+)?', hms) #else: #m = re.search(r'(?i)((\d)+:)?((\d+))?(:(\d)+)?', hms) hours = m.group(2) minutes = m.group(4) seconds = m.group(6) #dev.log(str(hours)+', '+str(minutes)+', '+str(seconds)) if seconds is None: seconds = '0' #Seconds was not set in the setting, so we start with 0 seconds seconds = int(seconds) #dev.log('Seconds is '+str(seconds)) if minutes is not None: #If minutes are specified #dev.log('minutes is '+minutes) sm = int(minutes) * 60 seconds = seconds + sm if hours is not None: #dev.log('hours is '+hours) sh = int(hours) * 60 * 60 seconds = seconds + sh return seconds else: dev.log('Could not extract seconds from hms format: '+hms, True) return None
def write_strm(name, fold, videoid, show=None, season=None, episode=None, startpoint = None, endpoint = None, artist='', album='', song='', year='', type=''): #dev.log('strm('+name+', '+fold+', '+videoid+')') movieLibrary = vars.tv_folder #The path we should save in is the vars.tv_folder setting from the addon settings if type=='musicvideo': movieLibrary = vars.musicvideo_folder sysname = urllib.quote_plus(videoid) #Escape strings in the videoid if needed enc_name = dev.legal_filename(name) #Encode the filename to a legal filename if vars.__settings__.getSetting("strm_link") == "Youtube Library": if type == 'musicvideo': content = 'plugin://plugin.video.youtubelibrary/?mode=playmusicvideo' if startpoint != None: content += '&startpoint='+startpoint if endpoint != None: content += '&endpoint='+endpoint content += '&id=%s&artist=%s&song=%s&album=%s&year=%s&filename=%s' % (sysname, artist, song, album, year, enc_name) #Set the content of the strm file with a link back to this addon for playing the video else: content = 'plugin://plugin.video.youtubelibrary/?mode=play&id=%s&show=%s&season=%s&episode=%s&filename=%s' % (sysname, show, season, episode, enc_name) #Set the content of the strm file with a link back to this addon for playing the video else: content = vars.KODI_ADDONLINK+'%s' % ( sysname) #Set the content of the strm file with a link to the official Kodi Youtube Addon xbmcvfs.mkdir(movieLibrary) #Create the maindirectory if it does not exists yet folder = os.path.join(movieLibrary, fold) #Set the folder to the maindir/dir xbmcvfs.mkdir(folder) #Create this subfolder if it does not exist yet stream = os.path.join(folder, enc_name + '.strm') #Set the file to maindir/name/name.strm file = xbmcvfs.File(stream, 'w') #Open / create this file for writing file.write(str(content.encode('UTF-8'))) #Write the content in the file file.close() #Close the file dev.log('write_strm: Written strm file: '+fold+'/'+enc_name+'.strm') return enc_name
def playYoutubeVid(id, meta=None, poster=None): ''' from resources.lib import pafy pafy.set_api_key(vars.API_KEY) #Resolve the youtube video url for ourselves v = pafy.new(id) stream_url = v.getbest().url ''' if meta is None: #Create an empty meta, so we can fill it with the information grabbed from youtube meta = {} if 'title' not in meta: meta['title'] = v.title #Store the youtube title in the meta if poster is None: poster = 'Default.png' #YDStreamExtractor.disableDASHVideo(True) #Kodi (XBMC) only plays the video for DASH streams, so you don't want these normally. Of course these are the only 1080p streams on YouTube try: #url = id #a youtube ID will work as well and of course you could pass the url of another site vid = YDStreamExtractor.getVideoInfo(id,quality=1) #quality is 0=SD, 1=720p, 2=1080p and is a maximum stream_url = vid.streamURL() #This is what Kodi (XBMC) will play except: dev.log('Failed to get a valid stream_url!') return False #Failed to grab a video title #xbmc.Player().play(v.getbest().url) #Play this video liz = xbmcgui.ListItem(meta['title'], iconImage=poster, thumbnailImage=poster) liz.setInfo( type="Video", infoLabels=meta ) liz.setPath(stream_url) return xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, liz)
def add_playlist(id, type=''): if type == '' or type == 'tv': api_url = 'http://youtubelibrary.nl/api/v1/playlists/tv/' + id + '?api_token=' + vars.__settings__.getSetting( 'api_token') if type == 'musicvideo': api_url = 'http://youtubelibrary.nl/api/v1/playlists/musicvideos/' + id + '?api_token=' + vars.__settings__.getSetting( 'api_token') if type == 'movies': api_url = 'http://youtubelibrary.nl/api/v1/playlists/movies/' + id + '?api_token=' + vars.__settings__.getSetting( 'api_token') dev.log('Adding the Api playlist to the config: ' + api_url) data = json.load(urllib2.urlopen(api_url)) if 'data' not in data: url = dev.build_url({'mode': 'ApiIndex'}) dev.adddir( 'Something went wrong', url, description= 'There was an error getting the playlist from the youtubelibrary.nl API.' ) return False playlist = data['data'] return playlist url = dev.build_url({'mode': 'ApiAddPlaylist', 'type': type}) dev.adddir(playlist['title'], url, description=playlist['description'])
def downloadYoutubeVid(name, fold, videoid, settings, type='', season=None): #youtube-dl command to download best quality: -f bestvideo[ext!=webm]+bestaudio[ext!=webm]/best[ext!=webm] #YDStreamExtractor.disableDASHVideo(True) movieLibrary = vars.tv_folder #The path we should save in is the vars.tv_folder setting from the addon settings if type == 'musicvideo': movieLibrary = vars.musicvideo_folder if type == 'movies': movieLibrary = vars.movies_folder folder = os.path.join(movieLibrary, fold) #Set the folder to the maindir/dir enc_name = dev.legal_filename( name) #Encode the filename to a legal filename xbmcvfs.mkdir( movieLibrary) #Create the maindirectory if it does not exist yet xbmcvfs.mkdir(folder) #Create this subfolder if it does not exist yet xbmcvfs.mkdir(folder) #Create this subfolder if it does not exist yet if type == '' or type == 'tv': folder = os.path.join(folder, 'Season ' + season) #Set the folder to the maindir/dir xbmcvfs.mkdir(folder) #Create this subfolder if it does not exist yet full_file_path = os.path.join(folder, enc_name) #Set the file to maindir/name/name dev.log('Downloading ' + videoid, 1) #vid = YDStreamExtractor.getVideoInfo(videoid,quality=1) path = os.path.join(movieLibrary, fold) #Set the folder to the maindir/dir #url = "https://www.youtube.com/watch?v=YKSU82afy1w" #ducktales intro to test url = "https://www.youtube.com/watch?v=" + videoid vid = YDStreamExtractor.getVideoInfo(url, quality=1) if vid == None: dev.log('Failed to retrieve video from url: ' + url) return False if settings.find('download_videos').text == '720p': dev.log('%%%%%%% QUALITY: 720p quality selected') format = 'bestvideo[height<=?720]+bestaudio/best[height<=?720]' elif settings.find('download_videos').text == '1080p': dev.log('%%%%%%% QUALITY: 1080p quality selected') format = 'bestvideo[height<=?1080]+bestaudio/best[height<=?1080]' else: dev.log('%%%%%%% QUALITY: best quality selected') format = 'bestvideo+bestaudio/best' ydl_opts = { 'format': format, 'logger': MyLogger(), 'progress_hooks': [my_hook], 'outtmpl': full_file_path + '.%(ext)s', #'-o' : enc_name+'.%(ext)s', } with youtube_dl.YoutubeDL(ydl_opts) as ydl: return ydl.download(['https://www.youtube.com/watch?v=' + videoid]) """
def addBookmark(currentTime, name, imdb='0'): import hashlib dev.log('addBookmark(%s)' % name) try: idFile = hashlib.md5() for i in name: idFile.update(str(i)) for i in imdb: idFile.update(str(i)) idFile = str(idFile.hexdigest()) dev.log('addBookmark: idFile calculated: %s' % idFile) timeInSeconds = str(currentTime) xbmcvfs.mkdir( xbmc.translatePath(vars.addonInfo('profile')).decode( 'utf-8')) #Create the directory if it does not yet exist dbcon = database.connect(os.path.join(vars.dataPath, 'settings.db')) dbcur = dbcon.cursor() dbcur.execute("CREATE TABLE IF NOT EXISTS bookmark (" "idFile TEXT, " "timeInSeconds TEXT, " "UNIQUE(idFile)" ");") dbcur.execute("DELETE FROM bookmark WHERE idFile = '%s'" % idFile) dbcur.execute("INSERT INTO bookmark Values (?, ?)", (idFile, timeInSeconds)) dbcon.commit() except: pass
def update_playlist(id, type=''): settings = m_xml.xml_get_elem('playlists/playlist', 'playlist', {'id': id}, type=type) #Grab the xml settings for this playlist if settings is None: dev.log('Could not find playlist '+id+' in the '+dev.typeXml(type)+' file', True) return False else: dev.log('Updating playlist %s (Id: %s)' % (settings.find('title').text.encode('utf-8'), id)) #Check in which folder the show should be added folder = settings.find('overwritefolder').text if folder is None or folder == '': folder = dev.legal_filename(settings.find('title').text) #Overwrite folder is not set in settings.xml, so set the folder to the title of the show else: folder = dev.legal_filename(folder) #Create the tvshow.nfo writenfo = settings.find('writenfo').text if writenfo != 'no': if type == '' or type == 'tv': generators.write_tvshow_nfo(folder, settings) update_playlist_vids(id, folder, settings, type=type) #Save the time this playlist got updated in the xml import datetime d=datetime.datetime.now() m_xml.xml_update_playlist_attr(id, 'scansince', d.strftime("%d/%m/%Y %H:%M:%S"), type=type) return True
def write_xml(elem, dir='', output='', type=''): if output == '': output = dev.typeXml(type) dev.log('write_xml('+type+','+output+').') xbmcvfs.mkdir(vars.settingsPath) #Create the settings dir if it does not exist already if dir is not '': xbmcvfs.mkdir(vars.settingsPath+dir) #Create the settings dir if it does not exist already #Write these settings to a .xml file in the addonfolder output_file = os.path.join(vars.settingsPath+dir, output) #Set the outputfile to settings.xml #Creating a backup of the .xml file (in case it gets corrupted) backupfile = os.path.join(vars.settingsPath+dir, output+'.backup') if xbmcvfs.exists(output_file): if xbmcvfs.copy(output_file, backupfile): dev.log('Created a backup of the xml file at: '+backupfile) else: dev.log('Failed to create a backup of the xml file at: '+backupfile) else: dev.log(output_file+' could not be found, so not able to create a backup') indent( elem ) #Prettify the xml so its not on one line tree = ElementTree.ElementTree( elem ) #Convert the xml back to an element tree.write(output_file) #Save the XML in the settings file #For backup purposes, check if the xml got corrupted by writing just now if xml_get(type) is False: dev.log('corrupt .xml file')
def hms_to_sec(hms): hms = hms.strip(' \t\n\r') #dev.log('hms_to_sec('+hms+')') m = re.search(r'(?i)((\d+)h)?((\d+)m)?((\d+)s)?', hms) if m: if m.group(2) is None and m.group(4) is None and m.group(6) == None: #if hms.count(':') == 2: m = re.search(r'(?i)((\d)+:)?((\d+))?(:(\d)+)?', hms) #else: #m = re.search(r'(?i)((\d)+:)?((\d+))?(:(\d)+)?', hms) hours = m.group(2) minutes = m.group(4) seconds = m.group(6) #dev.log(str(hours)+', '+str(minutes)+', '+str(seconds)) if seconds is None: seconds = '0' #Seconds was not set in the setting, so we start with 0 seconds seconds = int(seconds) #dev.log('Seconds is '+str(seconds)) if minutes is not None: #If minutes are specified #dev.log('minutes is '+minutes) sm = int(minutes) * 60 seconds = seconds + sm if hours is not None: #dev.log('hours is '+hours) sh = int(hours) * 60 * 60 seconds = seconds + sh return seconds else: dev.log('Could not extract seconds from hms format: ' + hms, True) return None
def write_xml(elem, dir='', output='', type=''): if output == '': output = dev.typeXml(type) dev.log('write_xml(' + type + ',' + output + ').') xbmcvfs.mkdir(vars.settingsPath ) #Create the settings dir if it does not exist already if dir is not '': xbmcvfs.mkdir( vars.settingsPath + dir) #Create the settings dir if it does not exist already #Write these settings to a .xml file in the addonfolder output_file = os.path.join(vars.settingsPath + dir, output) #Set the outputfile to settings.xml #Creating a backup of the .xml file (in case it gets corrupted) backupfile = os.path.join(vars.settingsPath + dir, output + '.backup') if xbmcvfs.exists(output_file): if xbmcvfs.copy(output_file, backupfile): dev.log('Created a backup of the xml file at: ' + backupfile) else: dev.log('Failed to create a backup of the xml file at: ' + backupfile) else: dev.log(output_file + ' could not be found, so not able to create a backup') indent(elem) #Prettify the xml so its not on one line tree = ElementTree.ElementTree(elem) #Convert the xml back to an element tree.write(output_file) #Save the XML in the settings file #For backup purposes, check if the xml got corrupted by writing just now if xml_get(type) is False: dev.log('corrupt .xml file')
def playlist_add_episode(playlist, season, id, season_tag='season', type=''): dev.log('playlist_add_episode('+season+','+id+', type='+type+')') #Check if this playlist isnt in the xml file yet #if xml_get_elem('season', 'episode', {'id' : id}, playlist=playlist) is None: #Build the playlist #doc = playlist_xml_get(playlist) #s = doc.find("season[@number='"+season+"']") s = xml_get_elem(season_tag, season_tag, {'number': season}, playlist=playlist, type=type) if s is None: playlist_add_season(playlist, season, type=type) #doc = playlist_xml_get(playlist) #s = doc.find("season[@number='"+season+"']") s = xml_get_elem(season_tag, season_tag, {'number': season}, playlist=playlist, type=type) #doc = playlist_xml_get(playlist) global playlistdocument attr = { 'id' : id} elem = Element('episode', attr) s.insert(0, elem) root = playlistdocument.getroot() write_xml(root, dir=dev.typeEpnr(type), output=playlist+'.xml') dev.log('Added the episode '+id+' to '+season_tag+': '+season+' in '+dev.typeEpnr(type)+'/'+playlist+'.xml') #else: #dev.log('playlist_add_episode: not added episode '+id+' since the episode already exists')
def refresh_playlist(id, type=''): #Grab the settings from this playlist settings = m_xml.xml_get_elem( 'playlists/playlist', 'playlist', {'id': id}, type=type) #Grab the xml settings for this playlist if settings is None: dev.log( 'refreshPlaylist: Could not find playlist ' + id + ' in the ' + typeXml(type) + ' file', True) return False else: i = xbmcgui.Dialog().yesno( "Refresh Playlist", "Are you sure you want to refresh this playlist?") if i != 0: m_xml.xml_update_playlist_setting(id, 'lastvideoId', '', type=type) #Delete the .xml containing all scanned videoId's as well file = os.path.join(vars.settingsPath, dev.typeEpnr(type)) file = os.path.join(file, id + '.xml') if os.path.isfile(file): success = os.remove(file) #Remove the episodenr xml file xbmcgui.Dialog().ok('Refreshed Playlist', 'Succesfully refreshed playlist ' + id) i = xbmcgui.Dialog().yesno( 'Delete from library', 'Do you also want to delete the previous videos from your library?' ) if i != 0: #Check in which folder the show resides folder = settings.find('overwritefolder').text if folder is None or folder == '': folder = dev.legal_filename( settings.find('title').text ) #Overwrite folder is not set in settings.xml, so set the folder to the title of the show else: folder = dev.legal_filename(folder) movieLibrary = vars.tv_folder #Use the directory from the addon settings if type == 'musicvideo': movieLibrary = vars.musicvideo_folder elif type == 'movies': movieLibrary = vars.movies_folder dir = os.path.join(movieLibrary, folder) #Set the folder to the maindir/dir success = shutil.rmtree( dir, ignore_errors=True) #Remove the directory #if vars.update_videolibrary == "true" and type=='': # update_dir = vars.tv_folder_path # if type == 'musicvideo': # update_dir = vars.musicvideo_folder_path # dev.log('Updating video library is enabled. Cleaning librarys directory %s' % update_dir, True) # xbmc.executebuiltin('xbmc.updatelibrary(Video,'+update_dir+')') xbmcgui.Dialog().ok( 'Removed from library', 'Deleted the previous videos from your library (You should clean your library, otherwise they will still show in your library)' ) editPlaylist(id, type=type) #Load the editplaylist view
def playlist_xml_get(playlist, type=''): dev.log('playlist_XML_get('+type+')') if xbmcvfs.exists(os.path.join(vars.settingsPath,dev.typeEpnr(type)+"/"+playlist+".xml")) == False: #If the episodes.xml file can't be found, we should create this file playlist_create_xml(playlist, type=type) global playlistdocument #Set the document variable as global, so every function can reach it playlistdocument = ElementTree.parse( vars.settingsPath+dev.typeEpnr(type)+'/'+playlist+'.xml' ) return playlistdocument
def manage_playlists(type=''): dev.log('manage_playlists(' + type + ')') #pl = m_xml.xml_get_elem('playlists', 'playlists') #Grab <playlists> m_xml.xml_get(type) pl = m_xml.document.findall('playlists/playlist') if pl is not None: for child in pl: #Loop through each playlist url = dev.build_url({ 'mode': 'editPlaylist', 'id': child.attrib['id'], 'type': type }) #Build the contextmenu item to force the updating of one playlist context_url = dev.build_url({ 'mode': 'updateplaylist', 'id': child.attrib['id'], 'type': type }) context_url2 = dev.build_url({ 'mode': 'deletePlaylist', 'id': child.attrib['id'], 'type': type }) context_url3 = dev.build_url({ 'mode': 'refreshPlaylist', 'id': child.attrib['id'], 'type': type }) context_url4 = dev.build_url({ 'mode': 'refreshArtwork', 'id': child.attrib['id'], 'type': type }) commands = [] commands.append(( dev.lang(31006), 'XBMC.RunPlugin(' + context_url + ')', )) commands.append(( dev.lang(31007), 'XBMC.RunPlugin(' + context_url2 + ')', )) commands.append(( dev.lang(31029), 'XBMC.RunPlugin(' + context_url3 + ')', )) commands.append(( dev.lang(31030), 'XBMC.RunPlugin(' + context_url4 + ')', )) dev.adddir(child.find('title').text, url, child.find('thumb').text, child.find('fanart').text, child.find('description').text, context=commands) xbmcplugin.endOfDirectory(vars.addon_handle)
def downloadYoutubeVid(name, fold, videoid, settings, type='', season=None): #youtube-dl command to download best quality: -f bestvideo[ext!=webm]+bestaudio[ext!=webm]/best[ext!=webm] #YDStreamExtractor.disableDASHVideo(True) movieLibrary = vars.tv_folder #The path we should save in is the vars.tv_folder setting from the addon settings if type=='musicvideo': movieLibrary = vars.musicvideo_folder if type=='movies': movieLibrary = vars.movies_folder folder = os.path.join(movieLibrary, fold) #Set the folder to the maindir/dir enc_name = dev.legal_filename(name) #Encode the filename to a legal filename xbmcvfs.mkdir(movieLibrary) #Create the maindirectory if it does not exist yet xbmcvfs.mkdir(folder) #Create this subfolder if it does not exist yet xbmcvfs.mkdir(folder) #Create this subfolder if it does not exist yet if type == '' or type == 'tv': folder = os.path.join(folder, 'Season '+season) #Set the folder to the maindir/dir xbmcvfs.mkdir(folder) #Create this subfolder if it does not exist yet full_file_path = os.path.join(folder, enc_name) #Set the file to maindir/name/name dev.log('Downloading '+videoid, 1) #vid = YDStreamExtractor.getVideoInfo(videoid,quality=1) path = os.path.join(movieLibrary, fold) #Set the folder to the maindir/dir #url = "https://www.youtube.com/watch?v=YKSU82afy1w" #ducktales intro to test url = "https://www.youtube.com/watch?v="+videoid vid = YDStreamExtractor.getVideoInfo(url,quality=1) if vid == None: dev.log('Failed to retrieve video from url: '+url) return False if settings.find('download_videos').text == '720p': dev.log('%%%%%%% QUALITY: 720p quality selected') format = 'bestvideo[height<=?720]+bestaudio/best[height<=?720]' elif settings.find('download_videos').text == '1080p': dev.log('%%%%%%% QUALITY: 1080p quality selected') format = 'bestvideo[height<=?1080]+bestaudio/best[height<=?1080]' else: dev.log('%%%%%%% QUALITY: best quality selected') format = 'bestvideo+bestaudio/best' ydl_opts = { 'format': format, 'logger': MyLogger(), 'progress_hooks': [my_hook], 'outtmpl' : full_file_path+'.%(ext)s', #'-o' : enc_name+'.%(ext)s', } with youtube_dl.YoutubeDL(ydl_opts) as ydl: return ydl.download(['https://www.youtube.com/watch?v='+videoid]) """
def find_year(text): regex = "(\(?()c(opyright)?\)?)?\s*(\d{4})" m = re.search(regex, text, re.IGNORECASE) if m: if len(m.group(4)) == 4: #Found a year! dev.log(u'Found a year!: '+m.group(4)+ ' Whole match: '+m.group(0)) text = text.replace(m.group(0), '') #Remove the copyright / year notice from the title return m.group(4), text return False, text
def number_of_episodes(playlist, season, season_tag='season', type=''): s = xml_get_elem(season_tag, season_tag, {'number': season}, playlist=playlist, type=type) if s == None: dev.log('number_of_episodes(' + type + '): Could not find ' + season_tag + ' ' + season + ' in playlist ' + playlist) return None dev.log('number_of_episodes(' + type + '): Found ' + str(len(s)) + ' episodes in ' + season_tag + ' ' + season) return len(s)
def update_playlist(type=''): id = vars.args['id'][0] xbmcgui.Dialog().notification(vars.__addonname__, 'Updating '+dev.typeName(type)+' Playlist '+id, vars.__icon__, 3000) service.update_playlist(id, type=type) xbmcgui.Dialog().notification(vars.__addonname__, 'Done updating '+dev.typeName(type)+' Playlist '+id, vars.__icon__, 3000) #Should we also update the video library? if vars.update_videolibrary == "true": update_dir = vars.tv_folder_path if type == 'musicvideo': update_dir = vars.musicvideo_folder_path dev.log('Updating video library is enabled. Updating librarys directory %s' % update_dir, True) xbmc.executebuiltin('xbmc.updatelibrary(Video,'+update_dir+')')
def xml_get(type=''): file=dev.typeXml(type) dev.log('XML_get('+type+','+file+')') global document #Set the document variable as global, so every function can reach it try: document = ElementTree.parse( vars.settingsPath+file ) except Exception: xbmcgui.Dialog().ok("ERROR: "+file+" got corrupted", "ERROR!: "+file+" got corrupted. Please report this error to the addon developer on youtubelibrary.nl or the kodi forums. Luckily a backup has been created automatically before.") dev.log('ERROR: '+file+' got corrupted.', 1) raise ValueError(output_file+' got corrupted! Best to quit here') return False return document
def update_playlist(id, type=''): xbmcgui.Dialog().notification(vars.__addonname__, 'Updating '+dev.typeName(type)+' Playlist '+id, vars.__icon__, 3000) service.update_playlist(id, type=type) xbmcgui.Dialog().notification(vars.__addonname__, 'Done updating '+dev.typeName(type)+' Playlist '+id, vars.__icon__, 3000) #Should we also update the video library? if vars.update_videolibrary == "true": update_dir = vars.tv_folder_path if type == 'musicvideo': update_dir = vars.musicvideo_folder_path elif type == 'movies': update_dir = vars.movies_folder_path dev.log('Updating video library is enabled. Updating librarys directory %s' % update_dir, True) xbmc.executebuiltin('xbmc.updatelibrary(Video,'+update_dir+')')
def yt_get_channel_info(Channelid): #Connect to youtube API youtube = build_youtube() dev.log('GET yt_get_channel_info: https://www.googleapis.com/youtube/v3/channels?part=snippet%2C+contentDetails%2C+brandingSettings&maxResults=50&id='+Channelid+'&key='+vars.API_KEY) #Search for the channels with the following parameters search_response = youtube.channels().list( part="brandingSettings,snippet,contentDetails", id=Channelid, maxResults=50 ).execute() return search_response
def playlist_xml_get(playlist, type=''): dev.log('playlist_XML_get(' + type + ')') if xbmcvfs.exists( os.path.join(vars.settingsPath, dev.typeEpnr(type) + "/" + playlist + ".xml") ) == False: #If the episodes.xml file can't be found, we should create this file playlist_create_xml(playlist, type=type) global playlistdocument #Set the document variable as global, so every function can reach it playlistdocument = ElementTree.parse(vars.settingsPath + dev.typeEpnr(type) + '/' + playlist + '.xml') return playlistdocument
def playlist_add_season(playlist, season, season_tag='season', type=''): dev.log('playlist_add_season('+season+')') #Check if this playlist isnt in the xml file yet #if xml_get_elem('season', 'episode', {'id' : id}, playlist=playlist) is None: #Build the playlist doc = playlist_xml_get(playlist, type=type) attr = { 'number' : season} elem = Element(season_tag, attr) root = doc.getroot() root.insert(0, elem) write_xml(root, dir=dev.typeEpnr(type), output=playlist+'.xml') dev.log('Added '+season_tag+': '+season+' in '+dev.typeEpnr(type)+'/'+playlist+'.xml')
def create_xml(file='settings.xml'): dev.log('Create_xml') #<playlists> root = Element('config') newxml = SubElement(root, 'playlists') example = { 'id': 'PUTPLAYLISTIDHERE', 'enabled': 'no', 'settings': { 'type': 'TV', 'title': 'Exampleplaylist', 'description': 'This is an example of a youtube playlist xml config for use with Youtube Library', 'genre': 'Action/Comedy', 'published': '2010', #Art 'thumb': 'thumbimgurl', 'fanart': 'fanarturl', 'banner': 'bannerurl', 'epsownfanart': 'No', # STRM & NFO Settings 'writenfo': 'Yes', 'delete': '168', 'keepvideos': '500', 'overwritefolder': 'Z:/MEDIA/TV Shows/Example show', #Filters 'minlength': '12:00', 'maxlength': '25:00', 'excludewords': 'trailer|commercial', 'onlyinclude': 'review', #Strip Stuff from NFO information 'striptitle': 'Brought to you by', 'removetitle': 'Example Youtube Channels|Always annoying part of title', 'stripdescription': 'See our other channels|Subscribe to our channel', 'removedescription': 'Brought to you by our sponsors', #Scan Settings 'lastvideoId': 'Wixi28loswo', 'scansince': '29 jun 2015 18:23:21' } } playlist = xml_create_playlist(example) #Append this playlist to the new created xml file #newxml.append(playlist) #Write this new xml to the settings.xml file write_xml(root, output=file) dev.log('Create_xml: Created new ' + file + ' file')
def xml_update_playlist_attr(id, attr, val, type=''): dev.log('XML: Updating playlist id ' + id + ' with attr ' + attr + ' : ' + val + ' (' + type + ')') #Grab this playlist from the xml file playlist = xml_get_elem('playlists/playlist', 'playlist', {'id': id}, type=type) #Check if we have succesfully retrieved the playlist if playlist == None: dev.log('XML_update_playlist: could not find playlist ' + id) else: dev.log('XML_update_playlist_: found playlist ' + id) #Update this attribute to the new val try: del playlist.attrib[attr] except: pass playlist.attrib[attr] = val #playlist.set(attr, val) #Write this to the xml root = document.getroot() write_xml(root, type=type) dev.log('XML_update_playlist_attr: written XML')
def playlist_add_season(playlist, season, season_tag='season', type=''): dev.log('playlist_add_season(' + season + ')') #Check if this playlist isnt in the xml file yet #if xml_get_elem('season', 'episode', {'id' : id}, playlist=playlist) is None: #Build the playlist doc = playlist_xml_get(playlist, type=type) attr = {'number': season} elem = Element(season_tag, attr) root = doc.getroot() root.insert(0, elem) write_xml(root, dir=dev.typeEpnr(type), output=playlist + '.xml') dev.log('Added ' + season_tag + ': ' + season + ' in ' + dev.typeEpnr(type) + '/' + playlist + '.xml')
def yt_get_playlist_info(id): #Connect to youtube API youtube = build_youtube() #Retrieve the information from the youtube API dev.log( 'GET yt_get_playlist_info: https://www.googleapis.com/youtube/v3/playlists?part=snippet%2C+id%2C+contentDetails&maxResults=50&channelId=' + id + '&key=' + vars.API_KEY) response = youtube.playlists().list(part="contentDetails,id,snippet", id=id, maxResults=50).execute() return response '''
def yt_get_channel_info(Channelid): #Connect to youtube API youtube = build_youtube() dev.log( 'GET yt_get_channel_info: https://www.googleapis.com/youtube/v3/channels?part=snippet%2C+contentDetails%2C+brandingSettings&maxResults=50&id=' + Channelid + '&key=' + vars.API_KEY) #Search for the channels with the following parameters search_response = youtube.channels().list( part="brandingSettings,snippet,contentDetails", id=Channelid, maxResults=50).execute() return search_response
def vids_by_playlist(id, nextpage=False): youtube = build_youtube() if nextpage == False: dev.log( 'GET vids_by_playlist: https://www.googleapis.com/youtube/v3/playlistItems?part=snippet%2C+contentDetails&maxResults=50&playlistId=' + id + '&key=' + vars.API_KEY) try: search_response = youtube.playlistItems().list( part="snippet,contentDetails", maxResults=50, playlistId=id).execute() except KeyboardInterrupt: raise except: dev.log('Playlist ' + id + ' could not be retrieved!') return False else: dev.log( 'GET vids_by_playlist: https://www.googleapis.com/youtube/v3/playlistItems?part=snippet%2C+contentDetails&maxResults=50&playlistId=' + id + '&pageToken=' + nextpage + '&key=' + vars.API_KEY) try: search_response = youtube.playlistItems().list( part="snippet,contentDetails", maxResults=50, playlistId=id, pageToken=nextpage).execute() except KeyboardInterrupt: raise except: dev.log('Playlist ' + id + ' could not be retrieved!') return False return search_response
def create_xml(file='settings.xml'): dev.log('Create_xml') #<playlists> root = Element('config') newxml = SubElement(root, 'playlists') example = { 'id' : 'PUTPLAYLISTIDHERE', 'enabled' : 'no', 'settings' : { 'type' : 'TV', 'title' : 'Exampleplaylist', 'description' : 'This is an example of a youtube playlist xml config for use with Youtube Library', 'genre' : 'Action/Comedy', 'published' : '2010', #Art 'thumb' : 'thumbimgurl', 'fanart' : 'fanarturl', 'banner' : 'bannerurl', 'epsownfanart' : 'No', # STRM & NFO Settings 'writenfo' : 'Yes', 'delete' : '168', 'keepvideos' : '500', 'overwritefolder' : 'Z:/MEDIA/TV Shows/Example show', #Filters 'minlength' : '12:00', 'maxlength' : '25:00', 'excludewords' : 'trailer|commercial', 'onlyinclude' : 'review', #Strip Stuff from NFO information 'striptitle' : 'Brought to you by', 'removetitle' : 'Example Youtube Channels|Always annoying part of title', 'stripdescription' : 'See our other channels|Subscribe to our channel', 'removedescription' : 'Brought to you by our sponsors', #Scan Settings 'lastvideoId' : 'Wixi28loswo', 'scansince' : '29 jun 2015 18:23:21' } } playlist = xml_create_playlist(example) #Append this playlist to the new created xml file #newxml.append(playlist) #Write this new xml to the settings.xml file write_xml(root, output=file) dev.log('Create_xml: Created new '+file+' file')
def yt_get_playlist_info(id): #Connect to youtube API youtube = build_youtube() #Retrieve the information from the youtube API dev.log('GET yt_get_playlist_info: https://www.googleapis.com/youtube/v3/playlists?part=snippet%2C+id%2C+contentDetails&maxResults=50&channelId='+id+'&key='+vars.API_KEY) response = youtube.playlists().list( part="contentDetails,id,snippet", id=id, maxResults=50 ).execute() return response '''
def vids_by_playlist(id, nextpage = False): youtube = build_youtube() if nextpage == False: dev.log('GET vids_by_playlist: https://www.googleapis.com/youtube/v3/playlistItems?part=snippet%2C+contentDetails&maxResults=50&playlistId='+id+'&key='+vars.API_KEY) try: search_response = youtube.playlistItems().list( part="snippet,contentDetails", maxResults=50, playlistId=id ).execute() except KeyboardInterrupt: raise except: dev.log('Playlist '+id+' could not be retrieved!') return False else: dev.log('GET vids_by_playlist: https://www.googleapis.com/youtube/v3/playlistItems?part=snippet%2C+contentDetails&maxResults=50&playlistId='+id+'&pageToken='+nextpage+'&key='+vars.API_KEY) try: search_response = youtube.playlistItems().list( part="snippet,contentDetails", maxResults=50, playlistId=id, pageToken=nextpage ).execute() except KeyboardInterrupt: raise except: dev.log('Playlist '+id+' could not be retrieved!') return False return search_response
def xml_get(type=''): file = dev.typeXml(type) dev.log('XML_get(' + type + ',' + file + ')') global document #Set the document variable as global, so every function can reach it try: document = ElementTree.parse(vars.settingsPath + file) except Exception: xbmcgui.Dialog().ok( "ERROR: " + file + " got corrupted", "ERROR!: " + file + " got corrupted. Please report this error to the addon developer on youtubelibrary.nl or the kodi forums. Luckily a backup has been created automatically before." ) dev.log('ERROR: ' + file + ' got corrupted.', 1) raise ValueError(output_file + ' got corrupted! Best to quit here') return False return document
def find_artist_song(text, hardcoded_artist): regex = "^([^-\n]+)(-|by|\|)\s*([^-:\n]+)$" m = re.search(regex, text, re.IGNORECASE) if m: dev.log('find_artist_song() Found Artist - Song: '+str(m.group(1).encode('UTF-8'))+' - '+str(m.group(3).encode('UTF-8'))) artist = remove_extra_spaces(m.group(1)) song = remove_extra_spaces(m.group(3)) if m.group(2) == 'by' or artist.lower() == hardcoded_artist.lower(): #Turn artist and song around artist = m.group(3) song = m.group(1) if '(' in artist and ')' not in artist or ')' in artist and '(' not in artist: return False, False return artist, song return False, False
def yt_get_playlists_by_channel(id, pagetoken='default'): if pagetoken == 'default': pagetoken = '' #Connect to youtube API youtube = build_youtube() dev.log( 'GET yt_get_playlists_by_channel: https://www.googleapis.com/youtube/v3/playlists?part=snippet%2C+contentDetails&maxResults=50&channelId=' + id + '&key=' + vars.API_KEY + '&pageToken=' + pagetoken) #Retrieve the information from the youtube API response = youtube.playlists().list(part="contentDetails,snippet", channelId=id, maxResults=50, pageToken=pagetoken).execute() return response
def deleteBookmark(name, imdb='0'): dev.log('deleteBookmark(%s)' % name) import hashlib try: idFile = hashlib.md5() for i in name: idFile.update(str(i)) for i in imdb: idFile.update(str(i)) idFile = str(idFile.hexdigest()) control.makeFile(control.vars.dataPath) dbcon = database.connect(os.path.join(vars.dataPath, 'settings.db')) dbcur = dbcon.cursor() dbcur.execute("CREATE TABLE IF NOT EXISTS bookmark (""idFile TEXT, ""timeInSeconds TEXT, ""UNIQUE(idFile)"");") dbcur.execute("DELETE FROM bookmark WHERE idFile = '%s'" % idFile) dbcon.commit() except: pass
def yt_get_playlists_by_channel(id, pagetoken='default'): if pagetoken == 'default': pagetoken = '' #Connect to youtube API youtube = build_youtube() dev.log('GET yt_get_playlists_by_channel: https://www.googleapis.com/youtube/v3/playlists?part=snippet%2C+contentDetails&maxResults=50&channelId='+id+'&key='+vars.API_KEY+'&pageToken='+pagetoken) #Retrieve the information from the youtube API response = youtube.playlists().list( part="contentDetails,snippet", channelId=id, maxResults=50, pageToken=pagetoken ).execute() return response
def manage_playlists(type=''): dev.log('manage_playlists('+type+')') #pl = m_xml.xml_get_elem('playlists', 'playlists') #Grab <playlists> m_xml.xml_get(type) pl = m_xml.document.findall('playlists/playlist') if pl is not None: for child in pl: #Loop through each playlist url = dev.build_url({'mode': 'editPlaylist', 'id': child.attrib['id'], 'type': type}) #Build the contextmenu item to force the updating of one playlist context_url = dev.build_url({'mode': 'updateplaylist', 'id': child.attrib['id'], 'type': type}) context_url2 = dev.build_url({'mode': 'deletePlaylist', 'id': child.attrib['id'], 'type': type}) commands = [] commands.append(( dev.lang(31006), 'XBMC.RunPlugin('+context_url+')', )) commands.append(( dev.lang(31007), 'XBMC.RunPlugin('+context_url2+')', )) dev.adddir(child.find('title').text, url, child.find('thumb').text, child.find('fanart').text, child.find('description').text, context=commands) xbmcplugin.endOfDirectory(vars.addon_handle)
def playlist_create_xml(playlist, type=''): dev.log('playlist_create_xml('+type+')') #<playlists> root = Element('seasons') #attr = { 'number' : season } #newxml = SubElement(root, 'season', attr) #attr = { 'id' : videoId} #elem = SubElement(newxml, 'episode', attr) #playlist = xml_create_playlist(example) #Append this playlist to the new created xml file #newxml.append(playlist) #Write this new xml to the settings.xml file write_xml(root, dev.typeEpnr(type), playlist+'.xml') dev.log('playlist_create_xml: Created new '+dev.typeEpnr(type)+'/'+playlist+'.xml')
def playlist_create_xml(playlist, type=''): dev.log('playlist_create_xml(' + type + ')') #<playlists> root = Element('seasons') #attr = { 'number' : season } #newxml = SubElement(root, 'season', attr) #attr = { 'id' : videoId} #elem = SubElement(newxml, 'episode', attr) #playlist = xml_create_playlist(example) #Append this playlist to the new created xml file #newxml.append(playlist) #Write this new xml to the settings.xml file write_xml(root, dev.typeEpnr(type), playlist + '.xml') dev.log('playlist_create_xml: Created new ' + dev.typeEpnr(type) + '/' + playlist + '.xml')
def addBookmark(currentTime, name, imdb='0'): import hashlib dev.log('addBookmark(%s)' % name) try: idFile = hashlib.md5() for i in name: idFile.update(str(i)) for i in imdb: idFile.update(str(i)) idFile = str(idFile.hexdigest()) dev.log('addBookmark: idFile calculated: %s' % idFile) timeInSeconds = str(currentTime) xbmcvfs.mkdir(xbmc.translatePath(vars.addonInfo('profile')).decode('utf-8')) #Create the directory if it does not yet exist dbcon = database.connect(os.path.join(vars.dataPath, 'settings.db')) dbcur = dbcon.cursor() dbcur.execute("CREATE TABLE IF NOT EXISTS bookmark (""idFile TEXT, ""timeInSeconds TEXT, ""UNIQUE(idFile)"");") dbcur.execute("DELETE FROM bookmark WHERE idFile = '%s'" % idFile) dbcur.execute("INSERT INTO bookmark Values (?, ?)", (idFile, timeInSeconds)) dbcon.commit() except: pass
def xml_get_elem(path, tag, whereAttrib=False, whereTxt=False, playlist=False, type=''): dev.log('XML_get_elem(' + type + ')') if playlist == False: xml_get(type) # Grab the xml file doc = document else: doc = playlist_xml_get( playlist, type=type) #Grab the episodes.xml file of this playlist for child in doc.findall(path): check = True # Use this var to check if this element meets all requirements. Set it by default to true, so it can be set to False if it fails some requirement #Check if this element has the tag we are looking for if child.tag == tag: #Should we also check that the element has a certain attribute with a certain value? if whereAttrib != False: # Check if this element meets all the requirements of the attributes for key, value in whereAttrib.iteritems(): if child.attrib[key] != value: #This element does not meet all requirements, so quit this for loop, since checking for others ones has no use, since it already does meet this requirement check = False break if check == False: #It has already failed to meet a requirement, so skip to the next xml element continue #Should we check if the element has the given text? if whereTxt != False: # Check if this element has the same text as required if child.text != whereTxt: #This XML element does not meet te requirement of holding the same text, so we will skip to the next xml element continue #If check is still true, we have found the correct element, so return this element return child break #If the code has made it here, that means it has failed to find the xml element, so return None return None
def refresh_playlist(id, type=''): #Grab the settings from this playlist settings = m_xml.xml_get_elem('playlists/playlist', 'playlist', {'id': id}, type=type) #Grab the xml settings for this playlist if settings is None: dev.log('refreshPlaylist: Could not find playlist '+id+' in the '+typeXml(type)+' file', True) return False else: i = xbmcgui.Dialog().yesno("Refresh Playlist", "Are you sure you want to refresh this playlist?") if i != 0: m_xml.xml_update_playlist_setting(id, 'lastvideoId', '', type=type) #Delete the .xml containing all scanned videoId's as well file = os.path.join(vars.settingsPath, dev.typeEpnr(type)) file = os.path.join(file, id+'.xml') if os.path.isfile(file): success = os.remove(file) #Remove the episodenr xml file xbmcgui.Dialog().ok('Refreshed Playlist', 'Succesfully refreshed playlist '+id) i = xbmcgui.Dialog().yesno('Delete from library', 'Do you also want to delete the previous videos from your library?') if i != 0: #Check in which folder the show resides folder = settings.find('overwritefolder').text if folder is None or folder == '': folder = dev.legal_filename(settings.find('title').text) #Overwrite folder is not set in settings.xml, so set the folder to the title of the show else: folder = dev.legal_filename(folder) movieLibrary = vars.tv_folder #Use the directory from the addon settings if type == 'musicvideo': movieLibrary = vars.musicvideo_folder elif type == 'movies': movieLibrary = vars.movies_folder dir = os.path.join(movieLibrary, folder) #Set the folder to the maindir/dir success = shutil.rmtree(dir, ignore_errors=True) #Remove the directory #if vars.update_videolibrary == "true" and type=='': # update_dir = vars.tv_folder_path # if type == 'musicvideo': # update_dir = vars.musicvideo_folder_path # dev.log('Updating video library is enabled. Cleaning librarys directory %s' % update_dir, True) # xbmc.executebuiltin('xbmc.updatelibrary(Video,'+update_dir+')') xbmcgui.Dialog().ok('Removed from library', 'Deleted the previous videos from your library (You should clean your library, otherwise they will still show in your library)') editPlaylist(id, type=type) #Load the editplaylist view
def build_youtube(): try: youtube = build(vars.YOUTUBE_API_SERVICE_NAME, vars.YOUTUBE_API_VERSION, developerKey=vars.API_KEY) except: dev.log( 'ERROR: Could not connect to Youtube API! Will try again in 15 seconds with SSL disabled', 2) import xbmc #Wait 15 seconds before trying again xbmc.Monitor().waitForAbort(15) #Try again with SSL disabled import ssl ssl._create_default_https_context = ssl._create_unverified_context youtube = build(vars.YOUTUBE_API_SERVICE_NAME, vars.YOUTUBE_API_VERSION, developerKey=vars.API_KEY) return youtube
def update_playlist(id, type=''): settings = m_xml.xml_get_elem( 'playlists/playlist', 'playlist', {'id': id}, type=type) #Grab the xml settings for this playlist if settings is None: dev.log( 'Could not find playlist ' + id + ' in the ' + dev.typeXml(type) + ' file', True) return False else: dev.log('Updating playlist %s (Id: %s)' % (settings.find('title').text.encode('utf-8'), id)) #Check in which folder the show should be added folder = settings.find('overwritefolder').text if folder is None or folder == '': folder = dev.legal_filename( settings.find('title').text ) #Overwrite folder is not set in settings.xml, so set the folder to the title of the show else: folder = dev.legal_filename(folder) #Create the tvshow.nfo writenfo = settings.find('writenfo').text if writenfo != 'no': if type == '' or type == 'tv': generators.write_tvshow_nfo(folder, settings) elif type == 'musicvideo': generators.write_artist_nfo(folder, settings) if update_playlist_vids(id, folder, settings, type=type) == False: return False #something failed while updating the videos of the playlist #Save the time this playlist got updated in the xml import datetime d = datetime.datetime.now() m_xml.xml_update_playlist_attr(id, 'scansince', d.strftime("%d/%m/%Y %H:%M:%S"), type=type) return True
def add_playlist(id, type=''): if type=='' or type=='tv': api_url = 'http://youtubelibrary.nl/api/v1/playlists/tv/'+id+'?api_token='+vars.__settings__.getSetting('api_token') if type=='musicvideo': api_url = 'http://youtubelibrary.nl/api/v1/playlists/musicvideos/'+id+'?api_token='+vars.__settings__.getSetting('api_token') if type=='movies': api_url = 'http://youtubelibrary.nl/api/v1/playlists/movies/'+id+'?api_token='+vars.__settings__.getSetting('api_token') dev.log('Adding the Api playlist to the config: '+api_url) data = json.load(urllib2.urlopen(api_url)) if 'data' not in data: url = dev.build_url({'mode': 'ApiIndex'}) dev.adddir('Something went wrong', url, description='There was an error getting the playlist from the youtubelibrary.nl API.') return False; playlist = data['data'] return playlist url = dev.build_url({'mode': 'ApiAddPlaylist', 'type': type}) dev.adddir(playlist['title'], url, description=playlist['description'])
def getBookmark(name, imdb='0'): import hashlib dev.log('getBookmark(%s)' % name) offset = '0' #log('getBookmark 1') idFile = hashlib.md5() #log('getBookmark 2') for i in name: idFile.update(str(i)) #log('getBookmark 3') for i in imdb: idFile.update(str(i)) #log('getBookmark 4') idFile = str(idFile.hexdigest()) #log('getBookmark: idFile calculated: %s' % idFile) xbmcvfs.mkdir(vars.dataPath) #Create the directory if it does not yet exist dbcon = database.connect(vars.databaseFile) dbcur = dbcon.cursor() dbcur.execute("SELECT * FROM bookmark WHERE idFile = '%s'" % idFile) match = dbcur.fetchone() offset = str(match[1]) dbcon.commit() return offset
def browse(api_url = 'default', params = False, type=''): if api_url == 'default': if type == '' or type == 'tv': api_url = 'http://youtubelibrary.nl/api/v1/playlists/tv'+build_url()+'&limit=20' if type == 'musicvideo': api_url = 'http://youtubelibrary.nl/api/v1/playlists/musicvideos'+build_url()+'&limit=20' if type == 'movies': api_url = 'http://youtubelibrary.nl/api/v1/playlists/movies'+build_url()+'&limit=20' #Check if we should add params if isinstance(params,dict): for key, val in params.iteritems(): api_url += '&'+key+'='+val dev.log('Browse the API with url: '+api_url) data = json.load(urllib2.urlopen(api_url)) if 'data' not in data: url = dev.build_url({'mode': 'ApiIndex'}) dev.adddir('Something went wrong', url, description='There was an error connecting to the Ytlibrary API.') return False; for playlist in data['data']: #videos.append(search_result) url = dev.build_url({'mode': 'ApiAddPlaylist', 'id': playlist['id'], 'type': type}) dev.adddir(playlist['title'], url, playlist['thumb'], fanart=playlist['fanart'], description=playlist['description']) if 'paginator' in data: if 'prev_page' in data['paginator']: if data['paginator']['prev_page'] is not None: url = dev.build_url({'mode': 'ApiBrowse', 'api_url': data['paginator']['prev_page'], 'type': type}) dev.adddir('<< Page '+str(data['paginator']['current_page']-1), url, description='Go to the previous page') if 'paginator' in data: if 'next_page' in data['paginator']: if data['paginator']['next_page'] is not None: url = dev.build_url({'mode': 'ApiBrowse', 'api_url': data['paginator']['next_page'], 'type': type}) dev.adddir('>> Page '+str(data['paginator']['current_page']+1), url, description='Go to the next page to see more pre-configured playlists.')
def playYoutubeVid(id, meta=None, poster=None): dev.log('poster: '+poster) #Poster URL that hickups the addon: image://C%3a%5cKodi%5cportable_data%5cuserdata%5caddon_data%5cplugin.video.youtubelibrary%5cStreams%5cTV%5cSleuteltje%20-%20Bios%20Intros%5cfolder.jpg/ #poster = None if meta is None: #Create an empty meta, so we can fill it with the information grabbed from youtube meta = {} if poster is None: poster = 'Default.png' elif poster.startswith('image://'): poster = poster[8:-1] poster = urllib.unquote(urllib.unquote(poster)) dev.log('poster cleaned: '+poster) #YDStreamExtractor.disableDASHVideo(True) #Kodi (XBMC) only plays the video for DASH streams, so you don't want these normally. Of course these are the only 1080p streams on YouTube try: #url = id #a youtube ID will work as well and of course you could pass the url of another site vid = YDStreamExtractor.getVideoInfo(id,quality=1) #quality is 0=SD, 1=720p, 2=1080p and is a maximum stream_url = vid.streamURL() #This is what Kodi (XBMC) will play except: dev.log('Failed to get a valid stream_url!') return False #Failed to grab a video title if 'title' not in meta: meta['title'] = vid.title #Store the youtube title in the meta #xbmc.Player().play(v.getbest().url) #Play this video liz = xbmcgui.ListItem(meta['title'], iconImage=poster, thumbnailImage=poster) liz.setInfo( type="Video", infoLabels=meta ) liz.setPath(stream_url) return xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, liz)
def deleteBookmark(name, imdb='0'): dev.log('deleteBookmark(%s)' % name) import hashlib try: idFile = hashlib.md5() for i in name: idFile.update(str(i)) for i in imdb: idFile.update(str(i)) idFile = str(idFile.hexdigest()) control.makeFile(control.vars.dataPath) dbcon = database.connect(os.path.join(vars.dataPath, 'settings.db')) dbcur = dbcon.cursor() dbcur.execute("CREATE TABLE IF NOT EXISTS bookmark (" "idFile TEXT, " "timeInSeconds TEXT, " "UNIQUE(idFile)" ");") dbcur.execute("DELETE FROM bookmark WHERE idFile = '%s'" % idFile) dbcon.commit() except: pass
def get_duration_vids(vid_ids, extra_info=False): dev.log('Grabbing duration of youtube videos') #Create a seperated string of vid_ids to give to the API idlist = '' for id in vid_ids: idlist += id + ',' idlist = idlist[:-1] dev.log( 'GET duration vids: https://www.googleapis.com/youtube/v3/videos?part=snippet%2C+contentDetails&maxResults=50&id=' + idlist + '&key=' + vars.API_KEY) youtube = build_youtube() search_response = youtube.videos().list(part="contentDetails,statistics", maxResults=50, id=idlist).execute() #Get the duration of each video in the response durations = {} extra = {} for vid in search_response.get("items", []): dur = vid['contentDetails']['duration'] dur = dur[2:] #Strip PT from the duration #dev.log('Duration of video: '+dur) seconds = hms_to_sec(dur) #dev.log('Which makes the video %s seconds long' % seconds) vidid = vid['id'] durations[vidid] = seconds if extra_info is not False: extra[vidid] = vid['statistics'] #except Exception as e: #dev.log("Couldnt extract time: %s" % e) #pass if extra_info is not False: return durations, extra return durations
def getBookmark(name, imdb='0'): import hashlib dev.log('getBookmark(%s)' % name) offset = '0' #log('getBookmark 1') idFile = hashlib.md5() #log('getBookmark 2') for i in name: idFile.update(str(i)) #log('getBookmark 3') for i in imdb: idFile.update(str(i)) #log('getBookmark 4') idFile = str(idFile.hexdigest()) #log('getBookmark: idFile calculated: %s' % idFile) xbmcvfs.mkdir( vars.dataPath) #Create the directory if it does not yet exist dbcon = database.connect(vars.databaseFile) dbcur = dbcon.cursor() dbcur.execute("SELECT * FROM bookmark WHERE idFile = '%s'" % idFile) match = dbcur.fetchone() offset = str(match[1]) dbcon.commit() return offset