Example #1
0
    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
Example #5
0
    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
Example #8
0
    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
Example #9
0
    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
Example #19
0
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
Example #21
0
    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