# -*- coding: utf-8 -*-
import sys
import re
import os
import xbmc
import xbmcplugin
import xbmcgui
import xbmcaddon
import xbmcvfs
import six
from six . moves import urllib
from lib . general import *
from lib . rumble_user import RumbleUser
from lib . comments import CommentWindow
try :
import json
except ImportError :
import simplejson as json
BASE_URL = ' https://rumble.com '
PLUGIN_URL = sys . argv [ 0 ]
PLUGIN_ID = int ( sys . argv [ 1 ] )
PLUGIN_NAME = PLUGIN_URL . replace ( ' plugin:// ' , ' ' )
ADDON = xbmcaddon . Addon ( )
ADDON_ICON = ADDON . getAddonInfo ( ' icon ' )
ADDON_NAME = ADDON . getAddonInfo ( ' name ' )
HOME_DIR = ' special://home/addons/ ' + PLUGIN_NAME
RESOURCE_DIR = HOME_DIR + ' resources/ '
MEDIA_DIR = RESOURCE_DIR + ' media/ '
DATE_FORMAT = ADDON . getSetting ( ' date_format ' )
RUMBLE_USER = RumbleUser ( )
if six . PY2 :
favorites = xbmc . translatePath ( os . path . join ( ADDON . getAddonInfo ( ' profile ' ) , ' favorites.dat ' ) )
else :
favorites = xbmcvfs . translatePath ( os . path . join ( ADDON . getAddonInfo ( ' profile ' ) , ' favorites.dat ' ) )
def favorites_create ( ) :
""" creates favorite directory if doesn ' t exist """
if six . PY2 :
addon_data_path = xbmc . translatePath ( ADDON . getAddonInfo ( ' profile ' ) )
else :
addon_data_path = xbmcvfs . translatePath ( ADDON . getAddonInfo ( ' profile ' ) )
if os . path . exists ( addon_data_path ) is False :
os . mkdir ( addon_data_path )
xbmc . sleep ( 1 )
def favorites_load ( return_string = False ) :
""" load favourites from file into variable """
if os . path . exists ( favorites ) :
fav_str = open ( favorites ) . read ( )
if return_string :
return fav_str
if fav_str :
return json . loads ( fav_str )
else :
favorites_create ( )
# nothing to load, return type necessary
if return_string :
return ' '
return [ ]
def to_unicode ( text , encoding = ' utf-8 ' , errors = ' strict ' ) :
""" Forces text to unicode """
if isinstance ( text , bytes ) :
return text . decode ( encoding , errors = errors )
return text
def get_search_string ( heading = ' ' , message = ' ' ) :
""" Ask the user for a search string """
search_string = None
keyboard = xbmc . Keyboard ( message , heading )
keyboard . doModal ( )
if keyboard . isConfirmed ( ) :
search_string = to_unicode ( keyboard . getText ( ) )
return search_string
def home_menu ( ) :
""" Creates home menu """
# Search
add_dir ( get_string ( 137 ) , ' ' , 1 , { ' thumb ' : ' search.png ' } )
# Favorites
add_dir ( get_string ( 1036 ) , ' ' , 7 , { ' thumb ' : ' favorite.png ' } )
if RUMBLE_USER . has_login_details ( ) :
# Subscriptions
add_dir ( ' Subscriptions ' , BASE_URL + ' /subscriptions ' , 3 , { ' thumb ' : ' favorite.png ' } , { } , ' subscriptions ' )
# Following
add_dir ( ' Following ' , BASE_URL + ' /followed-channels ' , 3 , { ' thumb ' : ' favorite.png ' } , { } , ' following ' )
# Watch Later
add_dir ( ' Watch Later ' , BASE_URL + ' /playlists/watch-later ' , 3 , { ' thumb ' : ' favorite.png ' } , { } , ' playlist ' )
# Battle Leaderboard
add_dir ( get_string ( 30050 ) , BASE_URL + ' /battle-leaderboard/recorded ' , 3 , { ' thumb ' : ' leader.png ' } , { } , ' top ' )
# Categories
add_dir ( get_string ( 30051 ) , BASE_URL + ' /browse ' , 3 , { ' thumb ' : ' viral.png ' } , { } , ' cat_list ' )
# Live Streams
add_dir ( get_string ( 30052 ) , BASE_URL + ' /browse/live ' , 3 , { ' thumb ' : ' viral.png ' } , { } , ' live_stream ' )
# Settings
add_dir ( get_string ( 5 ) , ' ' , 8 , { ' thumb ' : ' settings.png ' } )
xbmcplugin . endOfDirectory ( PLUGIN_ID , cacheToDisc = False )
def search_menu ( ) :
""" Creates search menu """
# Search Video
add_dir ( get_string ( 30100 ) , BASE_URL + ' /search/video?q= ' , 2 , { ' thumb ' : ' search.png ' } , { } , ' video ' )
# Search Channel
add_dir ( get_string ( 30101 ) , BASE_URL + ' /search/channel?q= ' , 2 , { ' thumb ' : ' search.png ' } , { } , ' channel ' )
# Search User
add_dir ( get_string ( 30102 ) , BASE_URL + ' /search/channel?q= ' , 2 , { ' thumb ' : ' search.png ' } , { } , ' user ' )
xbmcplugin . endOfDirectory ( PLUGIN_ID )
def pagination ( url , page , cat , search = False ) :
""" list directory items then show pagination """
if url > ' ' :
page = int ( page )
page_url = url
paginated = True
if page == 1 :
if search :
page_url = url + search
elif search and cat == ' video ' :
page_url = url + search + " &page= " + str ( page )
elif cat in { ' channel ' , ' cat_video ' , ' user ' , ' other ' , ' subscriptions ' , ' live_stream ' } :
page_url = url + " ?page= " + str ( page )
if cat in { ' following ' , ' top ' , ' cat_list ' } :
paginated = False
amount = list_rumble ( page_url , cat )
if paginated and amount > 15 and page < 10 :
# for next page
page = page + 1
name = get_string ( 30150 ) + " " + str ( page )
list_item = xbmcgui . ListItem ( name )
link_params = {
' url ' : url ,
' mode ' : ' 3 ' ,
' name ' : name ,
' page ' : str ( page ) ,
' cat ' : cat ,
}
link = build_url ( link_params )
if search and cat == ' video ' :
link = link + " &search= " + urllib . parse . quote_plus ( search )
xbmcplugin . addDirectoryItem ( PLUGIN_ID , link , list_item , True )
xbmcplugin . endOfDirectory ( PLUGIN_ID )
def get_image ( data , image_id ) :
""" method to get an image from scraped page ' s CSS from the image ID """
image_re = re . compile (
" i.user-image--img--id- " + str ( image_id ) + " .+? { \ s*background-image: url(.+?); " ,
re . MULTILINE | re . DOTALL | re . IGNORECASE
) . findall ( data )
if image_re != [ ] :
image = str ( image_re [ 0 ] ) . replace ( ' ( ' , ' ' ) . replace ( ' ) ' , ' ' )
else :
image = ' '
return image
def list_rumble ( url , cat ) :
""" Method to get and display items from Rumble """
amount = 0
headers = None
if ' subscriptions ' in url or cat == ' following ' :
# make sure there is a session
# result is stored in a cookie
RUMBLE_USER . has_session ( )
data = request_get ( url , None , headers )
# Fix for favorites & search
if cat in { ' other ' , ' channel ' } and ' /c/ ' in url :
cat = ' channel_video '
if ' search ' in url :
if cat == ' video ' :
amount = dir_list_create ( data , cat , ' video ' , True , 1 )
else :
amount = dir_list_create ( data , cat , ' channel ' , True )
elif cat in { ' subscriptions ' , ' cat_video ' , ' live_stream ' , ' playlist ' } :
amount = dir_list_create ( data , cat , cat , False , 2 )
elif cat in { ' channel ' , ' top ' , ' other ' } :
amount = dir_list_create ( data , cat , ' video ' , False , 2 )
elif cat in { ' channel_video ' , ' user ' } :
amount = dir_list_create ( data , cat , ' channel_video ' , False , 2 )
elif cat == ' following ' :
amount = dir_list_create ( data , cat , ' following ' , False , 2 )
elif cat == ' cat_list ' :
amount = dir_list_create ( data , cat , cat , False )
return amount
def dir_list_create ( data , cat , video_type = ' video ' , search = False , play = 0 ) :
""" create and display dir list based upon type """
amount = 0
if video_type == ' video ' :
videos = re . compile ( r ' href= \ " ([^ \ " ]+) \ " ><div class= \ " (?:[^ \ " ]+) \ " ><img \ s*class= \ " video-item--img \ " \ s*src= \ " ([^ \ " ]+) \ " \ s*alt= \ " (?:[^ \ " ]+) \ " \ s*>(?:<span class= \ " video-item--watching \ " >[^ \ <]+</span>)?(?:<div class=video-item--overlay-rank>(?:[0-9]+)</div>)?</div><(?:[^ \ >]+)></span></a><div class= \ " video-item--info \ " ><time class= \ " video-item--meta video-item--time \ " datetime=(.+?)-(.+?)-(.+?)T(?:.+?) title \ = \ " (?:[^ \ " ]+) \ " >(?:[^ \ <]+)</time><h3 class=video-item--title>(.+?)</h3><address(?:[^ \ >]+)><a rel=author class= \ " (?:[^ \ =]+)=(.+?)><div class=ellipsis-1>(.+?)</div> ' , re . MULTILINE | re . DOTALL | re . IGNORECASE ) . findall ( data )
if videos :
amount = len ( videos )
for link , img , year , month , day , title , channel_link , channel_name in videos :
info_labels = { }
if ' <svg ' in channel_name :
channel_name = channel_name . split ( ' <svg ' ) [ 0 ] + " (Verified) "
info_labels [ ' year ' ] = year
video_title = ' [B] ' + clean_text ( title ) + ' [/B] \n [COLOR gold] ' + channel_name + ' [/COLOR] - [COLOR lime] ' + get_date_formatted ( DATE_FORMAT , year , month , day ) + ' [/COLOR] '
images = { ' thumb ' : str ( img ) , ' fanart ' : str ( img ) }
#open get url and open player
add_dir ( video_title , BASE_URL + link , 4 , images , info_labels , cat , False , True , play , { ' name ' : channel_link , ' subscribe ' : True } )
elif video_type in { ' cat_video ' , ' subscriptions ' , ' live_stream ' , ' channel_video ' , ' playlist ' } :
if video_type == ' live_stream ' :
videos_regex = r ' <div class= \ " thumbnail__grid \ " \ s*role= \ " list \ " >(.*)<nav class= \ " paginator \ " > '
elif video_type == ' playlist ' :
videos_regex = r ' <ol \ s*class= \ " videostream__list \ " (?:[^>]+)>(.*)</ol> '
else :
videos_regex = r ' <ol \ s*class= \ " thumbnail__grid \ " >(.*)</ol> '
videos = re . compile ( videos_regex , re . DOTALL | re . IGNORECASE ) . findall ( data )
if videos :
if video_type == ' playlist ' :
videos = videos [ 0 ] . split ( ' " videostream videostream__list-item ' )
else :
videos = videos [ 0 ] . split ( ' " videostream thumbnail__grid- ' )
videos . pop ( 0 )
amount = len ( videos )
for video in videos :
video_title = ' '
images = { }
info_labels = { }
subscribe_context = False
title = re . compile ( r ' <h3(?:[^ \ >]+)?>(.*)</h3> ' , re . DOTALL | re . IGNORECASE ) . findall ( video )
link = re . compile ( r ' <a \ sclass= " videostream__link link " \ sdraggable= " false " \ shref= " ([^ \ " ]+) " > ' , re . DOTALL | re . IGNORECASE ) . findall ( video )
img = re . compile ( r ' <img \ s*class= \ " thumbnail__image \ " \ s*draggable= \ " false \ " \ s*src= \ " ([^ \ " ]+) \ " ' , re . DOTALL | re . IGNORECASE ) . findall ( video )
if title :
video_title = ' [B] ' + clean_text ( title [ 0 ] ) + ' [/B] '
if ' videostream__status--live ' in video :
video_title + = ' [COLOR red](Live)[/COLOR] '
if ' videostream__status--upcoming ' in video :
video_title + = ' [COLOR yellow](Upcoming)[/COLOR] '
channel_name = re . compile ( r ' <span \ sclass= " channel__name(?:[^ \ " ]+) " title= " (?:[^ \ " ]+) " >([^ \ <]+)</span>( \ s*<svg class=channel__verified)? ' , re . DOTALL | re . IGNORECASE ) . findall ( video )
channel_link = re . compile ( r ' <a \ s*rel= \ " author \ " \ s*class= \ " channel__link \ slink \ s(?:[^ \ " ]+) \ " \ s*href= \ " ([^ \ " ]+) \ " \ s*> ' , re . DOTALL | re . IGNORECASE ) . findall ( video )
if channel_name :
video_title + = ' \n [COLOR gold] ' + clean_text ( channel_name [ 0 ] [ 0 ] )
if channel_name [ 0 ] [ 1 ] :
video_title + = " (Verified) "
video_title + = ' [/COLOR] '
if channel_link :
subscribe_context = { ' name ' : channel_link [ 0 ] , ' subscribe ' : True }
date_time = re . compile ( r ' <time \ s*class= \ " (?:[^ \ " ]+) \ " \ s*datetime= \ " ( \ d {4} )-( \ d {2} )-( \ d {2} )T( \ d {2} ):( \ d {2} ):( \ d {2} )-( \ d {2} ):( \ d {2} ) \ " ' , re . DOTALL | re . IGNORECASE ) . findall ( video )
if date_time :
info_labels [ ' year ' ] = date_time [ 0 ] [ 0 ]
video_title + = ' - [COLOR lime] ' + get_date_formatted ( DATE_FORMAT , date_time [ 0 ] [ 0 ] , date_time [ 0 ] [ 1 ] , date_time [ 0 ] [ 2 ] ) + ' [/COLOR] '
if img :
images = { ' thumb ' : str ( img [ 0 ] ) , ' fanart ' : str ( img [ 0 ] ) }
duration = re . compile ( r ' videostream__status--duration \ " \ s*>([^<]+)</div> ' , re . DOTALL | re . IGNORECASE ) . findall ( video )
if duration :
info_labels [ ' duration ' ] = duration_to_secs ( duration [ 0 ] . strip ( ) )
#open get url and open player
add_dir ( video_title , BASE_URL + link [ 0 ] , 4 , images , info_labels , cat , False , True , play , subscribe_context )
return amount
elif video_type == ' cat_list ' :
cat_list = re . compile ( r ' <a \ s*class= \ " category__link link \ " \ s*href= \ " ([^ \ " ]+) \ " \ s*> \ s*<img \ s*class= \ " category__image \ " \ s*src= \ " ([^ \ " ]+) \ " \ s*alt=(?:[^ \ >]+)> \ s*<strong class= \ " category__title \ " >([^ \ <]+)</strong> ' , re . DOTALL | re . IGNORECASE ) . findall ( data )
if cat_list :
amount = len ( cat_list )
for link , img , title in cat_list :
cat = ' channel_video '
images = { ' thumb ' : str ( img ) , ' fanart ' : str ( img ) }
#open get url and open player
add_dir ( clean_text ( title ) , BASE_URL + link . strip ( ) + ' /videos ' , 3 , images , { } , cat )
elif video_type == ' following ' :
videos_regex = r ' <ol \ s*class= \ " followed-channels__list \ " >(.*)</ol> '
videos = re . compile ( videos_regex , re . DOTALL | re . IGNORECASE ) . findall ( data )
if videos :
videos = videos [ 0 ] . split ( ' " followed-channel flex items- ' )
videos . pop ( 0 )
amount = len ( videos )
for video in videos :
video_title = ' '
images = { }
title = re . compile ( r ' <span \ s*class= \ " clamp-2 \ " >([^<]+)< \ /span> ' , re . DOTALL | re . IGNORECASE ) . findall ( video )
followers = re . compile ( r ' <div \ s*class= \ " followed-channel__followers(?:[^ \ " ]+) \ " >([^<]+)</div> ' , re . DOTALL | re . IGNORECASE ) . findall ( video )
link = re . compile ( r ' <a \ s*class= \ " (?:[^ \ " ]+) \ " \ s*href= \ " ([^ \ " ]+) \ " > ' , re . DOTALL | re . IGNORECASE ) . findall ( video )
img = re . compile ( r ' <(?:img|span) \ s*class= \ " channel__avatar([^ \ " ]+) \ " \ s*(?:src= \ " ([^ \ " ]+) \ " )? ' , re . DOTALL | re . IGNORECASE ) . findall ( video )
if title :
video_title = ' [B] ' + clean_text ( title [ 0 ] ) + ' [/B] '
if ' <use href= " #channel_verified " /> ' in video :
video_title + = ' [COLOR gold](Verified)[/COLOR] '
link = link [ 0 ] if link else " "
if img :
if ' channel__letter ' in img [ 0 ] [ 0 ] :
if title :
image_url = MEDIA_DIR + ' letters/ ' + title [ 0 ] [ 0 ] . lower ( ) + ' .png '
else :
image_url = ' '
else :
image_url = img [ 0 ] [ 1 ]
images = { ' thumb ' : str ( image_url ) , ' fanart ' : str ( image_url ) }
if ' channel__live ' in img [ 0 ] [ 0 ] :
video_title + = ' [COLOR red](Live)[/COLOR] '
if followers :
video_title + = ' \n [COLOR green] ' + followers [ 0 ] . strip ( ) + ' [/COLOR] '
cat = ' user '
if ' /user/ ' not in link :
cat = ' channel_video '
#open get url and open player
add_dir ( video_title , BASE_URL + link , 3 , images , { } , cat , True , True , play , { ' name ' : link , ' subscribe ' : False } )
else :
channels = re . compile ( r ' a href=(.+?)> \ s*<div class= \ " channel-item--img \ " > \ s*<i class= \' user-image (?:user-image--img user-image--img--id-([^ \' ]+) \' )?(?:user-image--letter \' data-letter=([a-zA-Z]))? data-js=user-image> \ s*</i> \ s*</div> \ s*<h3 class=channel-item--title>(.+?)</h3> \ s*<span class=channel-item--subscribers>(.+?) Followers</span> ' , re . DOTALL ) . findall ( data )
if channels :
amount = len ( channels )
for link , img_id , img_letter , channel_name , subscribers in channels :
# split channel and user
if search :
if cat == ' channel ' :
if ' /c/ ' not in link :
continue
else :
if ' /user/ ' not in link :
continue
if ' <svg ' in channel_name :
channel_name = channel_name . split ( ' <svg ' ) [ 0 ] + " (Verified) "
if img_id :
img = str ( get_image ( data , img_id ) )
else :
img = MEDIA_DIR + ' letters/ ' + img_letter + ' .png '
images = { ' thumb ' : str ( img ) , ' fanart ' : str ( img ) }
video_title = ' [B] ' + channel_name + ' [/B] \n [COLOR palegreen] ' + subscribers + ' [/COLOR] [COLOR yellow] ' + get_string ( 30156 ) + ' [/COLOR] '
#open get url and open player
add_dir ( video_title , BASE_URL + link , 3 , images , { } , cat , True , True , play , { ' name ' : link , ' subscribe ' : True } )
return amount
def get_video_id ( url ) :
"""
gets a video id from a URL
helps in resolving
"""
data = request_get ( url )
# gets embed id from embed url
video_id = re . compile (
' , \" embedUrl \" : \" ' + BASE_URL + ' /embed/(.*?) \ / \" , ' ,
re . MULTILINE | re . DOTALL | re . IGNORECASE
) . findall ( data )
if video_id :
return video_id [ 0 ]
return False
def get_playlist_video_id ( url ) :
"""
gets a playlist video id from a URL
helps in adding video to playlist
"""
data = request_get ( url )
# gets embed id from embed url
video_id = re . compile (
' data-id= \" ([0-9]+) \" ' ,
re . MULTILINE | re . DOTALL | re . IGNORECASE
) . findall ( data )
if video_id :
return video_id [ 0 ]
return False
def resolver ( url ) :
""" Resolves a URL for rumble & returns resolved link to video """
# playback options - 0: high auto, 1: low auto, 2: quality select
playback_method = int ( ADDON . getSetting ( ' playbackMethod ' ) )
media_url = False
if playback_method > 0 :
urls = [ ]
video_id = get_video_id ( url )
if video_id :
# use site api to get video urls
# TODO: use as dict / array instead of using regex to get URLs
data = request_get ( BASE_URL + ' /embedJS/u3/?request=video&ver=2&v= ' + video_id )
sizes = [ ' 1080 ' , ' 720 ' , ' 480 ' , ' 360 ' , ' hls ' ]
for quality in sizes :
# get urls for quality
matches = re . compile (
' " ' + quality + ' " .+?url.+?: " (.*?) " ' ,
re . MULTILINE | re . DOTALL | re . IGNORECASE
) . findall ( data )
if matches :
if playback_method > 0 :
urls . append ( ( quality , matches [ 0 ] ) )
else :
media_url = matches [ 0 ]
break
# if not automatically selecting highest quality
if int ( playback_method ) > 0 :
# m3u8 check
if len ( urls ) == 1 and ' .m3u8 ' in urls [ 0 ] [ 1 ] :
from lib . m3u8 import m3u8
m3u8_handler = m3u8 ( )
urls = m3u8_handler . process ( request_get ( urls [ 0 ] [ 1 ] ) )
# reverses array - small to large
if playback_method == 1 :
urls = urls [ : : - 1 ]
media_url = urls [ 0 ] [ 1 ]
# quality select
elif playback_method == 2 :
if len ( urls ) > 0 :
selected_index = xbmcgui . Dialog ( ) . select (
' Select Quality ' , [ ( sourceItem [ 0 ] or ' ? ' ) for sourceItem in urls ]
)
if selected_index != - 1 :
media_url = urls [ selected_index ] [ 1 ]
if media_url :
media_url = media_url . replace ( ' \ / ' , ' / ' )
return media_url
def play_video ( name , url , thumb , play = 2 ) :
""" method to play video """
# get video link
url = resolver ( url )
if url :
# Use HTTP
if ADDON . getSetting ( ' useHTTP ' ) == ' true ' :
url = url . replace ( ' https:// ' , ' http:// ' , 1 )
list_item = xbmcgui . ListItem ( name , path = url )
list_item . setArt ( { ' icon ' : thumb , ' thumb ' : thumb } )
info_labels = { ' Title ' : name , ' plot ' : ' ' }
item_set_info ( list_item , info_labels )
if play == 1 :
xbmc . Player ( ) . play ( item = url , listitem = list_item )
elif play == 2 :
xbmcplugin . setResolvedUrl ( int ( sys . argv [ 1 ] ) , True , list_item )
else :
xbmcgui . Dialog ( ) . ok ( ' Error ' , ' Video not found ' )
def search_items ( url , cat ) :
""" Searches rumble """
search_str = get_search_string ( heading = " Search " )
if not search_str :
return False , 0
title = urllib . parse . quote_plus ( search_str )
pagination ( url , 1 , cat , title )
def favorites_show ( ) :
""" Displays favorites """
data = favorites_load ( )
try :
amount = len ( data )
if amount > 0 :
for i in data :
name = i [ 0 ]
url = i [ 1 ]
mode = i [ 2 ]
images = { ' thumb ' : str ( i [ 3 ] ) , ' fanart ' : str ( i [ 4 ] ) }
info_labels = { ' plot ' : str ( i [ 5 ] ) }
cat = i [ 6 ]
folder = ( i [ 7 ] == ' True ' )
play = i [ 8 ]
add_dir ( name , url , mode , images , info_labels , cat , folder , True , int ( play ) )
xbmcplugin . endOfDirectory ( PLUGIN_ID )
else :
xbmcgui . Dialog ( ) . ok ( get_string ( 14117 ) , get_string ( 30155 ) )
except Exception :
xbmcplugin . endOfDirectory ( PLUGIN_ID )
def favorite_add ( name , url , fav_mode , thumb , fanart , plot , cat , folder , play ) :
""" add favorite from name """
data = favorites_load ( )
data . append ( ( name , url , fav_mode , thumb , fanart , plot , cat , folder , play ) )
fav_file = open ( favorites , ' w ' )
fav_file . write ( json . dumps ( data ) )
fav_file . close ( )
notify ( get_string ( 30152 ) , name , thumb )
def favorite_remove ( name ) :
""" remove favorite from name """
# TODO: remove via something more unique instead
# TODO: remove via a method that doesn't require to loop through all favorites
data = favorites_load ( )
if data :
for index in range ( len ( data ) ) :
if data [ index ] [ 0 ] == name :
del data [ index ]
fav_file = open ( favorites , ' w ' )
fav_file . write ( json . dumps ( data ) )
fav_file . close ( )
break
notify ( get_string ( 30154 ) , name )
def favorites_import ( ) :
""" Due to plugin name change from original fork, the favorites will need to be imported """
if not xbmcgui . Dialog ( ) . yesno (
' Import Favorites ' ,
' This will replace the favorites with the plugin.video.rumble.matrix version. \n Proceed? ' ,
nolabel = ' Cancel ' ,
yeslabel = ' Ok '
) :
return
# no point trying to run this as it didn't exist for python 2
if six . PY2 :
notify ( ' Favorites Not Found ' )
return
# make sure path exists
favorites_create ( )
#load matrix favourites
rumble_matrix_dir = xbmcvfs . translatePath ( os . path . join ( ' special://home/userdata/addon_data/plugin.video.rumble.matrix ' , ' favorites.dat ' ) )
if os . path . exists ( rumble_matrix_dir ) :
rumble_matrix = open ( rumble_matrix_dir ) . read ( )
if rumble_matrix :
fav_file = open ( favorites , ' w ' )
fav_file . write ( rumble_matrix )
fav_file . close ( )
notify ( ' Imported Favorites ' )
return
notify ( ' Favorites Not Found ' )
def login_session_reset ( ) :
""" Forces a rumble session reset """
RUMBLE_USER . reset_session_details ( )
# Session Reset
notify ( get_string ( 30200 ) )
def login_test ( ) :
""" Method that resets session, then tests the login """
RUMBLE_USER . reset_session_details ( )
if RUMBLE_USER . has_login_details ( ) :
if RUMBLE_USER . login ( ) :
# Login Success
notify ( get_string ( 30201 ) )
else :
# Login Failed
notify ( get_string ( 30202 ) )
else :
# No details detected
notify ( get_string ( 30203 ) )
def subscribe ( name , action ) :
""" Attempts to (un)subscribe to rumble channel """
# make sure we have a session
if RUMBLE_USER . has_session ( ) :
action_type = False
if ' /user/ ' in name :
name = name . replace ( ' /user/ ' , ' ' )
action_type = ' user '
elif ' /c/ ' in name :
name = name . replace ( ' /c/ ' , ' ' )
action_type = ' channel '
if action_type :
# subscribe to action
data = RUMBLE_USER . subscribe ( action , action_type , name )
if data :
# Load data from JSON
data = json . loads ( data )
# make sure everything looks fine
if data . get ( ' user ' , False ) and data . get ( ' data ' , False ) \
and data [ ' user ' ] [ ' logged_in ' ] and data [ ' data ' ] [ ' thumb ' ] :
if action == ' subscribe ' :
notify ( ' Subscribed to ' + name , None , data [ ' data ' ] [ ' thumb ' ] )
else :
notify ( ' Unubscribed to ' + name , None , data [ ' data ' ] [ ' thumb ' ] )
return True
notify ( ' Unable to to perform action ' )
return False
def add_dir ( name , url , mode , images = { } , info_labels = { } , cat = ' ' , folder = True , fav_context = False , play = 0 , subscribe_context = False ) :
""" Adds directory items """
art_dict = {
' thumb ' : images . get ( ' thumb ' , HOME_DIR + ' icon.png ' ) ,
' fanart ' : images . get ( ' fanart ' , HOME_DIR + ' fanart.jpg ' ) ,
}
# set default image location to MEDIA_DIR
for art_type , art_loc in art_dict . items ( ) :
if art_loc :
if not art_loc . startswith ( HOME_DIR ) and \
not art_loc . startswith ( ' http ' ) and \
not art_loc . startswith ( ' \\ ' ) :
art_dict [ art_type ] = MEDIA_DIR + art_dict [ art_type ]
link_params = {
' url ' : url ,
' mode ' : str ( mode ) ,
' name ' : name ,
' thumb ' : art_dict [ ' thumb ' ] ,
' fanart ' : art_dict [ ' fanart ' ] ,
' plot ' : info_labels . get ( ' plot ' , ' ' ) ,
' cat ' : cat ,
}
context_menu = [ ]
if play :
link_params [ ' play ' ] = str ( play )
link = build_url ( link_params )
list_item = xbmcgui . ListItem ( name )
if folder :
list_item . setArt ( { ' icon ' : ' DefaultFolder.png ' , ' thumb ' : art_dict [ ' thumb ' ] } )
else :
list_item . setArt ( { ' icon ' : ' DefaultVideo.png ' , ' thumb ' : art_dict [ ' thumb ' ] } )
xbmcplugin . setContent ( PLUGIN_ID , ' videos ' )
if play == 2 and mode == 4 :
list_item . setProperty ( ' IsPlayable ' , ' true ' )
context_menu . append ( ( get_string ( 30158 ) , ' Action(Queue) ' ) )
if RUMBLE_USER . has_login_details ( ) :
# need to get current
params = get_params ( )
current_url = params . get ( ' url ' , None )
if ' /playlists/watch-later ' in current_url :
# delete watch later context
context_menu . append ( ( ' Delete from Watch Later ' , ' RunPlugin( %s ) ' % build_url ( { ' mode ' : ' 12 ' , ' url ' : url , ' cat ' : ' delete ' } ) ) )
else :
# add watch later context
context_menu . append ( ( ' Add to Watch Later ' , ' RunPlugin( %s ) ' % build_url ( { ' mode ' : ' 12 ' , ' url ' : url , ' cat ' : ' add ' } ) ) )
info_labels [ ' title ' ] = name
if play :
# adds information context menu
info_labels [ ' mediatype ' ] = ' tvshow '
item_set_info ( list_item , info_labels )
list_item . setProperty ( ' fanart_image ' , art_dict [ ' fanart ' ] )
if RUMBLE_USER . has_login_details ( ) :
if subscribe_context :
if subscribe_context [ ' subscribe ' ] :
context_menu . append ( ( ' Subscribe to ' + subscribe_context [ ' name ' ] , ' RunPlugin( %s ) ' % build_url ( { ' mode ' : ' 11 ' , ' name ' : subscribe_context [ ' name ' ] , ' cat ' : ' subscribe ' } ) ) )
else :
context_menu . append ( ( ' Unsubscribe to ' + subscribe_context [ ' name ' ] , ' RunPlugin( %s ) ' % build_url ( { ' mode ' : ' 11 ' , ' name ' : subscribe_context [ ' name ' ] , ' cat ' : ' unsubscribe ' } ) ) )
if play == 2 and mode == 4 :
context_menu . append ( ( ' Comments ' , ' RunPlugin( %s ) ' % build_url ( { ' mode ' : ' 13 ' , ' url ' : url } ) ) )
if fav_context :
favorite_str = favorites_load ( True )
try :
name_fav = json . dumps ( name )
except Exception :
name_fav = name
try :
# checks fav name via string (I do not like how this is done, so will redo in future)
if name_fav in favorite_str :
context_menu . append ( ( get_string ( 30153 ) , ' RunPlugin( %s ) ' % build_url ( { ' mode ' : ' 6 ' , ' name ' : name } ) ) )
else :
fav_params = {
' url ' : url ,
' mode ' : ' 5 ' ,
' name ' : name ,
' thumb ' : art_dict [ ' thumb ' ] ,
' fanart ' : art_dict [ ' fanart ' ] ,
' plot ' : info_labels . get ( ' plot ' , ' ' ) ,
' cat ' : cat ,
' folder ' : str ( folder ) ,
' fav_mode ' : str ( mode ) ,
' play ' : str ( play ) ,
}
context_menu . append ( ( get_string ( 30151 ) , ' RunPlugin( %s ) ' % build_url ( fav_params ) ) )
except Exception :
pass
if context_menu :
list_item . addContextMenuItems ( context_menu )
xbmcplugin . addDirectoryItem ( handle = PLUGIN_ID , url = link , listitem = list_item , isFolder = folder )
def playlist_manage ( url , action = " add " ) :
""" Adds to Rumble ' s Playlist """
video_id = get_playlist_video_id ( url )
if video_id :
if action == " add " :
RUMBLE_USER . playlist_add_video ( video_id )
message = " Added to playlist "
else :
RUMBLE_USER . playlist_delete_video ( video_id )
message = " Deleted from playlist "
else :
if action == " add " :
message = " Cannot add to playlist "
else :
message = " Cannot delete from playlist "
notify ( message , " Playlist " )
def comments_show ( url ) :
""" Retrieves and shows video ' s comments in a modal """
video_id = get_video_id ( url )
if video_id :
win = CommentWindow (
' addon-rumble-comments.xml ' ,
ADDON . getAddonInfo ( ' path ' ) ,
' default ' ,
video_id = video_id
)
win . doModal ( )
del win
else :
notify ( " Cannot find comments " , " Comments " )
def main ( ) :
""" main method to start plugin """
params = get_params ( )
mode = int ( params . get ( ' mode ' , 0 ) )
page = int ( params . get ( ' page ' , 1 ) )
play = int ( params . get ( ' play ' , 0 ) )
fav_mode = int ( params . get ( ' fav_mode ' , 0 ) )
url = params . get ( ' url ' , None )
if url :
url = urllib . parse . unquote_plus ( url )
name = params . get ( ' name ' , None )
if name :
name = urllib . parse . unquote_plus ( name )
thumb = params . get ( ' thumb ' , None )
if thumb :
thumb = urllib . parse . unquote_plus ( thumb )
fanart = params . get ( ' fanart ' , None )
if fanart :
fanart = urllib . parse . unquote_plus ( fanart )
plot = params . get ( ' plot ' , None )
if plot :
plot = urllib . parse . unquote_plus ( plot )
subtitle = params . get ( ' subtitle ' , None )
if subtitle :
subtitle = urllib . parse . unquote_plus ( subtitle )
cat = params . get ( ' cat ' , None )
if cat :
cat = urllib . parse . unquote_plus ( cat )
search = params . get ( ' search ' , None )
if search :
search = urllib . parse . unquote_plus ( search )
folder = params . get ( ' folder ' , None )
if folder :
folder = urllib . parse . unquote_plus ( folder )
folder = params . get ( ' folder ' , None )
if folder :
folder = urllib . parse . unquote_plus ( folder )
if mode == 0 :
home_menu ( )
elif mode == 1 :
search_menu ( )
elif mode == 2 :
search_items ( url , cat )
elif mode == 3 :
if search and search is not None :
pagination ( url , page , cat , search )
else :
pagination ( url , page , cat )
elif mode == 4 :
play_video ( name , url , thumb , play )
elif mode in [ 5 , 6 ] :
if ' \\ ' in name :
name = name . split ( ' \\ ' ) [ 1 ]
if ' - ' in name :
name = name . split ( ' - ' ) [ 0 ]
if mode == 5 :
favorite_add ( name , url , fav_mode , thumb , fanart , plot , cat , str ( folder ) , str ( play ) )
else :
favorite_remove ( name )
elif mode == 7 :
favorites_show ( )
elif mode == 8 :
ADDON . openSettings ( )
elif mode == 9 :
favorites_import ( )
elif mode == 10 :
login_session_reset ( )
elif mode == 11 :
subscribe ( name , cat )
elif mode == 12 :
playlist_manage ( url , cat )
elif mode == 13 :
comments_show ( url )
elif mode == 14 :
login_test ( )
if __name__ == " __main__ " :
main ( )