def load_subreddits_file_into_a_listitem(self): from utils import parse_subreddit_entry, build_script, compose_list_item, assemble_reddit_filter_string, prettify_reddit_query entries=[] listing=[] if os.path.exists(self.subreddits_file): with open(self.subreddits_file, 'r') as fh: content = fh.read() fh.close() spl = content.split('\n') for i in range(0, len(spl), 1): if spl[i]: subreddit = spl[i].strip() entries.append(subreddit ) entries.sort() for subreddit_entry in entries: subreddit, alias, shortcut_description=parse_subreddit_entry(subreddit_entry) reddit_url= assemble_reddit_filter_string("",subreddit, "yes") liz = compose_list_item( alias, "", "", "script", build_script("listSubReddit",reddit_url,prettify_reddit_query(alias)) ) liz.setProperty('ACTION_manage_subreddits', build_script('manage_subreddits', subreddit_entry,"","" ) ) listing.append(liz) return listing
def load_subreddits_file_into_a_listitem(self): from utils import parse_subreddit_entry, build_script, compose_list_item, assemble_reddit_filter_string, prettify_reddit_query entries=[] listing=[] if os.path.exists(self.subreddits_file): with open(self.subreddits_file, 'r') as fh: content = fh.read() fh.close() spl = content.split('\n') for i in range(0, len(spl), 1): if spl[i]: subreddit = spl[i].strip() entries.append(subreddit ) entries.sort() #log( ' entries count ' + str( len( entries) ) ) for subreddit_entry in entries: #strip out the alias identifier from the subreddit string retrieved from the file so we can process it. subreddit, alias, shortcut_description=parse_subreddit_entry(subreddit_entry) #log( subreddit + " " + shortcut_description ) reddit_url= assemble_reddit_filter_string("",subreddit, "yes") liz = compose_list_item( alias, "", "", "script", build_script("listSubReddit",reddit_url,prettify_reddit_query(alias)) ) liz.setProperty('ACTION_manage_subreddits', build_script('manage_subreddits', subreddit_entry,"","" ) ) listing.append(liz) return listing
def build_link_in_browser_context_menu_entries(url): label_html_to_text=translation(32502) label_open_browser=translation(32503) cxm_list=[] if cxm_show_html_to_text: cxm_list.append((label_html_to_text , build_script('readHTML', url) )) if cxm_show_open_browser: cxm_list.append((label_open_browser , build_script('openBrowser', url) )) return cxm_list
def build_youtube_context_menu_entries(previous_listing_was_of_type, youtube_url,video_id=None,title=None,channel_id_from_previous_listing=None,channel_name=None): from domains import ClassYoutube cxm_list=[] try: match=re.compile( ClassYoutube.regex, re.I).findall( youtube_url ) #regex='(youtube.com/)|(youtu.be/)|(youtube-nocookie.com/)|(plugin.video.youtube/play)' if match: if channel_id_from_previous_listing: channel_url="https://youtube.com/channel/{0}".format(channel_id_from_previous_listing) yt=ClassYoutube(youtube_url) url_type,id_=yt.get_video_channel_user_or_playlist_id_from_url(youtube_url) #log('previous_listing_was_of_type='+repr(previous_listing_was_of_type)) cxm_list.append( (translation(32523) , build_script("listRelatedVideo", youtube_url, title, 'related') ) ) if previous_listing_was_of_type=='channel': #cxm_list.append( (translation(32528) , build_script("listRelatedVideo", channel_url, title, 'playlists') ) ) #Playlists in this channel pass elif previous_listing_was_of_type=='playlist': cxm_list.append( (translation(32522) , build_script("listRelatedVideo", youtube_url, title, 'channel') ) ) elif previous_listing_was_of_type=='playlists': pass else: if url_type=='video': video_id=id_ cxm_list.append( (translation(32522) , build_script("listRelatedVideo", youtube_url, title, 'channel') ) ) cxm_list.append( (translation(32525) , build_script("listRelatedVideo", youtube_url, title, 'links_in_description') ) ) elif url_type=='channel': channel_id_from_url=id_ cxm_list.append( (translation(32522) , build_script("listRelatedVideo", youtube_url, title, 'channel') ) ) elif url_type=='playlist': #playlist_id_from_url=id_ if not previous_listing_was_of_type=='playlists': cxm_list.append( (translation(32526) , build_script("listRelatedVideo", youtube_url, title, 'playlist') ) ) #Show playlist (YouTube) #elif url_type=='user': # cxm_list.append( (translation(32523) , build_script("listRelatedVideo", youtube_url, title, 'related') ) ) cxm_list.append( (translation(32529) , build_script("listRelatedVideo", youtube_url, title, 'search') ) ) if channel_id_from_previous_listing: if not previous_listing_was_of_type=='playlists': cxm_list.append( (translation(32528) , build_script("listRelatedVideo", channel_url, title, 'playlists') ) ) #Playlists in this channel cxm_list.append( ("{0}{1}".format(translation(32527),channel_name), build_script("addSubreddit", "{0}[{1}]".format(channel_url,channel_name)) ) ) #Search reddit for this video ID" #url+= "/search.json?q=" + urllib.quote_plus(search_string) if video_id: cxm_list.append( (translation(32524) , build_script("listSubReddit", assemble_reddit_filter_string(video_id,'','',''), 'Search') ) ) except Exception as e: log(' EXCEPTION build_youtube_context_menu_entries():'+str(e)) return cxm_list
def load_subreddits_file_into_a_listitem(self): from utils import compose_list_item from reddit import subreddit_entry_to_listitem entries=[] listing=[] if os.path.exists(self.subreddits_file): with open(self.subreddits_file, 'r') as fh: content = fh.read() fh.close() spl = content.split('\n') for i in range(0, len(spl), 1): if spl[i]: subreddit = spl[i].strip() entries.append(subreddit ) entries.sort() #log( ' entries count ' + str( len( entries) ) ) for subreddit_entry in entries: liz=subreddit_entry_to_listitem(subreddit_entry) liz.setProperty('ACTION_manage_subreddits', build_script('manage_subreddits', subreddit_entry,"","" ) ) listing.append(liz) li_setting=compose_list_item( translation(32029), "History", "icon_search_subreddit.png", "script", build_script("listRecentlyPlayed", '', '') ) listing.append(li_setting) li_search=compose_list_item( translation(32016), translation(32016), "icon_search_subreddit.png", "script", build_script("search", '', '') ) listing.append(li_search) li_setting=compose_list_item( translation(32018), "Program", "icon_settings.png", "script", "Addon.OpenSettings(%s)"%addonID ) listing.append(li_setting) return listing
def build_reddit_context_menu_entries(url): from domains import ClassReddit cxm_list=[] match=re.compile( ClassReddit.regex, re.I).findall( url ) if match: subreddit=ClassReddit.get_video_id(url) if subreddit: # and cxm_show_by_subreddit: Go to r/{subreddit} cxm_list.append( (translation(32508).format(subreddit=subreddit), build_script("listSubReddit", assemble_reddit_filter_string("",subreddit), subreddit) ) ) return cxm_list
def build_reddit_search_context_menu_entries(hasmultiplesubreddit,subreddit,link_url ): cxm_list=[] colored_subreddit_full=colored_subreddit( subreddit ) label_search=translation(32520) parts_of_link_url=urlparse.urlparse(link_url) if cxm_show_search: if GCXM_hasmultiplesubreddit: cxm_list.append( (label_search , build_script("search", '', '') ) ) else: label_search+=' {0}'.format(colored_subreddit_full) cxm_list.append( (label_search , build_script("search", '', subreddit) ) ) #NOTE: can't use the entire link_url because it will work for www.reddit.com but not for oauth.reddit.com part_to_search="{0} {1}".format(parts_of_link_url.path,parts_of_link_url.query) if part_to_search.startswith('/'): part_to_search=part_to_search[1:] #remove starting '/' remove_these_words=['.mp4','.webm','/v/','.jpg','.png'] #mainly to match imgur links where we want to catch the imageID not "imageID.mp4" part_to_search=re.sub('|'.join(re.escape(word) for word in remove_these_words), '', part_to_search) #log('parts to search='+part_to_search) cxm_list.append( (translation(32531) , build_script("listSubReddit", assemble_reddit_filter_string(part_to_search,'','',''), name=translation(32531)) ) ) #"Other posts with this link" return cxm_list
def load_subreddits_file_into_a_listitem(self): from utils import compose_list_item, prettify_reddit_query from reddit import parse_subreddit_entry, assemble_reddit_filter_string entries = [] listing = [] if os.path.exists(self.subreddits_file): with open(self.subreddits_file, 'r') as fh: content = fh.read() fh.close() spl = content.split('\n') for i in range(0, len(spl), 1): if spl[i]: subreddit = spl[i].strip() entries.append(subreddit) entries.sort() #log( ' entries count ' + str( len( entries) ) ) for subreddit_entry in entries: #strip out the alias identifier from the subreddit string retrieved from the file so we can process it. subreddit, alias, shortcut_description = parse_subreddit_entry( subreddit_entry) #log( subreddit + " " + shortcut_description ) reddit_url = assemble_reddit_filter_string("", subreddit, "yes") liz = compose_list_item( alias, "", "", "script", build_script("listSubReddit", reddit_url, prettify_reddit_query(alias))) liz.setProperty( 'ACTION_manage_subreddits', build_script('manage_subreddits', subreddit_entry, "", "")) listing.append(liz) return listing
def play_from_here(self): i = self.gui_listbox.getSelectedPosition() list_item_bs = self.gui_listbox.getListItem(i - 1) post_id_bs = list_item_bs.getProperty('post_id') #replace or put &after=post_id to the reddit query so that the returned posts will be "&after=post_id" rq = self.reddit_query_of_this_gui.split('&after=')[0] #log(' rq= %s ' %( rq ) ) if post_id_bs: rq = rq + '&after=' + post_id_bs #log(' rq= %s ' %( rq ) ) action = build_script('autoPlay', rq, '', '') log(' PLAY_FROM_HERE %d %s %s' % (i, post_id_bs, list_item_bs.getLabel())) self.busy_execute_sleep(action, 10000, False)
def addLink(title, title_line2, iconimage, previewimage,preview_w,preview_h,domain, description, credate, reddit_says_is_video, commentsUrl, subreddit, link_url, over_18, posted_by="", num_comments=0,post_id=''): from utils import ret_info_type_icon, build_script,colored_subreddit #from reddit import assemble_reddit_filter_string from domains import parse_reddit_link, sitesBase from ContextMenus import build_context_menu_entries preview_ar=0.0 DirectoryItem_url='' if over_18: mpaa="R" title_line2 = "[COLOR red][NSFW][/COLOR] "+title_line2 else: mpaa="" post_title=title if len(post_title) > 100 or description: il_description='[B]%s[/B][CR][CR]%s' %( post_title, description ) else: il_description='' il={ "title": post_title, "plot": il_description, "Aired": credate, "mpaa": mpaa, "Genre": "r/"+subreddit, "studio": domain, "director": posted_by } #, "duration": 1271} (duration uses seconds for titan skin liz=xbmcgui.ListItem(label=post_title ,label2=title_line2 ,path='') #path not used by gui. if preview_w==0 or preview_h==0: preview_ar=0.0 else: preview_ar=float(preview_w) / preview_h #log(' preview_ar:'+repr(preview_ar)) if preview_ar>1.4: #this triggers whether the (control id 203) will show up #the gui checks for this: String.IsEmpty(Container(55).ListItem.Property(preview_ar)) to show/hide a wider preview # this is overridden if the post is an album. liz.setProperty('preview_ar', str(preview_ar) ) # -- $INFO[ListItem.property(preview_ar)] #text_below_image=il_description+title_line2 + colored_subreddit( posted_by, 'dimgrey',False ) text_below_image='[B]%s[/B][CR]%s %s[CR]%s' %( post_title, title_line2, colored_subreddit( ' by '+posted_by, 'dimgrey',False ), description ) liz.setInfo(type='video', infoLabels={"plotoutline": text_below_image, } ) #makes the gui use a control that allows the user scroll tall image if preview_ar<0.3: liz.setProperty('very_tall_image', str(preview_ar) ) # -- IsEmpty(Container(55).ListItem.Property(very_tall_image)) elif preview_ar<0.5: liz.setProperty('tall_image', str(preview_ar) ) # -- IsEmpty(Container(55).ListItem.Property(tall_image)) if num_comments > 0 or description: liz.setProperty('comments_action', build_script('listLinksInComment', commentsUrl ) ) liz.setProperty('link_url', link_url ) liz.setInfo(type='video', infoLabels=il) #use clearart to indicate if link is video, album or image. here, we default to unsupported. clearart=ret_info_type_icon('', '') liz.setArt({ "clearart": clearart }) #force all links to ytdl to see if they are playable liz.setProperty('item_type','script') liz.setProperty('onClick_action', build_script('playYTDLVideo', link_url,'',previewimage) ) #liz.setProperty('onClick_action', build_script('playYTDLVideo', link_url,'','') ) #get meta_ogimage_content for links that do not have a preview image if previewimage: needs_preview=False else: if any(site in domain for site in sites_that_will_ban_if_excessive_connections): previewimage=iconimage needs_preview=False else: needs_preview=True #reddit has no thumbnail for this link. please get one ld=parse_reddit_link(link_url,reddit_says_is_video, needs_preview, False, preview_ar ) if previewimage=="": if domain.startswith('self.'): liz.setArt({"thumb": ld.thumb if ld else '', "banner": '' , }) else: liz.setArt({"thumb": iconimage, "banner": ld.poster if ld else '' , }) else: liz.setArt({"thumb": iconimage, "banner":previewimage, }) #log( ' %s' %(domain)) #log( ' reddit thumb[%s] ' %(iconimage )) #log( ' reddit preview[%s] ar=%f %dx%d' %(previewimage, preview_ar, preview_w,preview_h )) #if ld: log( ' new-thumb[%s] poster[%s] ' %( ld.thumb, ld.poster )) if ld: #use clearart to indicate the type of link(video, album, image etc.) clearart=ret_info_type_icon(ld.media_type, ld.link_action, domain ) liz.setArt({ "clearart": clearart }) if iconimage in ["","nsfw", "default"]: iconimage=ld.thumb #we gathered a description from the link if ld.desctiption: liz.setInfo(type='video', infoLabels={'plot': il_description + '[CR]' + ld.desctiption, }) if ld.dictlist: #log('****has album images') #listItem is not json serializable so dictlist_to_listItems() is done in the gui #image_listItems=dictlist_to_listItems(ld.dictlist) liz.setProperty('album_images', json.dumps( ld.dictlist ) ) # dictlist=json.loads(string) #overrride the preview_ar flag. (easier to do this here than have the xml figure it out in <visible> liz.setProperty('preview_ar', None ) #log( liz.getProperty('album_images')) #link_action set in domains.py - parse_reddit_link if ld.link_action == sitesBase.DI_ACTION_PLAYABLE: property_link_type=ld.link_action DirectoryItem_url =ld.playable_url else: property_link_type='script' if ld.link_action=='viewTallImage' : #viewTallImage take different args DirectoryItem_url = build_script(mode=ld.link_action, url=ld.playable_url, name=str(preview_w), type_=str(preview_h) ) else: #log( '****' + repr( ld.dictlist )) DirectoryItem_url = build_script(mode=ld.link_action, url=ld.playable_url, name=post_title , type_=previewimage ) #log(' action %s--%s' %( ld.link_action, DirectoryItem_url) ) liz.setProperty('item_type',property_link_type) liz.setProperty('onClick_action',DirectoryItem_url) else: #unsupported type here: pass #***build context menu*** # convert a list of tuple into a string then set it as a property # in GUI, the string is converted back via ast.literal_eval() and put into listItems liz.setProperty('context_menu', str(build_context_menu_entries(num_comments, commentsUrl, subreddit, domain, link_url, post_id, post_title, posted_by, liz.getProperty('onClick_action'), iconimage )) ) return liz
def display_album_from(dictlist, album_name): from domains import sitesBase from utils import build_script directory_items = [] label = "" for idx, d in enumerate(dictlist): ti = d['li_thumbnailImage'] media_url = d.get('DirectoryItem_url') media_type = d.get('type') media_thumb = d.get('thumb') isPlayable = d.get('isPlayable') #Error Type: <type 'exceptions.TypeError'> cannot concatenate 'str' and 'list' objects log( ' display_album_from list:' + media_url + " " + repr(media_type) ) # ****** don't forget to add "[0]" when using parseDOM parseDOM(div,"img", ret="src")[0] #There is only 1 textbox for Title and description in our custom gui. # I don't know how to achieve this in the xml file so it is done here: # combine title and description without [CR] if label is empty. [B]$INFO[Container(53).ListItem.Label][/B][CR]$INFO[Container(53).ListItem.Plot] # new note: this is how it is done: # $INFO[Container(53).ListItem.Label,[B],[/B][CR]] $INFO[Container(53).ListItem.Plot] #if the infolabel is empty, nothing is printed for that block combined = '[B]' + d['li_label2'] + "[/B][CR]" if d['li_label2'] else "" combined += d['infoLabels'].get('plot') if d['infoLabels'].get( 'plot') else "" d['infoLabels']['plot'] = combined #d['infoLabels']['genre'] = "0,-2000" #d['infoLabels']['year'] = 1998 #log( d['infoLabels'].get('plot') ) liz = xbmcgui.ListItem(label=label, label2=d['li_label2'], iconImage=media_thumb, thumbnailImage=media_thumb) if media_type == sitesBase.TYPE_VIDEO: if isPlayable == 'true': liz.setProperty('item_type', 'playable') liz.setProperty('onClick_action', media_url) else: liz.setProperty('item_type', 'script') liz.setProperty( 'onClick_action', build_script('playYTDLVideo', media_url, '', media_thumb)) liz.setInfo( type='video', infoLabels=d['infoLabels'] ) #this tricks the skin to show the plot. where we stored the picture descriptions #liz.setArt({"thumb": ti, "poster":poster_url, "banner":d['DirectoryItem_url'], "fanart":poster_url, "landscape":d['DirectoryItem_url'] }) liz.setArt({"thumb": ti, "banner": media_url}) directory_items.append(( media_url, liz, False, )) from guis import cGUI #msg=WINDOW.getProperty(url) #WINDOW.clearProperty( url ) #log( ' msg=' + msg ) #<label>$INFO[Window(10000).Property(foox)]</label> #WINDOW.setProperty('view_450_slideshow_title',WINDOW.getProperty(url)) li = [] for di in directory_items: #log( str(di[1] ) ) li.append(di[1]) ui = cGUI('view_450_slideshow.xml', addon_path, defaultSkin='Default', defaultRes='1080i', listing=li, id=53) ui.include_parent_directory_entry = False #ui.title_bar_text=WINDOW.getProperty(url) ui.doModal() del ui
def listSubReddit(url, subreddit_key, type_): from guis import progressBG from utils import post_is_filtered_out, build_script, compose_list_item, xbmc_notify from reddit import reddit_request, has_multiple, assemble_reddit_filter_string global GCXM_hasmultiplesubreddit, GCXM_actual_url_used_to_generate_these_posts, GCXM_reddit_query_of_this_gui, GCXM_hasmultipledomain, GCXM_hasmultipleauthor #the +'s got removed by url conversion title_bar_name = subreddit_key.replace(' ', '+') #log(" title_bar_name %s " %(title_bar_name) ) log("listSubReddit r/%s\n %s" % (title_bar_name, url)) currentUrl = url icon = banner = header = None xbmc_busy() loading_indicator = progressBG('Loading...') loading_indicator.update(0, 'Retrieving ' + subreddit_key) content = reddit_request(url) loading_indicator.update(10, subreddit_key) if not content: xbmc_busy(False) loading_indicator.end( ) #it is important to close xbmcgui.DialogProgressBG return threads = [] q_liz = Queue() #output queue (listitem) content = json.loads(content) #log("query returned %d items " % len(content['data']['children']) ) posts_count = len(content['data']['children']) filtered_out_posts = 0 hms = has_multiple('subreddit', content['data']['children']) if hms == False: #r/random and r/randnsfw returns a random subreddit. we need to use the name of this subreddit for the "next page" link. try: g = content['data']['children'][0]['data']['subreddit'] except ValueError: g = "" except IndexError: xbmc_busy(False) loading_indicator.end( ) #it is important to close xbmcgui.DialogProgressBG xbmc_notify("List Subreddit", translation(32022)) return if g: title_bar_name = g #preserve the &after string so that functions like play slideshow and play all videos can 'play' the correct page # extract the &after string from currentUrl -OR- send it with the 'type' argument when calling this function. currentUrl = assemble_reddit_filter_string('', g) + '&after=' + type_ #put subreddit icon/header in the GUI icon, banner, header = subreddit_icoheader_banner(g) GCXM_hasmultiplesubreddit = hms GCXM_hasmultipledomain = has_multiple('domain', content['data']['children']) GCXM_hasmultipleauthor = has_multiple('author', content['data']['children']) GCXM_actual_url_used_to_generate_these_posts = url GCXM_reddit_query_of_this_gui = currentUrl for idx, entry in enumerate(content['data']['children']): try: #if entry.get('kind')!='t3': # filtered_out_posts+=1 # continue if post_is_filtered_out(entry.get('data')): filtered_out_posts += 1 continue #have threads process each reddit post t = threading.Thread(target=reddit_post_worker, args=(idx, entry, q_liz), name='#t%.2d' % idx) threads.append(t) t.start() except Exception as e: log(" EXCEPTION:=" + str(sys.exc_info()[0]) + " " + str(e)) #check the queue to determine progress break_counter = 0 #to avoid infinite loop expected_listitems = (posts_count - filtered_out_posts) if expected_listitems > 0: loading_indicator.set_tick_total(expected_listitems) last_queue_size = 0 while q_liz.qsize() < expected_listitems: if break_counter >= 100: break #each change in the queue size gets a tick on our progress track if last_queue_size < q_liz.qsize(): items_added = q_liz.qsize() - last_queue_size loading_indicator.tick(items_added) else: break_counter += 1 last_queue_size = q_liz.qsize() xbmc.sleep(100) #wait for all threads to finish before collecting the list items for idx, t in enumerate(threads): #log(' joining %s' %t.getName()) t.join(timeout=20) xbmc_busy(False) #compare the number of entries to the returned results #log( "queue:%d entries:%d" %( q_liz.qsize() , len(content['data']['children'] ) ) ) if q_liz.qsize() != expected_listitems: #some post might be filtered out. log('some threads did not return a listitem') #for t in threads: log('isAlive %s %s' %(t.getName(), repr(t.isAlive()) ) ) #liu=[ qi for qi in sorted(q_liz.queue) ] li = [liz for idx, liz in sorted(q_liz.queue)] #empty the queue. with q_liz.mutex: q_liz.queue.clear() loading_indicator.end() #it is important to close xbmcgui.DialogProgressBG try: #this part makes sure that you load the next page instead of just the first after = "" after = content['data']['after'] if after: if "&after=" in currentUrl: nextUrl = currentUrl[:currentUrl.find("&after=" )] + "&after=" + after else: nextUrl = currentUrl + "&after=" + after liz = compose_list_item( translation(32004), "", "DefaultFolderNextSquare.png", "script", build_script("listSubReddit", nextUrl, title_bar_name, after)) #for items at the bottom left corner liz.setArt({"clearart": "DefaultFolderNextSquare.png"}) liz.setInfo(type='video', infoLabels={"Studio": translation(32004)}) liz.setProperty('link_url', nextUrl) li.append(liz) except Exception as e: log(" EXCEPTzION:=" + str(sys.exc_info()[0]) + " " + str(e)) xbmc_busy(False) title_bar_name = urllib.unquote_plus(title_bar_name) ui = skin_launcher('listSubReddit', title_bar_name=title_bar_name, listing=li, subreddits_file=subredditsFile, currentUrl=currentUrl, icon=icon, banner=banner, header=header) ui.doModal() del ui
def build_context_menu_entries(num_comments,commentsUrl, subreddit, domain, link_url, post_id, post_title, posted_by, onClick_action, thumbnail): s=truncate(subreddit,15) #crop long subreddit names in context menu colored_subreddit_short=colored_subreddit( s ) colored_domain_full=colored_subreddit( domain, 'tan',False ) post_title_short=truncate(post_title,15) post_author=truncate(posted_by,15) label_view_comments=translation(32504)+' ({0})'.format(num_comments) label_more_by_author=translation(32506).format(author=post_author) label_goto_subreddit=translation(32508).format(subreddit=subreddit) label_goto_domain=translation(32510).format(domain=domain) label_autoplay_after=translation(32513)+' '+colored_subreddit( post_title_short, 'gray',False ) label_add_to_shortcuts=translation(32516).format(subreddit=subreddit) cxm_list=[] cxm_list.extend( build_link_in_browser_context_menu_entries(link_url) ) cxm_list.extend( build_open_browser_to_pair_context_menu_entries(link_url) ) if cxm_show_comments: cxm_list.append((label_view_comments , build_script('listLinksInComment', commentsUrl ) )) #more by author if GCXM_hasmultipleauthor and cxm_show_by_author: cxm_list.append( (label_more_by_author, build_script("listSubReddit", assemble_reddit_filter_string("","/user/"+posted_by+'/submitted'), posted_by) ) ) #more from r/subreddit if GCXM_hasmultiplesubreddit and cxm_show_by_subreddit: cxm_list.append( (label_goto_subreddit, build_script("listSubReddit", assemble_reddit_filter_string("",subreddit), subreddit) ) ) #more from domain if GCXM_hasmultipledomain and cxm_show_by_domain: cxm_list.append( ( label_goto_domain, build_script("listSubReddit", assemble_reddit_filter_string("",'','',domain), domain) ) ) #more random (no setting to disable this) if any(x in GCXM_actual_url_used_to_generate_these_posts.lower() for x in ['/random','/randnsfw']): #if '/rand' in GCXM_actual_url_used_to_generate_these_posts: cxm_list.append( (translation(32511) +' random', build_script('listSubReddit', GCXM_actual_url_used_to_generate_these_posts)) , ) #Reload #Autoplay all #Autoplay after post_title #slideshow if cxm_show_autoplay: cxm_list.extend( [ (translation(32512) , build_script('autoPlay', GCXM_reddit_query_of_this_gui)), (label_autoplay_after , build_script('autoPlay', GCXM_reddit_query_of_this_gui.split('&after=')[0]+'&after='+post_id)), ]) if cxm_show_slideshow: cxm_list.append( (translation(32514) , build_script('autoSlideshow', GCXM_reddit_query_of_this_gui)) ) #Add %s to shortcuts if not subreddit_in_favorites(subreddit) and cxm_show_add_shortcuts: cxm_list.append( (label_add_to_shortcuts, build_script("addSubreddit", subreddit) ) ) #Add to subreddit/domain filter if cxm_show_filter: cxm_list.append( (translation(32519).format(colored_subreddit_short), build_script("addtoFilter", subreddit,'','subreddit') ) ) cxm_list.append( (translation(32519).format(colored_domain_full) , build_script("addtoFilter", domain,'','domain') ) ) #Search / Other posts with this link cxm_list.extend( build_reddit_search_context_menu_entries(GCXM_hasmultiplesubreddit,subreddit,link_url) ) if cxm_show_youtube_items: cxm_list.extend( build_youtube_context_menu_entries('', link_url, video_id=None, title=post_title )) cxm_list.extend( build_add_to_favourites_context_menu_entry(title=post_title, onClick_action=onClick_action,thumbnail=thumbnail) ) return cxm_list
def reddit_comment_worker(idx, h, q_out, submitter): from domains import parse_reddit_link, sitesBase from utils import format_description, ret_info_type_icon, build_script # h[0]=score, # h[1]=link_desc, # h[2]=link_http, # h[3]=post_text, # h[4]=post_html, # h[5]=d, # h[6]="t1", # h[7]=author, # h[8]=created_utc, try: #log(str(i)+" score:"+ str(h[0]).zfill(5)+" "+ h[1] +'|'+ h[3] ) comment_score = h[0] #log("score %d < %d (%s)" %(comment_score,int_CommentTreshold, CommentTreshold) ) link_url = h[2] desc100 = h[3].replace( '\n', ' ')[0:100] #first 100 characters of description kind = h[ 6] #reddit uses t1 for user comments and t3 for OP text of the post. like a poster describing the post. d = h[5] #depth of the comment tab = " " * d if d > 0 else "-" author = h[7] if link_url.startswith('/r/'): domain = 'subreddit' elif link_url.startswith('/u/'): domain = 'redditor' elif link_url.startswith( '#' ): #don't know what these are. they are to be replaced with image on reddit domain = link_url else: from urlparse import urlparse domain = '{uri.netloc}'.format(uri=urlparse(link_url)) #log( ' %s TITLE:%s... link[%s]' % ( str(comment_score).zfill(4), desc100.ljust(20)[:20],link_url ) ) if link_url: log(' comment %s TITLE:%s... link[%s]' % (str(d).zfill(3), desc100.ljust(20)[:20], link_url)) ld = parse_reddit_link(link_url=link_url, assume_is_video=False, needs_preview=True, get_playable_url=True) if author == submitter: #add a submitter tag author = "[COLOR cadetblue][B]%s[/B][/COLOR][S]" % author else: author = "[COLOR cadetblue]%s[/COLOR]" % author if kind == 't1': t_prepend = r"%s" % (tab) elif kind == 't3': t_prepend = r"[B]Post text:[/B]" plot = format_description(h[3]) liz = xbmcgui.ListItem(label=t_prepend + author + ': ' + desc100, label2="") liz.setInfo(type="Video", infoLabels={ "Title": h[1], "plot": plot, "studio": domain, "votes": str(comment_score), "director": author }) #force all links to ytdl to see if it can be played if link_url: #log(' there is a link from %s' %domain) if not ld: #log(' link is not supported ') liz.setProperty('item_type', 'script') liz.setProperty('onClick_action', build_script('playYTDLVideo', link_url)) plot = "[COLOR greenyellow][%s] %s" % ('?', plot) + "[/COLOR]" liz.setLabel(tab + plot) liz.setProperty( 'link_url', link_url) #just used as text at bottom of the screen clearart = ret_info_type_icon('', '') liz.setArt({"clearart": clearart}) if ld: #use clearart to indicate if link is video, album or image. here, we default to unsupported. #clearart=ret_info_type_icon(setInfo_type, mode_type) clearart = ret_info_type_icon(ld.media_type, ld.link_action, domain) liz.setArt({"clearart": clearart}) if ld.link_action == sitesBase.DI_ACTION_PLAYABLE: property_link_type = ld.link_action DirectoryItem_url = ld.playable_url else: property_link_type = 'script' DirectoryItem_url = build_script(mode=ld.link_action, url=ld.playable_url, name='', type_='') #(score, link_desc, link_http, post_text, post_html, d, ) #list_item_name=str(h[0]).zfill(3) #log(str(i)+" score:"+ str(h[0]).zfill(5)+" desc["+ h[1] +']|text:['+ h[3]+']' +link_url + ' videoID['+videoID+']' + 'playable:'+ setProperty_IsPlayable ) #log( h[4] + ' -- videoID['+videoID+']' ) #log("sss:"+ supportedPluginUrl ) #fl= re.compile('\[(.*?)\]\(.*?\)',re.IGNORECASE) #match '[...](...)' with a capture group inside the []'s as capturegroup1 #result = fl.sub(r"[B]\1[/B]", h[3]) #replace the match with [B] [/B] with capturegroup1 in the middle of the [B]'s #turn link green if DirectoryItem_url: plot = "[COLOR greenyellow][%s] %s" % (domain, plot) + "[/COLOR]" liz.setLabel(tab + plot) #liz.setArt({"thumb": thumb_url, "poster":thumb_url, "banner":thumb_url, "fanart":thumb_url, "landscape":thumb_url }) liz.setArt({"thumb": ld.poster}) liz.setProperty('item_type', property_link_type) #script or playable liz.setProperty( 'onClick_action', DirectoryItem_url) #<-- needed by the xml gui skin liz.setProperty( 'link_url', link_url) #just used as text at bottom of the screen #liz.setPath(DirectoryItem_url) #directory_items.append( (DirectoryItem_url, liz,) ) else: #this section are for comments that have no links or unsupported links #if not ShowOnlyCommentsWithlink: #directory_items.append( ("", liz, ) ) pass #END section are for comments that have no links or unsupported links q_out.put([idx, liz]) except Exception as e: log('EXCEPTION comments_worker' + str(e))
def onClick(self, controlID): from utils import build_script, assemble_reddit_filter_string #log( ' clicked on control id %d' %controlID ) listbox_selected_item=self.gui_listbox.getSelectedItem() subreddits_selected_item=self.subreddits_listbox.getSelectedItem() if controlID == self.main_control_id: self.gui_listbox_SelectedPosition = self.gui_listbox.getSelectedPosition() #item = self.gui_listbox.getSelectedItem() if self.include_parent_directory_entry and self.gui_listbox_SelectedPosition == 0: self.close() #include_parent_directory_entry means that we've added a ".." as the first item on the list onInit #name = item.getLabel() try:di_url=listbox_selected_item.getProperty('onClick_action') #this property is created when assembling the kwargs.get("listing") for this class except:di_url="" item_type=listbox_selected_item.getProperty('item_type').lower() log( " clicked on %d IsPlayable=%s url=%s " %( self.gui_listbox_SelectedPosition, item_type, di_url ) ) if item_type=='playable': #a big thank you to spoyser (http://forum.kodi.tv/member.php?action=profile&uid=103929) for this help pl = xbmc.PlayList(xbmc.PLAYLIST_VIDEO) pl.clear() pl.add(di_url, listbox_selected_item) xbmc.Player().play(pl, windowed=False) #self.close() elif item_type=='script': #"script.web.viewer, http://m.reddit.com/login" #log( di_url ) #if user clicked on 'next' we close this screen and load the next page. if 'mode=listSubReddit' in di_url: self.busy_execute_sleep(di_url,500,True ) else: self.busy_execute_sleep(di_url,5000,False ) #modes=['listImgurAlbum','viewImage','listLinksInComment','playTumblr','playInstagram','playFlickr' ] #if any(x in di_url for x in modes): #viewImage uses xml gui, xbmc.Player() sometimes report an error after 'play'-ing # use RunPlugin to avoid this issue #xbmcplugin.setResolvedUrl(self.pluginhandle, True, item) #xbmc.executebuiltin('RunPlugin(%s)' %di_url ) #works for showing image(with gui) but doesn't work for videos(Attempt to use invalid handle -1) #xbmc.executebuiltin('RunScript(%s)' %di_url ) #nothing works #xbmc.executebuiltin('RunAddon(plugin.video.reddit_viewer)' ) #does nothing. adding the parameter produces error(unknown plugin) #xbmc.executebuiltin('ActivateWindow(video,%s)' %di_url ) #Can't find window video ...#Activate/ReplaceWindow called with invalid destination window: video elif controlID == self.SUBREDDITS_LIST: di_url=subreddits_selected_item.getProperty('onClick_action') #this property was created in load_subreddits_file_into_a_listitem self.busy_execute_sleep(di_url ) elif controlID == self.BTN_GOTO_SUBREDDIT: goto_subreddit_action=listbox_selected_item.getProperty('goto_subreddit_action') self.busy_execute_sleep(goto_subreddit_action) elif controlID == self.BTN_ZOOM_N_SLIDE: action=listbox_selected_item.getProperty('zoom_n_slide_action') self.busy_execute_sleep(action, 50,False) elif controlID == self.BTN_PLAY_ALL: #action='RunAddon(script.reddit.reader,mode=autoPlay&url=%s&name=&type=)' % self.reddit_query_of_this_gui #build_script( mode, url, name="", type="", script_to_call=addonID) action=build_script('autoPlay', self.reddit_query_of_this_gui,'','') #log(' PLAY_ALL '+ action) self.busy_execute_sleep(action, 10000,False) elif controlID == self.BTN_PLAY_FROM_HERE: #get the post_id before the selected item. (not the selected items post_id) i =self.gui_listbox.getSelectedPosition() list_item_bs = self.gui_listbox.getListItem(i-1) post_id_bs = list_item_bs.getProperty('post_id') #replace or put &after=post_id to the reddit query so that the returned posts will be "&after=post_id" rq=self.reddit_query_of_this_gui.split('&after=')[0] #log(' rq= %s ' %( rq ) ) if post_id_bs: rq = rq + '&after=' + post_id_bs #log(' rq= %s ' %( rq ) ) action=build_script('autoPlay', rq,'','') log(' PLAY_FROM_HERE %d %s %s' %( i, post_id_bs, list_item_bs.getLabel() ) ) self.busy_execute_sleep(action, 10000,False) elif controlID == self.BTN_SLIDESHOW: #action='RunAddon(script.reddit.reader,mode=autoPlay&url=%s&name=&type=)' % self.reddit_query_of_this_gui #build_script( mode, url, name="", type="", script_to_call=addonID) action=build_script('autoSlideshow', self.reddit_query_of_this_gui,'','') log(' SLIDESHOW '+ action) self.busy_execute_sleep(action, 1000,False) elif controlID == self.BTN_READ_HTML: #action='RunAddon(script.reddit.reader,mode=autoPlay&url=%s&name=&type=)' % self.reddit_query_of_this_gui #build_script( mode, url, name="", type="", script_to_call=addonID) #action=build_script('autoSlideshow', self.reddit_query_of_this_gui,'','') link=listbox_selected_item.getProperty('link_url') action=build_script('readHTML', link,'','') log(' READ_HTML '+ action) self.busy_execute_sleep(action, 1000,False) elif controlID == self.BTN_COMMENTS: action=listbox_selected_item.getProperty('comments_action') log(' BTN_COMMENTS '+ action) if action: #if there are no comments, the comments_action property is not created for this listitem self.busy_execute_sleep(action,3000,False ) elif controlID == self.BTN_SEARCH: from default import translation #this https://www.reddit.com/r/Art/.json?&nsfw:no+&limit=10 #becomes https://www.reddit.com/r/Art/search.json?&nsfw:no+&limit=10&q=SEARCHTERM&restrict_sr=on&sort=relevance&t=all pos=self.reddit_query_of_this_gui.find('/.json') if pos != -1 and pos > 22: pos+=1 #insert 'search' between '/' and '.json' search_query=self.reddit_query_of_this_gui[:pos] + 'search' + self.reddit_query_of_this_gui[pos:] keyboard = xbmc.Keyboard('', translation(32073)) keyboard.doModal() if keyboard.isConfirmed() and keyboard.getText(): search_text=keyboard.getText() #restrict_sr = limit result to subreddit #sort & t not changeable for now search_query=search_query+'&q=' + urllib.unquote_plus(search_text) + '&restrict_sr=on&sort=relevance&t=all' action=build_script("listSubReddit", search_query,'Search Result' ) log(' BTN_SEARCH '+ action) if action: self.busy_execute_sleep(action,3000,False ) elif controlID == self.BTN_RELOAD: #log( self.reddit_query_of_this_gui) #<-- r/random will return a random subredddit. #actual_url_ will tell us whether r/random was used to generate this list actual_query_of_this_gui=self.getProperty('actual_url_used_to_generate_these_posts') action=build_script("listSubReddit", actual_query_of_this_gui ) log(' BTN_RELOAD '+ action) if action: self.busy_execute_sleep(action,3000,False )
def build_open_browser_to_pair_context_menu_entries(url): cxm_list=[] lcase_url=url.lower() if "openload.co" in lcase_url: pairing_url="https://olpair.com" if "thevideo.me" in lcase_url: pairing_url="https://thevideo.me/pair" if cxm_show_open_browser: cxm_list.append(("Go to [B][COLOR=cyan]{0}[/COLOR][/B]".format(pairing_url), build_script('openBrowser', pairing_url) )) return cxm_list
def subreddit_entry_to_listitem(subreddit_entry): from utils import compose_list_item, build_script, xstr, prettify_reddit_query addtl_subr_info={} nsfw=False icon=banner=header=public_description=display_name=override_header_image=None header_ar=0 addtl_subr_info=ret_sub_info(subreddit_entry) #strip out the alias identifier from the subreddit string retrieved from the file so we can process it. entry_type, subreddit, alias, shortcut_description=parse_subreddit_entry(subreddit_entry) icon=default_icon=ret_settings_type_default_icon(entry_type) pretty_label=prettify_reddit_query(alias) pretty_label=pretty_label.replace('+',' + ') if addtl_subr_info: icon=addtl_subr_info.get('icon_img') banner=addtl_subr_info.get('banner_img') #rectangular shape header=addtl_subr_info.get('header_img') #square shape from bannerTvImageUrl header_ar=img_ar(addtl_subr_info.get('header_size')) if (header_ar > 8) and (not icon): #some header_img are very wide. this is to check and override the icon display in the gui override_header_image=header banner=header public_description=xstr( addtl_subr_info.get('public_description','')) display_name=xstr(addtl_subr_info.get('display_name','')) #log('{} icon={} header={} banner={}'.format( subreddit, repr(icon), repr(header), repr(banner) )) if entry_type=='link': #<-- added new ability to have youtube channels as a shortcut on the main screen #here, the subreddit variable contains a url. we made sure that it points to a youtube channel(ContextMenus.py). that way, there is no need to specify 'channel' when calling listRelatedVideo liz = compose_list_item( pretty_label, entry_type, "", "script", build_script("listRelatedVideo",subreddit,alias) ) else: #domain, subreddit, combined, search, multireddit reddit_url=assemble_reddit_filter_string("",subreddit, "yes") if entry_type=='domain': #remove the identifier that this setting is a domain pretty_label=re.findall(r'(?::|\/domain\/)(.+)',subreddit)[0] if subreddit.lower() in ["all","popular"]: liz = compose_list_item( pretty_label, entry_type, "", "script", build_script("listSubReddit",reddit_url,alias) ) else: if addtl_subr_info: #if we have additional info about this subreddit #log(repr(addtl_subr_info)) #title=addtl_subr_info.get('title','')+'\n' #display_name=xstr(addtl_subr_info.get('display_name','')) #if samealphabetic( title, display_name): title='' #header_title=xstr(addtl_subr_info.get('header_title','')) #in reddit_viewer, title, header_title and public_description is shown as plot nsfw=addtl_subr_info.get('over18') icon=next((item for item in [icon,banner,header] if item ), '') or default_icon #picks the first item that is not None #icon=icon or default_icon #log( pretty_label + ' icon=' + icon + ' nsfw='+repr(nsfw)) liz = compose_list_item( pretty_label, entry_type, "", "script", build_script("listSubReddit",reddit_url,alias) ) else: liz = compose_list_item( pretty_label, entry_type, "", "script", build_script("listSubReddit",reddit_url,alias) ) liz.setArt({ "thumb": icon, "banner":banner, "fanart":override_header_image }) liz.setInfo('video', {"Title":display_name, "plot":public_description} ) if nsfw: liz.setProperty('nsfw', 'true' ) return liz
def build_context_menu_entries(num_comments, commentsUrl, subreddit, domain, link_url, post_id, post_title, posted_by): from reddit import assemble_reddit_filter_string, subreddit_in_favorites #, this_is_a_user_saved_list from utils import colored_subreddit, build_script, truncate s = truncate(subreddit, 15) #crop long subreddit names in context menu colored_subreddit_short = colored_subreddit(s) colored_subreddit_full = colored_subreddit(subreddit) colored_domain_full = colored_subreddit(domain, 'tan', False) post_title_short = truncate(post_title, 15) post_author = truncate(posted_by, 15) label_view_comments = translation(32050) + ' ({})'.format(num_comments) label_goto_subreddit = translation(32051) + ' {}'.format( colored_subreddit_full) label_goto_domain = translation(32053) + ' {}'.format(colored_domain_full) label_search = translation(32052) label_autoplay_after = translation(32055) + ' ' + colored_subreddit( post_title_short, 'gray', False) label_more_by_author = translation(32049) + ' ' + colored_subreddit( post_author, 'gray', False) cxm_list = [ ('html to text', build_script('readHTML', link_url)), (label_view_comments, build_script('listLinksInComment', commentsUrl)), ] #more by author if GCXM_hasmultipleauthor: cxm_list.append((label_more_by_author, build_script( "listSubReddit", assemble_reddit_filter_string( "", "/user/" + posted_by + '/submitted'), posted_by))) #more from r/subreddit if GCXM_hasmultiplesubreddit: cxm_list.append( (label_goto_subreddit, build_script("listSubReddit", assemble_reddit_filter_string("", subreddit), subreddit))) #more from domain if GCXM_hasmultipledomain: cxm_list.append( (label_goto_domain, build_script("listSubReddit", assemble_reddit_filter_string("", '', '', domain), domain))) #more random if any(x in GCXM_actual_url_used_to_generate_these_posts.lower() for x in ['/random', '/randnsfw'] ): #if '/rand' in GCXM_actual_url_used_to_generate_these_posts: cxm_list.append( (translation(32053) + ' random', build_script('listSubReddit', GCXM_actual_url_used_to_generate_these_posts)), ) #Reload #Autoplay all #Autoplay after post_title #slideshow cxm_list.extend([ (translation(32054), build_script('autoPlay', GCXM_reddit_query_of_this_gui)), (label_autoplay_after, build_script( 'autoPlay', GCXM_reddit_query_of_this_gui.split('&after=')[0] + '&after=' + post_id)), (translation(32048), build_script('autoSlideshow', GCXM_reddit_query_of_this_gui)), ]) #Add %s to shortcuts if not subreddit_in_favorites(subreddit): cxm_list.append((translation(32056) % colored_subreddit_short, build_script("addSubreddit", subreddit))) #Add to subreddit/domain filter cxm_list.append((translation(32057) % colored_subreddit_short, build_script("addtoFilter", subreddit, '', 'subreddit'))) cxm_list.append((translation(32057) % colored_domain_full, build_script("addtoFilter", domain, '', 'domain'))) #Search if GCXM_hasmultiplesubreddit: cxm_list.append((label_search, build_script("search", '', ''))) else: label_search += ' {}'.format(colored_subreddit_full) cxm_list.append((label_search, build_script("search", '', subreddit))) return cxm_list
def listRecentlyPlayed(url,name,type_): from utils import db_getLastPlayedVideos,build_script,ret_info_type_icon,truncate_middle,pretty_datediff_wrap from domains import parse_reddit_link,sitesBase from ContextMenus import build_youtube_context_menu_entries,build_reddit_search_context_menu_entries recently_played_links=db_getLastPlayedVideos() directory_items=[] for idx, recently_played_tuple in enumerate(recently_played_links): #log(repr(recently_played_tuple)) last_played, recently_played_url=recently_played_tuple pretty_date=pretty_datediff_wrap(last_played,use_utc_as_base=False) #log("---{0} {1}".format(pretty_date, last_played ) ) parsed_web_url=parse_web_url_from(recently_played_url) #grabs the (youtube) url from plugin://plugin.video... #log('recent{0}:{1}'.format(idx, recently_played_url)) if not parsed_web_url: log(' listRecentlyPlayed skipping:{0}'.format(recently_played_url)) continue link_components=urlparse.urlparse( parsed_web_url ) domain=link_components.netloc label=parsed_web_url #recently_played_url.split("|", 1)[0] #remove |Useragent:... liz=xbmcgui.ListItem(label=truncate_middle(label, 110), label2=pretty_date ) liz.setInfo( type="Video", infoLabels={ "Title": parsed_web_url, "plot": recently_played_url, "studio": domain } ) ld=parse_reddit_link(link_url=parsed_web_url, assume_is_video=True, needs_preview=False ) if ld: #use clearart to indicate if link is video, album or image. here, we default to unsupported. #clearart=ret_info_type_icon(setInfo_type, mode_type) clearart=ret_info_type_icon(ld.media_type, ld.link_action, domain ) liz.setArt({ "clearart": clearart }) if ld.link_action == sitesBase.DI_ACTION_PLAYABLE: property_link_type=ld.link_action DirectoryItem_url =ld.playable_url else: property_link_type='script' DirectoryItem_url = build_script(mode=ld.link_action, url=ld.playable_url, name='' , type_='' ) if DirectoryItem_url: #log(DirectoryItem_url) liz.setArt({"thumb": ld.thumb,"banner":ld.poster }) liz.setProperty('item_type',property_link_type) #script or playable liz.setProperty('onClick_action', DirectoryItem_url) #<-- needed by the xml gui skin liz.setProperty('link_url', recently_played_url ) #just used as text at bottom of the screen #liz.setPath(DirectoryItem_url) context_menu_list=[] context_menu_list.extend(build_youtube_context_menu_entries(previous_listing_was_of_type='',youtube_url=parsed_web_url,video_id=None)) context_menu_list.extend(build_reddit_search_context_menu_entries(False,'',parsed_web_url) ) #context_menu_list.extend(build_reddit_context_menu_entries(link_url)) liz.setProperty('context_menu', str(context_menu_list) ) #directory_items.append( (DirectoryItem_url, liz,) ) else: log("*************not ld*****************") directory_items.append( liz ) #from guis import text_to_links_gui #ui = text_to_links_gui('srr_links_in_text.xml' , addon_path, defaultSkin='Default', defaultRes='1080i', listing=directory_items, title='Recently Played', poster=None) from guis import cGUI ui = cGUI('srr_history_list.xml' , addon_path, defaultSkin='Default', defaultRes='1080i', listing=directory_items, id=55, title='Recently Played') ui.include_parent_directory_entry=False ui.doModal() del ui
def listSubReddit(url, subreddit_key, type_): from guis import progressBG from utils import post_is_filtered_out, build_script, compose_list_item, xbmc_notify,prettify_reddit_query, set_query_field from reddit import reddit_request, has_multiple, assemble_reddit_filter_string, subreddit_icoheader_banner global GCXM_hasmultiplesubreddit, GCXM_actual_url_used_to_generate_these_posts,GCXM_reddit_query_of_this_gui,GCXM_hasmultipledomain,GCXM_hasmultipleauthor #the +'s got removed by url conversion title_bar_name=subreddit_key.replace(' ','+') if title_bar_name.startswith('?'): title_bar_name=prettify_reddit_query(title_bar_name) #log(" title_bar_name %s " %(title_bar_name) ) log("listSubReddit r/%s\n %s" %(title_bar_name,url) ) currentUrl = url icon=banner=header=None xbmc_busy() loading_indicator=progressBG('Loading...') loading_indicator.update(0,'Retrieving '+subreddit_key) content = reddit_request(url) loading_indicator.update(10,subreddit_key ) if not content: xbmc_busy(False) loading_indicator.end() #it is important to close xbmcgui.DialogProgressBG return threads = [] q_liz = Queue() #output queue (listitem) content = json.loads(content) #log("query returned %d items " % len(content['data']['children']) ) posts_count=len(content['data']['children']) filtered_out_posts=0 hms=has_multiple('subreddit', content['data']['children']) if hms==False: #r/random and r/randnsfw returns a random subreddit. we need to use the name of this subreddit for the "next page" link. try: g=content['data']['children'][0]['data']['subreddit'] except ValueError: g="" except IndexError: xbmc_busy(False) loading_indicator.end() #it is important to close xbmcgui.DialogProgressBG xbmc_notify("List Subreddit",translation(32022)) return if g: title_bar_name=g #preserve the &after string so that functions like play slideshow and play all videos can 'play' the correct page # extract the &after string from currentUrl -OR- send it with the 'type' argument when calling this function. currentUrl=assemble_reddit_filter_string('',g) + '&after=' + type_ #put subreddit icon/header in the GUI icon,banner,header=subreddit_icoheader_banner(g) GCXM_hasmultiplesubreddit=hms GCXM_hasmultipledomain=has_multiple('domain', content['data']['children']) GCXM_hasmultipleauthor=has_multiple('author', content['data']['children']) GCXM_actual_url_used_to_generate_these_posts=url GCXM_reddit_query_of_this_gui=currentUrl for idx, entry in enumerate(content['data']['children']): try: if post_is_filtered_out( entry.get('data') ): filtered_out_posts+=1 continue domain,domain_count=count_links_from_same_domain( entry ) #count how many same domains we're hitting delay=compute_anti_dos_delay(domain,domain_count) #have threads process each reddit post t = threading.Thread(target=reddit_post_worker, args=(idx, entry,q_liz,delay), name='#t%.2d'%idx) threads.append(t) t.start() except Exception as e: log(" EXCEPTION:="+ str( sys.exc_info()[0]) + " " + str(e) ) log( repr(domains_d) ) #check the queue to determine progress break_counter=0 #to avoid infinite loop expected_listitems=(posts_count-filtered_out_posts) if expected_listitems>0: loading_indicator.set_tick_total(expected_listitems) last_queue_size=0 while q_liz.qsize() < expected_listitems: if break_counter>=500: #log('break counter reached limit') break #each change in the queue size gets a tick on our progress track if last_queue_size < q_liz.qsize(): items_added=q_liz.qsize()-last_queue_size loading_indicator.tick(items_added) else: break_counter+=1 last_queue_size=q_liz.qsize() xbmc.sleep(100) #wait for all threads to finish before collecting the list items for idx, t in enumerate(threads): #log(' joining %s' %t.getName()) t.join(timeout=20) #<-- does not seem to work xbmc_busy(False) #compare the number of entries to the returned results #log( "queue:%d entries:%d" %( q_liz.qsize() , len(content['data']['children'] ) ) ) if q_liz.qsize() != expected_listitems: #some post might be filtered out. log('some threads did not return a listitem') #for t in threads: log('isAlive %s %s' %(t.getName(), repr(t.isAlive()) ) ) #liu=[ qi for qi in sorted(q_liz.queue) ] li=[ liz for idx,liz in sorted(q_liz.queue) ] #empty the queue. with q_liz.mutex: q_liz.queue.clear() loading_indicator.end() #it is important to close xbmcgui.DialogProgressBG try: #this part makes sure that you load the next page instead of just the first after=content['data']['after'] o = urlparse.urlparse(currentUrl) current_url_query = urlparse.parse_qs(o.query) count=current_url_query.get('count') if current_url_query.get('count')==None: #firsttime it is none count=itemsPerPage else: #nexttimes it will be kept incremented with itemsPerPage try: count=int(current_url_query.get('count')[0]) + int(itemsPerPage) except ValueError: count=itemsPerPage nextUrl=set_query_field(currentUrl,'count', count, True) #log('$$$ nextUrl: ' +nextUrl) nextUrl=set_query_field(nextUrl, field='after', value=after, replace=True) #(url, field, value, replace=False): #log('$$$currenturl: ' +currentUrl) #log('$$$ nextUrl: ' +nextUrl) liz = compose_list_item( translation(32024), "", "DefaultFolderNextSquare.png", "script", build_script("listSubReddit",nextUrl,title_bar_name,after) ) #for items at the bottom left corner liz.setArt({ "clearart": "DefaultFolderNextSquare.png" }) liz.setInfo(type='video', infoLabels={"Studio":translation(32024)}) liz.setProperty('link_url', nextUrl ) li.append(liz) except Exception as e: log(" EXCEPTzION:="+ str( sys.exc_info()[0]) + " " + str(e) ) xbmc_busy(False) title_bar_name=urllib.unquote_plus(title_bar_name) ui=skin_launcher('listSubReddit', title_bar_name=title_bar_name, listing=li, subreddits_file=subredditsFile, currentUrl=currentUrl, icon=icon, banner=banner, header=header) ui.doModal() del ui
def onClick(self, controlID): from utils import build_script, assemble_reddit_filter_string listbox_selected_item=self.gui_listbox.getSelectedItem() subreddits_selected_item=self.subreddits_listbox.getSelectedItem() if controlID == self.main_control_id: self.gui_listbox_SelectedPosition = self.gui_listbox.getSelectedPosition() if self.include_parent_directory_entry and self.gui_listbox_SelectedPosition == 0: self.close() #include_parent_directory_entry means that we've added a ".." as the first item on the list onInit try:di_url=listbox_selected_item.getProperty('onClick_action') #this property is created when assembling the kwargs.get("listing") for this class except:di_url="" item_type=listbox_selected_item.getProperty('item_type').lower() log( " clicked on %d IsPlayable=%s url=%s " %( self.gui_listbox_SelectedPosition, item_type, di_url ) ) if item_type=='playable': pl = xbmc.PlayList(xbmc.PLAYLIST_VIDEO) pl.clear() pl.add(di_url, listbox_selected_item) xbmc.Player().play(pl, windowed=False) elif item_type=='script': if 'mode=listSubReddit' in di_url: self.busy_execute_sleep(di_url,500,True ) else: self.busy_execute_sleep(di_url,5000,False ) elif controlID == self.SUBREDDITS_LIST: di_url=subreddits_selected_item.getProperty('onClick_action') #this property was created in load_subreddits_file_into_a_listitem self.busy_execute_sleep(di_url ) elif controlID == self.BTN_GOTO_SUBREDDIT: goto_subreddit_action=listbox_selected_item.getProperty('goto_subreddit_action') self.busy_execute_sleep(goto_subreddit_action) elif controlID == self.BTN_ZOOM_N_SLIDE: action=listbox_selected_item.getProperty('zoom_n_slide_action') self.busy_execute_sleep(action, 50,False) elif controlID == self.BTN_PLAY_ALL: action=build_script('autoPlay', self.reddit_query_of_this_gui,'','') self.busy_execute_sleep(action, 10000,False) elif controlID == self.BTN_PLAY_FROM_HERE: i =self.gui_listbox.getSelectedPosition() list_item_bs = self.gui_listbox.getListItem(i-1) post_id_bs = list_item_bs.getProperty('post_id') rq=self.reddit_query_of_this_gui.split('&after=')[0] if post_id_bs: rq = rq + '&after=' + post_id_bs action=build_script('autoPlay', rq,'','') log(' PLAY_FROM_HERE %d %s %s' %( i, post_id_bs, list_item_bs.getLabel() ) ) self.busy_execute_sleep(action, 10000,False) elif controlID == self.BTN_SLIDESHOW: action=build_script('autoSlideshow', self.reddit_query_of_this_gui,'','') log(' SLIDESHOW '+ action) self.busy_execute_sleep(action, 1000,False) elif controlID == self.BTN_READ_HTML: link=listbox_selected_item.getProperty('link_url') action=build_script('readHTML', link,'','') log(' READ_HTML '+ action) self.busy_execute_sleep(action, 1000,False) elif controlID == self.BTN_COMMENTS: action=listbox_selected_item.getProperty('comments_action') log(' BTN_COMMENTS '+ action) if action: self.busy_execute_sleep(action,3000,False ) elif controlID == self.BTN_SEARCH: from default import translation pos=self.reddit_query_of_this_gui.find('/.json') if pos != -1 and pos > 22: pos+=1 #insert 'search' between '/' and '.json' search_query=self.reddit_query_of_this_gui[:pos] + 'search' + self.reddit_query_of_this_gui[pos:] keyboard = xbmc.Keyboard('', translation(32073)) keyboard.doModal() if keyboard.isConfirmed() and keyboard.getText(): search_text=keyboard.getText() search_query=search_query+'&q=' + urllib.unquote_plus(search_text) + '&restrict_sr=on&sort=relevance&t=all' action=build_script("listSubReddit", search_query,'Search Result' ) log(' BTN_SEARCH '+ action) if action: self.busy_execute_sleep(action,3000,False ) elif controlID == self.BTN_RELOAD: actual_query_of_this_gui=self.getProperty('actual_url_used_to_generate_these_posts') action=build_script("listSubReddit", actual_query_of_this_gui ) log(' BTN_RELOAD '+ action) if action: self.busy_execute_sleep(action,3000,False )
def reddit_comment_worker(idx, h, q_out,submitter,delay=0): from domains import parse_reddit_link, sitesBase from utils import format_description, ret_info_type_icon, build_script, is_filtered from ContextMenus import build_youtube_context_menu_entries, build_reddit_context_menu_entries, build_link_in_browser_context_menu_entries, build_open_browser_to_pair_context_menu_entries if delay>0: xbmc.Monitor().waitForAbort( float(delay)/1000 ) #xbmc.sleep(delay) # h[0]=score, # h[1]=link_desc, # h[2]=link_http, # h[3]=post_text, # h[4]=post_html, # h[5]=d, # h[6]="t1", # h[7]=author, # h[8]=created_utc, try: #log(str(i)+" score:"+ str(h[0]).zfill(5)+" "+ h[1] +'|'+ h[3] ) comment_score=h[0] #log("score %d < %d (%s)" %(comment_score,int_CommentTreshold, CommentTreshold) ) link_url=h[2] desc100=h[3].replace('\n',' ')[0:100] #first 100 characters of description kind=h[6] #reddit uses t1 for user comments and t3 for OP text of the post. like a poster describing the post. d=h[5] #depth of the comment tab=" "*d if d>0 else "-" author=h[7] domain='' if link_url.startswith('/r/'): domain='subreddit' elif link_url.startswith('/u/'): domain='redditor' elif link_url.startswith('#'): #some sort of css flair link_url='' else: domain = '{uri.netloc}'.format( uri=urlparse.urlparse( link_url ) ) if link_url: log( ' comment %s TITLE:%s... link[%s]' % ( str(d).zfill(3), desc100.ljust(20)[:20],link_url ) ) ld=parse_reddit_link(link_url=link_url, assume_is_video=False, needs_preview=True, get_playable_url=True ) plot=format_description(h[3]) if author==submitter:#add a submitter tag author="[COLOR cadetblue][B]%s[/B][/COLOR][S]" %author plot="[B][OP][/B] "+plot else: author="[COLOR cadetblue]%s[/COLOR]" %author if kind=='t1': t_prepend=r"%s" %( tab ) elif kind=='t3': t_prepend=r"[B]Post text:[/B]" liz=xbmcgui.ListItem(label=t_prepend + author + ': '+ desc100 , label2="") liz.setInfo( type="Video", infoLabels={ "Title": h[1], "plot": plot, "studio": domain, "votes": str(comment_score), "director": author } ) liz.setProperty('comment_depth',str(d)) liz.setProperty('plot',plot) #cannot retrieve infolabels in the gui. we put 'plot' here too. liz.setProperty('author',author)# and 'author' too. #force all links to ytdl to see if it can be played if link_url: #log(' there is a link from %s' %domain) if not ld: #log(' link is not supported ') liz.setProperty('item_type','script') liz.setProperty('onClick_action', build_script('playYTDLVideo', link_url) ) plot= "[COLOR greenyellow][%s] %s"%('?', plot ) + "[/COLOR]" liz.setLabel(tab+plot) liz.setProperty('link_url', link_url ) #just used as text at bottom of the screen clearart=ret_info_type_icon('', '') liz.setArt({ "clearart": clearart }) if ld: #use clearart to indicate if link is video, album or image. here, we default to unsupported. #clearart=ret_info_type_icon(setInfo_type, mode_type) clearart=ret_info_type_icon(ld.media_type, ld.link_action, domain ) liz.setArt({ "clearart": clearart }) if ld.link_action == sitesBase.DI_ACTION_PLAYABLE: property_link_type=ld.link_action DirectoryItem_url =ld.playable_url else: property_link_type='script' DirectoryItem_url = build_script(mode=ld.link_action, url=ld.playable_url, name='' , type_='' ) #(score, link_desc, link_http, post_text, post_html, d, ) #list_item_name=str(h[0]).zfill(3) #log(str(i)+" score:"+ str(h[0]).zfill(5)+" desc["+ h[1] +']|text:['+ h[3]+']' +link_url + ' videoID['+videoID+']' + 'playable:'+ setProperty_IsPlayable ) #log( h[4] + ' -- videoID['+videoID+']' ) #log("sss:"+ supportedPluginUrl ) #fl= re.compile('\[(.*?)\]\(.*?\)',re.IGNORECASE) #match '[...](...)' with a capture group inside the []'s as capturegroup1 #result = fl.sub(r"[B]\1[/B]", h[3]) #replace the match with [B] [/B] with capturegroup1 in the middle of the [B]'s #turn link green if DirectoryItem_url: plot= "[COLOR greenyellow][%s] %s"%(domain, plot ) + "[/COLOR]" liz.setLabel(tab+plot) #liz.setArt({"thumb": thumb_url, "poster":thumb_url, "banner":thumb_url, "fanart":thumb_url, "landscape":thumb_url }) liz.setArt({"thumb": ld.thumb,"banner":ld.poster }) liz.setProperty('item_type',property_link_type) #script or playable liz.setProperty('onClick_action', DirectoryItem_url) #<-- needed by the xml gui skin liz.setProperty('link_url', link_url ) #just used as text at bottom of the screen #liz.setPath(DirectoryItem_url) context_menu_list=[] context_menu_list.extend(build_youtube_context_menu_entries(previous_listing_was_of_type='',youtube_url=link_url,video_id=None)) context_menu_list.extend(build_reddit_context_menu_entries(link_url)) context_menu_list.extend(build_link_in_browser_context_menu_entries(link_url)) context_menu_list.extend(build_open_browser_to_pair_context_menu_entries(link_url)) liz.setProperty('context_menu', str(context_menu_list) ) #directory_items.append( (DirectoryItem_url, liz,) ) else: #this section are for comments that have no links or unsupported links #if not ShowOnlyCommentsWithlink: #directory_items.append( ("", liz, ) ) pass #END section are for comments that have no links or unsupported links q_out.put( [idx, liz] ) except Exception as e: log('EXCEPTION comments_worker '+ str(e))
def build_add_to_favourites_context_menu_entry(title, onClick_action, thumbnail=None): cxm_list=[] if cxm_show_add_to_favorites: cxm_list.append( (translation(32530) , build_script("addtoKodiFavorites", onClick_action,title,thumbnail) ) ) return cxm_list
def subreddit_entry_to_listitem(subreddit_entry): from utils import compose_list_item, build_script, xstr, prettify_reddit_query addtl_subr_info = {} nsfw = False icon = banner = header = public_description = display_name = override_header_image = None header_ar = 0 addtl_subr_info = ret_sub_info(subreddit_entry) #strip out the alias identifier from the subreddit string retrieved from the file so we can process it. entry_type, subreddit, alias, shortcut_description = parse_subreddit_entry( subreddit_entry) icon = default_icon = ret_settings_type_default_icon(entry_type) pretty_label = prettify_reddit_query(alias) pretty_label = pretty_label.replace('+', ' + ') if addtl_subr_info: icon = addtl_subr_info.get('icon_img') banner = addtl_subr_info.get('banner_img') #rectangular shape header = addtl_subr_info.get( 'header_img') #square shape from bannerTvImageUrl header_ar = img_ar(addtl_subr_info.get('header_size')) if (header_ar > 8) and ( not icon ): #some header_img are very wide. this is to check and override the icon display in the gui override_header_image = header banner = header public_description = xstr(addtl_subr_info.get('public_description', '')) display_name = xstr(addtl_subr_info.get('display_name', '')) #log('{} icon={} header={} banner={}'.format( subreddit, repr(icon), repr(header), repr(banner) )) if entry_type == 'link': #<-- added new ability to have youtube channels as a shortcut on the main screen #here, the subreddit variable contains a url. we made sure that it points to a youtube channel(ContextMenus.py). that way, there is no need to specify 'channel' when calling listRelatedVideo liz = compose_list_item( pretty_label, entry_type, "", "script", build_script("listRelatedVideo", subreddit, alias)) else: #domain, subreddit, combined, search, multireddit reddit_url = assemble_reddit_filter_string("", subreddit, "yes") if entry_type == 'domain': #remove the identifier that this setting is a domain pretty_label = re.findall(r'(?::|\/domain\/)(.+)', subreddit)[0] if subreddit.lower() in ["all", "popular"]: liz = compose_list_item( pretty_label, entry_type, "", "script", build_script("listSubReddit", reddit_url, alias)) else: if addtl_subr_info: #if we have additional info about this subreddit #log(repr(addtl_subr_info)) #title=addtl_subr_info.get('title','')+'\n' #display_name=xstr(addtl_subr_info.get('display_name','')) #if samealphabetic( title, display_name): title='' #header_title=xstr(addtl_subr_info.get('header_title','')) #in reddit_viewer, title, header_title and public_description is shown as plot nsfw = addtl_subr_info.get('over18') icon = next( (item for item in [icon, banner, header] if item), '') or default_icon #picks the first item that is not None #icon=icon or default_icon #log( pretty_label + ' icon=' + icon + ' nsfw='+repr(nsfw)) liz = compose_list_item( pretty_label, entry_type, "", "script", build_script("listSubReddit", reddit_url, alias)) else: liz = compose_list_item( pretty_label, entry_type, "", "script", build_script("listSubReddit", reddit_url, alias)) liz.setArt({ "thumb": icon, "banner": banner, "fanart": override_header_image }) liz.setInfo('video', {"Title": display_name, "plot": public_description}) if nsfw: liz.setProperty('nsfw', 'true') return liz
def addLink(title, title_line2, iconimage, previewimage, preview_w, preview_h, domain, description, credate, reddit_says_is_video, commentsUrl, subreddit, link_url, over_18, posted_by="", num_comments=0, post_id=''): from utils import ret_info_type_icon, build_script, colored_subreddit #from reddit import assemble_reddit_filter_string from domains import parse_reddit_link, sitesBase preview_ar = 0.0 DirectoryItem_url = '' if over_18: mpaa = "R" title_line2 = "[COLOR red][NSFW][/COLOR] " + title_line2 else: mpaa = "" post_title = title if len(post_title) > 100 or description: il_description = '[B]%s[/B][CR][CR]%s' % (post_title, description) else: il_description = '' il = { "title": post_title, "plot": il_description, "Aired": credate, "mpaa": mpaa, "Genre": "r/" + subreddit, "studio": domain, "director": posted_by } #, "duration": 1271} (duration uses seconds for titan skin liz = xbmcgui.ListItem(label=post_title, label2=title_line2, path='') #path not used by gui. if preview_w == 0 or preview_h == 0: preview_ar = 0.0 else: preview_ar = float(preview_w) / preview_h log(' preview_ar:' + repr(preview_ar)) if preview_ar > 1.4: #this triggers whether the (control id 203) will show up #log(' ar and description criteria met') #the gui checks for this: String.IsEmpty(Container(55).ListItem.Property(preview_ar)) to show/hide preview and description liz.setProperty( 'preview_ar', str(preview_ar)) # -- $INFO[ListItem.property(preview_ar)] #text_below_image=il_description+title_line2 + colored_subreddit( posted_by, 'dimgrey',False ) text_below_image = '[B]%s[/B][CR]%s %s[CR]%s' % ( post_title, title_line2, colored_subreddit(' by ' + posted_by, 'dimgrey', False), description) liz.setInfo(type='video', infoLabels={ "plotoutline": text_below_image, }) #makes the gui use a control that allows the user scroll tall image if preview_ar < 0.3: liz.setProperty( 'very_tall_image', str(preview_ar) ) # -- IsEmpty(Container(55).ListItem.Property(very_tall_image)) elif preview_ar < 0.5: liz.setProperty( 'tall_image', str(preview_ar) ) # -- IsEmpty(Container(55).ListItem.Property(tall_image)) if num_comments > 0 or description: liz.setProperty('comments_action', build_script('listLinksInComment', commentsUrl)) liz.setProperty('link_url', link_url) liz.setInfo(type='video', infoLabels=il) #use clearart to indicate if link is video, album or image. here, we default to unsupported. clearart = ret_info_type_icon('', '') liz.setArt({"clearart": clearart}) #force all links to ytdl to see if they are playable liz.setProperty('item_type', 'script') liz.setProperty('onClick_action', build_script('playYTDLVideo', link_url, '', previewimage)) #***build context menu*** # convert a list of tuple into a string then set it as a property # in GUI, the string is converted back via ast.literal_eval() and put into listItems liz.setProperty( 'context_menu', str( build_context_menu_entries(num_comments, commentsUrl, subreddit, domain, link_url, post_id, post_title, posted_by))) if previewimage: needs_preview = False else: needs_preview = True #reddit has no thumbnail for this link. please get one ld = parse_reddit_link(link_url, reddit_says_is_video, needs_preview, False, preview_ar) if previewimage == "": if domain.startswith('self.'): liz.setArt({ "thumb": ld.thumb if ld else '', "banner": '', }) else: liz.setArt({ "thumb": iconimage, "banner": ld.poster if ld else '', }) else: liz.setArt({ "thumb": iconimage, "banner": previewimage, }) #log( ' reddit thumb[%s] ' %(iconimage )) #log( ' reddit preview[%s] ar=%f %dx%d' %(previewimage, preview_ar, preview_w,preview_h )) #if ld: log( ' new-thumb[%s] poster[%s] ' %( ld.thumb, ld.poster )) if ld: #use clearart to indicate the type of link(video, album, image etc.) clearart = ret_info_type_icon(ld.media_type, ld.link_action, domain) liz.setArt({"clearart": clearart}) if iconimage in ["", "nsfw", "default"]: iconimage = ld.thumb #we gathered a description from the link if ld.desctiption: liz.setInfo(type='video', infoLabels={ 'plot': il_description + '[CR]' + ld.desctiption, }) #link_action set in domains.py - parse_reddit_link if ld.link_action == sitesBase.DI_ACTION_PLAYABLE: property_link_type = ld.link_action DirectoryItem_url = ld.playable_url else: property_link_type = 'script' if ld.link_action == 'viewTallImage': #viewTallImage take different args DirectoryItem_url = build_script(mode=ld.link_action, url=ld.playable_url, name=str(preview_w), type_=str(preview_h)) else: #log( '****' + repr( ld.dictlist )) DirectoryItem_url = build_script(mode=ld.link_action, url=ld.playable_url, name=post_title, type_=previewimage) #log(' action %s--%s' %( ld.link_action, DirectoryItem_url) ) liz.setProperty('item_type', property_link_type) liz.setProperty('onClick_action', DirectoryItem_url) liz.setProperty('album_images', json.dumps(ld.dictlist)) # dictlist=json.loads(string) #log( liz.getProperty('album_images')) else: #unsupported type here: pass return liz