Skip to content

Commit

Permalink
[plugin.video.stalkervod] 0.0.1
Browse files Browse the repository at this point in the history
  • Loading branch information
rickeylohia committed Nov 28, 2023
1 parent 1963417 commit 7c2b250
Show file tree
Hide file tree
Showing 18 changed files with 1,384 additions and 0 deletions.
674 changes: 674 additions & 0 deletions plugin.video.stalkervod/LICENSE

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions plugin.video.stalkervod/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Stalker VOD Kodi add-on
**plugin.video.stalkervod** is a [Kodi](https://kodi.tv/) add-on for Stalker platform IPTV Client. You can watch Video On-Demand as well as TV Channels.

0.0.1 Initial Release
29 changes: 29 additions & 0 deletions plugin.video.stalkervod/addon.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<addon id="plugin.video.stalkervod" name="Stalker VOD Client" version="0.0.1" provider-name="rickey">
<requires>
<import addon="xbmc.python" version="3.0.1"/>
<import addon="script.module.requests" version="2.27.1"/>
</requires>
<extension point="xbmc.python.pluginsource" library="addon_entry.py">
<provides>video</provides>
</extension>
<extension point="xbmc.addon.metadata">
<reuselanguageinvoker>true</reuselanguageinvoker>
<platform>all</platform>
<summary lang="en_GB">Stalker VOD Client</summary>
<description lang="en_GB">Kodi Stalker client for accessing on demand videos and channels from Stalker middleware</description>
<license>GPL-3.0-or-later</license>
<language>en</language>
<source>https://github.com/rickeylohia/plugin.video.stalkervod</source>
<website>https://github.com/rickeylohia/plugin.video.stalkervod</website>
<assets>
<icon>resources/media/icon.png</icon>
<screenshot>resources/media/screenshot_1.png</screenshot>
<screenshot>resources/media/screenshot_2.png</screenshot>
<screenshot>resources/media/screenshot_3.png</screenshot>
</assets>
<news>v0.0.1 (2023-10-22)
- Initial Release
</news>
</extension>
</addon>
7 changes: 7 additions & 0 deletions plugin.video.stalkervod/addon_entry.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
"""Stalker VOD plugin entry point"""
from __future__ import absolute_import, division, unicode_literals

if __name__ == '__main__':
from sys import argv
from lib.addon import run
run(argv)
Empty file.
272 changes: 272 additions & 0 deletions plugin.video.stalkervod/lib/addon.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,272 @@
"""
Compatible with Kodi 19.x "Matrix" and above
"""
from __future__ import absolute_import, division, unicode_literals
import re
import math
from urllib.parse import parse_qsl
import xbmc
import xbmcgui
import xbmcplugin
from .globals import G
from .utils import _ask_for_input
from .api import (get_categories, get_tv_genres, remove_favorites, add_favorites, get_vod_favorites,
get_tv_channels, get_videos, get_vod_stream_url, get_tv_stream_url)


def remove_favorites_refresh(params):
"""Remove from favorites and refresh"""
remove_favorites(params['video_id'])
url = G.get_plugin_url({'action': 'favorites', 'page': params['page'], 'update_listing': False})
func_str = f'Container.Update({url})'
xbmc.executebuiltin(func_str)


def play_video(video_id, series):
"""Play video"""
stream_url = get_vod_stream_url(video_id, series)
play_item = xbmcgui.ListItem(path=stream_url)
xbmcplugin.setResolvedUrl(G.get_handle(), True, listitem=play_item)


def play_tv(cmd):
"""Play TV Channel"""
stream_url = get_tv_stream_url(cmd)
play_item = xbmcgui.ListItem(path=stream_url)
xbmcplugin.setResolvedUrl(G.get_handle(), True, listitem=play_item)


def list_categories():
"""List categories"""
xbmcplugin.setPluginCategory(G.get_handle(), 'VOD')
xbmcplugin.setContent(G.get_handle(), 'videos')

list_item = xbmcgui.ListItem(label='FAVORITES')
url = G.get_plugin_url({'action': 'favorites', 'page': 1, 'update_listing': False})
xbmcplugin.addDirectoryItem(G.get_handle(), url, list_item, True)

list_item = xbmcgui.ListItem(label='TV CHANNELS')
url = G.get_plugin_url({'action': 'tv', 'page': 1, 'update_listing': False})
xbmcplugin.addDirectoryItem(G.get_handle(), url, list_item, True)
categories = get_categories()
for category in categories:
list_item = xbmcgui.ListItem(label=category['title'])
url = G.get_plugin_url({'action': 'search', 'category': category['title'], 'category_id': category['id']})
list_item.addContextMenuItems([('Search', f'RunPlugin({url}, False)')])
# list_item.setInfo('video', {'title': category['title'], 'mediatype': 'video'})
url = G.get_plugin_url({'action': 'listing', 'category': category['title'], 'category_id': category['id'],
'page': 1, 'update_listing': False, 'search_term': ''})
xbmcplugin.addDirectoryItem(G.get_handle(), url, list_item, True)
xbmcplugin.endOfDirectory(G.get_handle(), succeeded=True, updateListing=False, cacheToDisc=False)


def list_tv_genres():
"""List TV channel genres"""
xbmcplugin.setPluginCategory(G.get_handle(), 'TV CHANNELS')
xbmcplugin.setContent(G.get_handle(), 'videos')
genres = get_tv_genres()
for genre in genres:
list_item = xbmcgui.ListItem(label=genre['title'].upper())
url = G.get_plugin_url({'action': 'tv_listing', 'category': genre['title'].upper(), 'category_id': genre['id'],
'page': 1, 'update_listing': False})
xbmcplugin.addDirectoryItem(G.get_handle(), url, list_item, True)
xbmcplugin.endOfDirectory(G.get_handle(), succeeded=True, updateListing=False, cacheToDisc=False)


def list_channels(params):
"""List TV Channels"""
page = params['page']
update_listing = params['update_listing']
xbmcplugin.setPluginCategory(G.get_handle(), 'TV CHANNELS - ' + params['category'])
xbmcplugin.setContent(G.get_handle(), 'videos')
videos = get_tv_channels(params['category_id'], page)
item_count = len(videos['data'])
directory_items = []
for video in videos['data']:
label = video['name']
list_item = xbmcgui.ListItem(label, label)
list_item.setProperty('IsPlayable', 'true')
url = G.get_plugin_url({'action': 'tv_play', 'cmd': video['cmd']})
directory_items.append((url, list_item, False))
if int(videos['total_items']) > item_count:
add_navigation_items(params, videos, directory_items)
item_count = item_count + 2
xbmcplugin.addDirectoryItems(G.get_handle(), directory_items, item_count)
xbmcplugin.addSortMethod(G.get_handle(), xbmcplugin.SORT_METHOD_NONE, '%DA')
xbmcplugin.endOfDirectory(G.get_handle(), succeeded=True, updateListing=update_listing == 'True', cacheToDisc=False)


def list_videos(params):
"""List videos for a category"""
search_term = params.get('search_term', '')
xbmcplugin.setPluginCategory(G.get_handle(), params['category'])
xbmcplugin.setContent(G.get_handle(), 'videos')
videos = get_videos(params['category_id'], params['page'], search_term)
create_video_listing(videos, params)


def list_favorites(params):
"""List Favorites Channels"""
xbmcplugin.setPluginCategory(G.get_handle(), 'FAVORITES')
xbmcplugin.setContent(G.get_handle(), 'videos')
videos = get_vod_favorites(params['page'])
create_video_listing(videos, params)


def create_video_listing(videos, params):
"""Create paginated listing"""
page = params['page']
update_listing = params['update_listing']
item_count = len(videos['data'])
directory_items = []
for video in videos['data']:
label = video['name'] if video['hd'] == 1 else video['name'] + ' (SD)'
list_item = xbmcgui.ListItem(label, label)
if params['action'] == 'favorites':
url = G.get_plugin_url({'action': 'remove_fav', 'video_id': video['id'], 'page': page})
list_item.addContextMenuItems([('Remove from favorites', f'RunPlugin({url}, False)')])
else:
url = G.get_plugin_url({'action': 'add_fav', 'video_id': video['id']})
list_item.addContextMenuItems([('Add to favorites', f'RunPlugin({url}, False)')])

is_folder = False
poster_url = G.portal_config.portal_base_url + video['screenshot_uri']
video_info = list_item.getVideoInfoTag()
if video['series']:
url = G.get_plugin_url({'action': 'sub_folder', 'video_id': video['id'], 'start': video['series'][0],
'end': video['series'][-1], 'name': video['name'], 'poster_url': poster_url})
is_folder = True
video_info.setMediaType('season')
else:
url = G.get_plugin_url({'action': 'play', 'video_id': video['id'], 'series': 0})
# if video['time'] and video['time'] != '0':
# video_info.setDuration(int(video['time']) * 60)
video_info.setMediaType('movie')
list_item.setProperty('IsPlayable', 'true')

video_info.setTitle(video['name'])
video_info.setOriginalTitle(video['name'])
video_info.setSortTitle(video['name'])
video_info.setCountries([video['country']])
video_info.setDirectors([video['director']])
video_info.setPlot(video['description'])
video_info.setPlotOutline(video['description'])
actors = [xbmc.Actor(actor) for actor in video['actors'].split(',') if actor] # pylint: disable=maybe-no-member
video_info.setCast(actors)
video_info.setLastPlayed(video['last_played'])
video_info.setDateAdded(video['added'])
if video['year'].isdigit():
video_info.setYear(int(video['year']))
list_item.setArt({'poster': poster_url})
directory_items.append((url, list_item, is_folder))
# Add navigation items
if int(videos['total_items']) > item_count:
add_navigation_items(params, videos, directory_items)
item_count = item_count + 2
xbmcplugin.addDirectoryItems(G.get_handle(), directory_items, item_count)
xbmcplugin.addSortMethod(G.get_handle(), xbmcplugin.SORT_METHOD_NONE, '%DA')
xbmcplugin.endOfDirectory(G.get_handle(), succeeded=True, updateListing=update_listing == 'True', cacheToDisc=False)


def add_navigation_items(params, videos, directory_items):
"""Add navigation list items"""
page = params['page']
total_pages = int(math.ceil(float(videos['total_items']) / float(videos['max_page_items'])))
_max_page_limit = G.addon_config.max_page_limit
if _max_page_limit > 1:
total_pages = total_pages if (total_pages % _max_page_limit) == 0 else total_pages + _max_page_limit - (
total_pages % _max_page_limit)
label = '<< Last Page' if int(page) == 1 else '<< Previous Page'
list_item = xbmcgui.ListItem(label)
list_item.setArt({'thumb': G.get_custom_thumb_path('pagePrevious.png')})
list_item.setProperty('specialsort', 'top')
prev_page = total_pages - _max_page_limit + 1 if int(page) == 1 else int(page) - _max_page_limit
params.update({'page': prev_page, 'update_listing': True})
url = G.get_plugin_url(params)
directory_items.insert(0, (url, list_item, True))

label = 'First Page >>' if int(page) == total_pages - _max_page_limit + 1 else 'Next Page >>'
list_item = xbmcgui.ListItem(label)
list_item.setArt({'thumb': G.get_custom_thumb_path('pageNext.png')})
list_item.setProperty('specialsort', 'bottom')
next_page = 1 if int(page) == total_pages - _max_page_limit + 1 else int(page) + _max_page_limit
params.update({'page': next_page, 'update_listing': True})
url = G.get_plugin_url(params)
directory_items.append((url, list_item, True))


def list_episodes(params):
"""List episodes for a series"""
name = params['name']
xbmcplugin.setPluginCategory(G.get_handle(), name)
xbmcplugin.setContent(G.get_handle(), 'videos')
temp = name.split(' ')
match = re.match("^S[0-9]+$", temp[-1])
season = None
if match:
season = int(match.string[1:])
name = ' '.join(temp[:-1])
for episode_no in range(int(params['start']), int(params['end']) + 1):
list_item = xbmcgui.ListItem(label='Episode ' + str(episode_no))
video_info = list_item.getVideoInfoTag()
video_info.setTitle(name)
video_info.setOriginalTitle(name)
if match:
video_info.setEpisode(episode_no)
video_info.setSeason(season)
video_info.setSortSeason(season)
video_info.setMediaType('episode')
video_info.setTvShowTitle(name)
else:
video_info.setMediaType('movie')
list_item.setProperties({'IsPlayable': 'true'})
list_item.setArt({'poster': params['poster_url']})
url = G.get_plugin_url({'action': 'play', 'video_id': params['video_id'], 'series': episode_no})
xbmcplugin.addDirectoryItem(G.get_handle(), url, list_item, False)
xbmcplugin.endOfDirectory(G.get_handle(), succeeded=True, updateListing=False, cacheToDisc=False)


def search(params):
"""Search for videos"""
search_term = _ask_for_input(params['category'])
if search_term:
params.update({'action': 'listing', 'update_listing': False, 'search_term': search_term, 'page': 1})
url = G.get_plugin_url(params)
func_str = f'Container.Update({url})'
xbmc.executebuiltin(func_str)


def router(param_string):
"""Route calls"""
params = dict(parse_qsl(param_string))
if params:
if params['action'] == 'listing':
list_videos(params)
elif params['action'] == 'tv_listing':
list_channels(params)
elif params['action'] == 'sub_folder':
list_episodes(params)
elif params['action'] == 'play':
play_video(params['video_id'], params['series'])
elif params['action'] == 'tv_play':
play_tv(params['cmd'])
elif params['action'] == 'search':
search(params)
elif params['action'] == 'tv':
list_tv_genres()
elif params['action'] == 'favorites':
list_favorites(params)
elif params['action'] == 'remove_fav':
remove_favorites_refresh(params)
elif params['action'] == 'add_fav':
add_favorites(params['video_id'])
else:
raise ValueError('Invalid param string: {}!'.format(param_string))
else:
list_categories()


def run(argv):
"""Run"""
G.init_globals()
router(argv[2][1:])
Loading

0 comments on commit 7c2b250

Please sign in to comment.