You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
plugin.video.rumble/main.py

634 lines
21 KiB
Python

# -*- coding: utf-8 -*-
import sys, re, os
2 years ago
import xbmc, xbmcplugin, xbmcgui, xbmcaddon, xbmcvfs
import six
from six.moves import urllib
2 years ago
from resources.general import *
from resources.rumbleUser import *
2 years ago
2 years ago
try:
import json
except ImportError:
2 years ago
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://','')
2 years ago
ADDON = xbmcaddon.Addon()
ADDON_ICON = ADDON.getAddonInfo('icon')
ADDON_NAME = ADDON.getAddonInfo('name')
HOME_DIR = 'special://home/addons/{0}'.format(PLUGIN_NAME)
2 years ago
RESOURCE_DIR = HOME_DIR + 'resources/'
MEDIA_DIR = RESOURCE_DIR + 'media/'
2 years ago
kodi_version = float(xbmcaddon.Addon('xbmc.addon').getAddonInfo('version')[:4])
date_format = ADDON.getSetting('date_format')
rumbleUser = rumbleUser()
if six.PY2:
favorites = xbmc.translatePath(os.path.join(ADDON.getAddonInfo('profile'), 'favorites.dat'))
2 years ago
else:
favorites = xbmcvfs.translatePath(os.path.join(ADDON.getAddonInfo('profile'), 'favorites.dat'))
def createFavorites():
addonID = ADDON.getAddonInfo('id')
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)==False:
os.mkdir(addon_data_path)
xbmc.sleep(1)
def loadFavorites( return_string = False ):
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:
createFavorites()
if return_string:
return ''
else:
return []
2 years ago
def to_unicode(text, encoding='utf-8', errors='strict'):
# Force text to unicode
2 years ago
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
2 years ago
search_string = None
keyboard = xbmc.Keyboard(message, heading)
keyboard.doModal()
if keyboard.isConfirmed():
search_string = to_unicode(keyboard.getText())
return search_string
# main menu
def home_menu():
# Search
addDir( get_string(137), '', 1, MEDIA_DIR + 'search.png', '', '' ,'' )
2 years ago
# Favorites
addDir( get_string(1036), '', 7, MEDIA_DIR + 'favorite.png', '', '', '' )
if rumbleUser.hasLoginDetails():
# subscriptions
addDir( 'Subscriptions', BASE_URL + '/subscriptions', 3, MEDIA_DIR + 'favorite.png', '', '', 'other' )
# subscriptions
addDir( 'Following', BASE_URL + '/', 3, MEDIA_DIR + 'favorite.png', '', '', 'following' )
2 years ago
# News
addDir( get_string(29916), BASE_URL + '/category/news', 3, MEDIA_DIR + 'news.png', '', '', 'other' )
2 years ago
# Viral
addDir( get_string(30050), BASE_URL + '/category/viral', 3, MEDIA_DIR + 'viral.png', '', '', 'other' )
2 years ago
# Podcasts
addDir( get_string(30051), BASE_URL + '/category/podcasts', 3, MEDIA_DIR +'podcast.png','','','other')
2 years ago
# Battle Leaderboard
addDir( get_string(30052), BASE_URL + '/battle-leaderboard', 3, MEDIA_DIR + 'leader.png', '', '', 'top' )
2 years ago
# Entertainment
addDir( get_string(30053), BASE_URL + '/category/entertainment', 3, MEDIA_DIR + 'entertaiment.png', '', '', 'other' )
2 years ago
# Sports
addDir( get_string(19548), BASE_URL + '/category/sports', 3, MEDIA_DIR + 'sports.png', '', '', 'other' )
2 years ago
# Science
addDir( get_string(29948), BASE_URL + '/category/science', 3, MEDIA_DIR + 'science.png', '', '', 'other' )
2 years ago
# Technology
addDir( get_string(30054), BASE_URL + '/category/technology', 3, MEDIA_DIR + 'technology.png', '', '', 'other' )
2 years ago
# Vlogs
addDir( get_string(30055), BASE_URL + '/category/vlogs', 3, MEDIA_DIR + 'vlog.png', '', '', 'other' )
2 years ago
# Settings
addDir( get_string(5), '', 8, MEDIA_DIR + 'settings.png', '', '', '' )
2 years ago
SetView('WideList')
xbmcplugin.endOfDirectory(PLUGIN_ID, cacheToDisc=False)
# search menu
def search_menu():
# Search Video
addDir( get_string(30100), BASE_URL + '/search/video?q=', 2, MEDIA_DIR + 'search.png', '', '', 'video' )
2 years ago
# Search Channel
addDir( get_string(30101), BASE_URL + '/search/channel?q=',2,MEDIA_DIR + 'search.png', '', '', 'channel' )
# Search User
addDir( get_string(30102), BASE_URL + '/search/channel?q=',2,MEDIA_DIR + 'search.png', '', '', 'user' )
2 years ago
SetView('WideList')
xbmcplugin.endOfDirectory(PLUGIN_ID)
def pagination(url,page,cat,search=False):
2 years ago
if url > '':
page = int(page)
pageUrl = url
if page == 1:
2 years ago
if search:
pageUrl = url + search
elif search and cat == 'video':
pageUrl = url + search + "&page=" + str( page )
elif cat in {'channel', 'user', 'other' }:
pageUrl = url + "?page=" + str( page )
amount = list_rumble( pageUrl, cat )
if amount > 15 and page < 10:
# for next page
page = page + 1
name = get_string(30150) + " " + str( page )
2 years ago
li=xbmcgui.ListItem(name)
linkParams = {
'url': url,
'mode': '3',
'name': name,
'page': str( page ),
'cat': cat,
}
link = buildURL( linkParams )
if search and cat == 'video':
link = link + "&search=" + urllib.parse.quote_plus(search)
xbmcplugin.addDirectoryItem(PLUGIN_ID, link, li, True)
2 years ago
SetView('WideList')
xbmcplugin.endOfDirectory(PLUGIN_ID)
def get_image(data,id):
image_re = re.compile("i.user-image--img--id-"+str(id)+".+?{ 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):
amount = 0
headers = None
if 'subscriptions' in url or cat == 'following':
# make sure there is a session
# result is stored in a cookie
rumbleUser.hasSession()
#{ 'cookie': 'u_s=' + ADDON.getSetting('session')}
data = getRequest(url, None, headers)
if 'search' in url:
if cat == 'video':
amount = create_dir_list( data, cat, 'video', True, 1 )
else:
amount = create_dir_list( data, cat, 'channel', True )
elif cat in { 'channel', 'user', 'top', 'other' }:
amount = create_dir_list( data, cat, 'video', False, 2 )
elif cat == 'following':
amount = create_dir_list( data, cat, 'following', False, 2 )
return amount
def create_dir_list( data, cat, type='video', search = False, play=False ):
amount = 0
if type == 'video':
videos = re.compile('a href=([^\>]+)><div class=\"(?:[^\"]+)\"><img class=\"video-item--img\" src=(https:\/\/.+?) alt=(?:[^\>]+)>(?:<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:
if '<svg' in channel_name:
channel_name = channel_name.split('<svg')[0] + " (Verified)"
video_title = '[B]' + title + '[/B]\n[COLOR gold]' + channel_name + ' - [COLOR lime]' + get_date_formatted( date_format, year, month, day ) + '[/COLOR]'
#open get url and open player
addDir( video_title, BASE_URL + link, 4, str(img), str(img), '', cat, False, True, play, { 'name' : channel_link, 'subscribe': True } )
elif type == 'following':
following = re.compile('<a class=\"main-menu-item main-menu-item-channel\" title=\"?(?:[^\"]+)\"? href=([^>]+)>\s*<i class=\'user-image (?:user-image--img user-image--img--id-([^\']+)\')?(?:user-image--letter\' data-letter=([a-zA-Z]))?></i>\s*<span class=\"main-menu-item-label main-menu-item-channel-label\">([^<]+)</span>', re.MULTILINE|re.DOTALL|re.IGNORECASE).findall(data)
if following:
amount = len(following)
for link, img_id, img_letter, channel_name in following:
if img_id:
img = str( get_image( data, img_id ) )
else:
img = MEDIA_DIR + 'letters/' + img_letter + '.png'
video_title = '[B]' + channel_name + '[/B]'
#open get url and open player
addDir( video_title, BASE_URL + link, 3, img, img, '', 'other', True, True, play, { 'name' : link, 'subscribe': False } )
else:
channels = re.compile('a href=(.+?)>\s*<div class=\"channel-item--img\">\s*<i class=\'user-image user-image--img user-image--img--id-(.+?)\'></i>\s*</div>\s*<h3 class=channel-item--title>(.+?)</h3>\s*<span class=channel-item--subscribers>(.+?) subscribers</span>',re.DOTALL).findall(data)
if channels:
amount = len(channels)
for link, img_id, 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)"
img = str( get_image( data, img_id ) )
video_title = '[B]' + channel_name + '[/B]\n[COLOR palegreen]' + subscribers + ' [COLOR yellow]' + get_string(30155) + '[/COLOR]'
#open get url and open player
addDir( video_title, BASE_URL + link, 3, img, img, '', cat, True, True, play, { 'name' : link, 'subscribe': True } )
return amount
2 years ago
def resolver(url):
# playback options - 0: large to small, 1: small to large, 2: quality select
2 years ago
playbackMethod = ADDON.getSetting('playbackMethod')
mediaURL = False
2 years ago
if playbackMethod == '2':
urls = []
data = getRequest(url)
# gets embed id from embed url
embed_id = re.compile(',\"embedUrl\":\"' + BASE_URL + '/embed/(.*?)\/\",', re.MULTILINE|re.DOTALL|re.IGNORECASE).findall(data)
if embed_id:
# use site api to get video urls
data = getRequest(BASE_URL + '/embedJS/u3/?request=video&ver=2&v=' + embed_id[0])
2 years ago
sizes = [ '1080', '720', '480', '360', 'hls' ]
2 years ago
# reverses array - small to large
2 years ago
if playbackMethod == '1':
sizes = sizes[::-1]
for quality in sizes:
2 years ago
matches = re.compile( '"' + quality + '".+?url.+?:"(.*?)"', re.MULTILINE|re.DOTALL|re.IGNORECASE).findall(data)
2 years ago
if matches:
if playbackMethod == '2':
urls.append(( quality, matches[0] ))
else:
mediaURL = matches[0]
break
# quality select
2 years ago
if playbackMethod == '2':
if len(urls) > 0:
selectedIndex = xbmcgui.Dialog().select(
'Select Quality', [(sourceItem[0] or '?') for sourceItem in urls]
)
if selectedIndex != -1:
mediaURL = urls[selectedIndex][1]
if mediaURL:
mediaURL = mediaURL.replace('\/', '/')
return mediaURL
2 years ago
# method to play video
2 years ago
def play_video(name, url, iconimage, play=2):
# get video link
2 years ago
url = resolver(url)
if url:
li = xbmcgui.ListItem(name, path=url)
li.setArt({'icon': iconimage, 'thumb': iconimage})
if kodi_version > 19.8:
vidtag = li.getVideoInfoTag()
vidtag.setTitle(name)
else:
li.setInfo(type='video', infoLabels={'Title': name, 'plot': ''})
if play == 1:
xbmc.Player().play(item=url, listitem=li)
elif play == 2:
xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, li)
else:
xbmcgui.Dialog().ok( 'Error', 'Video not found' )
2 years ago
def search_items(url,cat):
vq = get_search_string(heading="Search")
if ( not vq ): return False, 0
title = urllib.parse.quote_plus(vq)
2 years ago
pagination(url,1,cat,title)
2 years ago
def getFavorites():
2 years ago
data = loadFavorites()
2 years ago
2 years ago
try:
amount = len(data)
if amount > 0:
for i in data:
2 years ago
name = i[0]
url = i[1]
mode = i[2]
iconimage = i[3]
fanArt = i[4]
description = i[5]
cat = i[6]
folder = ( i[7] == 'True' )
2 years ago
play = i[8]
addDir( name, url, mode, str(iconimage), str(fanArt), str(description), cat, folder, True, int(play) )
2 years ago
SetView('WideList')
xbmcplugin.endOfDirectory(PLUGIN_ID)
else:
xbmcgui.Dialog().ok( get_string(14117), get_string(30155) )
2 years ago
except:
SetView('WideList')
xbmcplugin.endOfDirectory(PLUGIN_ID)
def addFavorite(name, url, fav_mode, iconimage, fanart, description, cat, folder, play):
data = loadFavorites()
data.append((name, url, fav_mode, iconimage, fanart, description, cat, folder, play))
b = open(favorites, 'w')
b.write(json.dumps(data))
b.close()
notify( get_string(30152), name, iconimage )
2 years ago
def rmFavorite(name):
data = loadFavorites()
2 years ago
for index in range(len(data)):
if data[index][0]==name:
del data[index]
b = open(favorites, 'w')
2 years ago
b.write(json.dumps(data))
b.close()
break
notify( get_string(30154), name )
2 years ago
def importFavorites():
if not xbmcgui.Dialog().yesno(
'Import Favorites',
'This will replace the favorites with the plugin.video.rumble.matrix version.\nProceed?',
nolabel = 'Cancel',
yeslabel = 'Ok'
):
return
# no point trying to run this as it didn't exist for python 2
if six.PY2:
return
# make sure path exists
createFavorites()
#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:
b = open(favorites, 'w')
b.write(rumble_matrix)
b.close()
notify( 'Imported Favorites' )
return
notify( 'Favorites Not Found' )
def resetLoginSession():
rumbleUser.resetSessionDetails()
notify( 'Session has been reset' )
def subscribe(name, action):
# make sure we have a session
if rumbleUser.hasSession():
type = False
if '/user/' in name:
name = name.replace( '/user/', '' )
type = 'user'
elif '/c/' in name:
name = name.replace( '/c/', '' )
type = 'channel'
if type:
data = rumbleUser.subscribe( action, type, name )
xbmc.log( data, xbmc.LOGWARNING )
if action == 'subscribe':
notify( 'Subscribed to ' + name )
else:
notify( 'Unubscribed to ' + name )
return True
notify( 'Unable to to perform action' )
def addDir(name, url, mode, iconimage, fanart, description, cat, folder=True, fav_context=False, play=False, subscribe_context=False):
2 years ago
linkParams = {
'url': url,
'mode': str( mode ),
'name': name,
'fanart': fanart,
'iconimage': iconimage,
'description': description,
'cat': cat,
}
2 years ago
2 years ago
if play:
linkParams['play'] = str( play )
link = buildURL( linkParams )
li=xbmcgui.ListItem( name )
2 years ago
if folder:
li.setArt({'icon': 'DefaultFolder.png', 'thumb': iconimage})
else:
li.setArt({'icon': 'DefaultVideo.png', 'thumb': iconimage})
if play == 2 and mode == 4:
li.setProperty('IsPlayable', 'true')
if kodi_version > 19.8:
vidtag = li.getVideoInfoTag()
vidtag.setMediaType('video')
vidtag.setTitle(name)
vidtag.setPlot(description)
else:
li.setInfo(type='Video', infoLabels={'Title': name, 'Plot': description})
2 years ago
if fanart > '':
li.setProperty('fanart_image', fanart)
else:
li.setProperty('fanart_image', HOME_DIR + 'fanart.jpg')
contextMenu = []
if rumbleUser.hasLoginDetails():
if subscribe_context:
if subscribe_context['subscribe']:
contextMenu.append(('Subscribe to ' + subscribe_context['name'],'RunPlugin(%s)' % buildURL( {'mode': '11','name': subscribe_context['name'], 'cat': 'subscribe'} )))
else:
contextMenu.append(('Unsubscribe to ' + subscribe_context['name'],'RunPlugin(%s)' % buildURL( {'mode': '11','name': subscribe_context['name'], 'cat': 'unsubscribe'} )))
if fav_context:
favorite_str = loadFavorites( True )
2 years ago
2 years ago
try:
2 years ago
name_fav = json.dumps(name)
2 years ago
except:
2 years ago
name_fav = name
2 years ago
try:
# checks fave name via string ( I do not like how this is done )
if name_fav in favorite_str:
contextMenu.append((get_string(30153),'RunPlugin(%s)' % buildURL( {'mode': '6','name': name} )))
2 years ago
else:
fav_params = {
'url': url,
'mode': '5',
'name': name,
'fanart': fanart,
'iconimage': iconimage,
'description': description,
'cat': cat,
'folder': str(folder),
'fav_mode': str(mode),
'play': str(play),
}
contextMenu.append((get_string(30151),'RunPlugin(%s)' %buildURL( fav_params )))
2 years ago
except:
pass
if contextMenu:
li.addContextMenuItems(contextMenu)
2 years ago
xbmcplugin.addDirectoryItem(handle=PLUGIN_ID, url=link, listitem=li, isFolder=folder)
2 years ago
2 years ago
def main():
2 years ago
2 years ago
params=get_params()
mode=int(params.get( 'mode', 0 ))
page=int(params.get( 'page', 1 ))
play=int(params.get( 'play', 1 ))
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)
iconimage=params.get( 'iconimage', None )
if iconimage:
iconimage=urllib.parse.unquote_plus(iconimage)
fanart=params.get( 'fanart', None )
if fanart:
fanart=urllib.parse.unquote_plus(fanart)
description=params.get( 'description', None )
if description:
description=urllib.parse.unquote_plus(description)
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:
2 years ago
home_menu()
elif mode==1:
search_menu()
elif mode==2:
search_items(url,cat)
elif mode==3:
if search and search !=None:
pagination(url, page, cat, search)
2 years ago
else:
pagination(url, page, cat)
2 years ago
elif mode==4:
play_video(name, url, iconimage, play)
elif mode in [5,6]:
if '\\ ' in name:
2 years ago
name = name.split('\\ ')[1]
if ' - ' in name:
2 years ago
name = name.split(' - ')[0]
if mode == 5:
addFavorite( name, url, fav_mode, iconimage, fanart, description, cat, str(folder), str(play) )
else:
rmFavorite( name )
2 years ago
elif mode==7:
getFavorites()
elif mode==8:
ADDON.openSettings()
elif mode==9:
importFavorites()
elif mode==10:
resetLoginSession()
elif mode==11:
subscribe(name, cat)
2 years ago
if __name__ == "__main__":
main()