Compare commits
20 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4288c032db | ||
|
|
04a5378a87 | ||
|
|
ca5918ded9 | ||
|
|
2e7737c1af | ||
|
|
441bb10624 | ||
|
|
9adb23b280 | ||
|
|
7b547b2bc8 | ||
|
|
4ec75ad266 | ||
|
|
7dcf68d2be | ||
|
|
9199eb4290 | ||
|
|
8831af3fb4 | ||
|
|
20b1686b04 | ||
|
|
ae028f485a | ||
|
|
d5af0c8d7e | ||
|
|
e596998a72 | ||
|
|
f224c0b94a | ||
|
|
bc06467784 | ||
|
|
b2f369de10 | ||
|
|
0e070308db | ||
|
|
1b7c3ffae0 |
BIN
fanart.jpg
|
Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 32 KiB |
BIN
icon.png
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 13 KiB |
BIN
kodi.png
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 15 KiB |
@@ -1,6 +1,8 @@
|
||||
version: '0.4.1'
|
||||
version: '0.4.4'
|
||||
changelog: |
|
||||
- #57 - Fix browsing by pages
|
||||
- #67 - Optimize images
|
||||
- #72 - Include position ticks in external sub call
|
||||
- #73 - Fix next episode dialog
|
||||
dependencies:
|
||||
py2:
|
||||
- addon: 'xbmc.python'
|
||||
|
||||
@@ -14,6 +14,7 @@ from base64 import b64encode
|
||||
from collections import defaultdict
|
||||
from traceback import format_exc
|
||||
from kodi_six.utils import py2_decode
|
||||
from six import ensure_text
|
||||
|
||||
from .kodi_utils import HomeWindow
|
||||
from .clientinfo import ClientInformation
|
||||
@@ -493,7 +494,7 @@ class DownloadUtils:
|
||||
|
||||
secure = False
|
||||
for user in result:
|
||||
if user.get("Name") == unicode(user_name, "utf-8"):
|
||||
if user.get("Name") == ensure_text(user_name, "utf-8"):
|
||||
userid = user.get("Id")
|
||||
user_image = self.get_user_artwork(user, 'Primary')
|
||||
log.debug("Username Found: {0}".format(user.get("Name")))
|
||||
|
||||
@@ -16,6 +16,7 @@ from .utils import get_art, datetime_from_string
|
||||
from .loghandler import LazyLogger
|
||||
from .downloadutils import DownloadUtils
|
||||
from .kodi_utils import HomeWindow
|
||||
from six import ensure_text
|
||||
|
||||
log = LazyLogger(__name__)
|
||||
kodi_version = int(xbmc.getInfoLabel('System.BuildVersion')[:2])
|
||||
@@ -178,7 +179,7 @@ def extract_item_info(item, gui_options):
|
||||
name_info["SeasonIndex"] = u"%02d" % item_details.season_number
|
||||
name_info["EpisodeIndex"] = u"%02d" % item_details.episode_number
|
||||
log.debug("FormatName: {0} | {1}".format(name_format, name_info))
|
||||
item_details.name = unicode(name_format).format(**name_info).strip()
|
||||
item_details.name = ensure_text(name_format).format(**name_info).strip()
|
||||
|
||||
year = item.get("ProductionYear")
|
||||
prem_date = item.get("PremiereDate")
|
||||
|
||||
@@ -427,6 +427,12 @@ def play_file(play_info):
|
||||
data["play_action_type"] = "play"
|
||||
data["item_type"] = result.get("Type", None)
|
||||
data["can_delete"] = result.get("CanDelete", False)
|
||||
|
||||
# Check for next episodes
|
||||
if result.get('Type') == 'Episode':
|
||||
next_episode = get_next_episode(result)
|
||||
data["next_episode"] = next_episode
|
||||
|
||||
home_window.set_property('now_playing', json.dumps(data))
|
||||
|
||||
list_item.setPath(playurl)
|
||||
@@ -494,10 +500,6 @@ def play_file(play_info):
|
||||
else:
|
||||
log.info("PlaybackResumrAction : Playback resumed")
|
||||
|
||||
next_episode = get_next_episode(result)
|
||||
data["next_episode"] = next_episode
|
||||
send_next_episode_details(result, next_episode)
|
||||
|
||||
|
||||
def __build_label2_from(source):
|
||||
videos = [item for item in source.get('MediaStreams', {}) if item.get('Type') == "Video"]
|
||||
@@ -630,7 +632,7 @@ def send_next_episode_details(item, next_episode):
|
||||
"force_transcode": False
|
||||
}
|
||||
}
|
||||
send_event_notification("upnext_data", next_info)
|
||||
send_event_notification("upnext_data", next_info, True)
|
||||
|
||||
|
||||
def set_list_item_props(item_id, list_item, result, server, extra_props, title):
|
||||
@@ -835,10 +837,10 @@ def external_subs(media_source, list_item, item_id):
|
||||
|
||||
url_root = '{}/Videos/{}/{}/Subtitles/{}'.format(server, item_id, source_id, index)
|
||||
if language:
|
||||
url = '{}/Stream.{}.{}?api_key={}'.format(
|
||||
url = '{}/0/Stream.{}.{}?api_key={}'.format(
|
||||
url_root, language, codec, token)
|
||||
else:
|
||||
url = '{}/Stream.{}?api_key={}'.format(url_root, codec, token)
|
||||
url = '{}/0/Stream.{}?api_key={}'.format(url_root, codec, token)
|
||||
|
||||
default = ""
|
||||
if stream['IsDefault']:
|
||||
@@ -1048,6 +1050,10 @@ def stop_all_playback(played_information):
|
||||
|
||||
|
||||
def get_playing_data():
|
||||
home_window = HomeWindow()
|
||||
play_data_string = home_window.get_property('now_playing')
|
||||
play_data = json.loads(play_data_string)
|
||||
|
||||
settings = xbmcaddon.Addon()
|
||||
server = settings.getSetting('server_address')
|
||||
try:
|
||||
@@ -1057,10 +1063,9 @@ def get_playing_data():
|
||||
return None
|
||||
log.debug("get_playing_data : getPlayingFile() : {0}".format(playing_file))
|
||||
if server in playing_file:
|
||||
url_data = urlparse(playing_file)
|
||||
query = parse_qs(url_data.query)
|
||||
|
||||
return play_data_map.get(playing_file)
|
||||
return play_data
|
||||
else:
|
||||
return {}
|
||||
|
||||
|
||||
class Service(xbmc.Player):
|
||||
@@ -1166,7 +1171,7 @@ class PlaybackService(xbmc.Monitor):
|
||||
home_window.set_property('exit', 'True')
|
||||
return
|
||||
|
||||
if sender[-7:] != '.SIGNAL':
|
||||
if sender != 'plugin.video.jellycon':
|
||||
return
|
||||
|
||||
signal = method.split('.', 1)[-1]
|
||||
@@ -1174,16 +1179,12 @@ class PlaybackService(xbmc.Monitor):
|
||||
return
|
||||
|
||||
data_json = json.loads(data)
|
||||
message_data = data_json[0]
|
||||
log.debug("PlaybackService:onNotification:{0}".format(message_data))
|
||||
decoded_data = base64.b64decode(message_data)
|
||||
play_info = json.loads(decoded_data)
|
||||
play_info = data_json[0]
|
||||
log.debug("PlaybackService:onNotification:{0}".format(play_info))
|
||||
|
||||
if signal == "jellycon_play_action":
|
||||
log.info("Received jellycon_play_action : {0}".format(play_info))
|
||||
play_file(play_info, self.monitor)
|
||||
play_file(play_info)
|
||||
elif signal == "jellycon_play_youtube_trailer_action":
|
||||
log.info("Received jellycon_play_trailer_action : {0}".format(play_info))
|
||||
trailer_link = play_info["url"]
|
||||
xbmc.executebuiltin(trailer_link)
|
||||
elif signal == "set_view":
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
|
||||
import json
|
||||
import os
|
||||
import threading
|
||||
|
||||
@@ -9,6 +10,7 @@ import xbmcaddon
|
||||
|
||||
from .loghandler import LazyLogger
|
||||
from .play_utils import send_event_notification
|
||||
from .kodi_utils import HomeWindow
|
||||
|
||||
log = LazyLogger(__name__)
|
||||
|
||||
@@ -32,6 +34,8 @@ class PlayNextService(threading.Thread):
|
||||
play_next_triggered = False
|
||||
is_playing = False
|
||||
|
||||
now_playing = None
|
||||
|
||||
while not xbmc.Monitor().abortRequested() and not self.stop_thread:
|
||||
|
||||
player = xbmc.Player()
|
||||
@@ -42,6 +46,13 @@ class PlayNextService(threading.Thread):
|
||||
play_next_trigger_time = int(settings.getSetting('play_next_trigger_time'))
|
||||
log.debug("New play_next_trigger_time value: {0}".format(play_next_trigger_time))
|
||||
|
||||
now_playing_file = player.getPlayingFile()
|
||||
if now_playing_file != now_playing:
|
||||
# If the playing file has changed, reset the play next values
|
||||
play_next_dialog = None
|
||||
play_next_triggered = False
|
||||
now_playing = now_playing_file
|
||||
|
||||
duration = player.getTotalTime()
|
||||
position = player.getTime()
|
||||
trigger_time = play_next_trigger_time # 300
|
||||
@@ -51,7 +62,7 @@ class PlayNextService(threading.Thread):
|
||||
play_next_triggered = True
|
||||
log.debug("play_next_triggered hit at {0} seconds from end".format(time_to_end))
|
||||
|
||||
play_data = get_playing_data(self.monitor.played_information)
|
||||
play_data = get_playing_data()
|
||||
log.debug("play_next_triggered play_data : {0}".format(play_data))
|
||||
|
||||
next_episode = play_data.get("next_episode")
|
||||
@@ -78,6 +89,7 @@ class PlayNextService(threading.Thread):
|
||||
play_next_dialog = None
|
||||
|
||||
is_playing = False
|
||||
now_playing = None
|
||||
|
||||
if xbmc.Monitor().waitForAbort(1):
|
||||
break
|
||||
|
||||
@@ -13,6 +13,7 @@ from datetime import datetime
|
||||
import xbmcaddon
|
||||
import xbmcgui
|
||||
import xbmc
|
||||
from six import ensure_binary
|
||||
from kodi_six.utils import py2_decode
|
||||
|
||||
from .kodi_utils import HomeWindow
|
||||
@@ -132,10 +133,7 @@ def get_server_details():
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
sock.settimeout(4.0)
|
||||
|
||||
sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 3) # timeout
|
||||
sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
|
||||
sock.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_LOOP, 1)
|
||||
sock.setsockopt(socket.IPPROTO_IP, socket.SO_REUSEADDR, 1)
|
||||
|
||||
log.debug("MutliGroup: {0}".format(multi_group))
|
||||
log.debug("Sending UDP Data: {0}".format(message))
|
||||
@@ -318,7 +316,7 @@ def check_server(force=False, change_user=False, notify=False):
|
||||
user_item.setProperty("secure", "true")
|
||||
|
||||
m = hashlib.md5()
|
||||
m.update(name)
|
||||
m.update(ensure_binary(name))
|
||||
hashed_username = m.hexdigest()
|
||||
saved_password = settings.getSetting("saved_user_password_" + hashed_username)
|
||||
if saved_password:
|
||||
|
||||
@@ -5,6 +5,7 @@ import xbmcaddon
|
||||
import xbmc
|
||||
import xbmcvfs
|
||||
|
||||
import binascii
|
||||
import string
|
||||
import random
|
||||
import json
|
||||
@@ -14,6 +15,7 @@ import math
|
||||
from datetime import datetime
|
||||
import calendar
|
||||
import re
|
||||
from six import ensure_text, ensure_binary
|
||||
from six.moves.urllib.parse import urlencode
|
||||
|
||||
from .downloadutils import DownloadUtils
|
||||
@@ -295,14 +297,19 @@ def single_urlencode(text):
|
||||
return text.decode('utf-8') # return the result again as unicode
|
||||
|
||||
|
||||
def send_event_notification(method, data):
|
||||
message_data = json.dumps(data)
|
||||
source_id = "jellycon"
|
||||
base64_data = base64.b64encode(message_data.encode())
|
||||
escaped_data = '\\"[\\"{0}\\"]\\"'.format(base64_data)
|
||||
command = 'XBMC.NotifyAll({0}.SIGNAL,{1},{2})'.format(source_id, method, escaped_data)
|
||||
log.debug("Sending notification event data: {0}".format(command))
|
||||
xbmc.executebuiltin(command)
|
||||
def send_event_notification(method, data=None, hexlify=False):
|
||||
'''
|
||||
Send events through Kodi's notification system
|
||||
'''
|
||||
data = data or {}
|
||||
|
||||
if hexlify:
|
||||
# Used exclusively for the upnext plugin
|
||||
data = ensure_text(binascii.hexlify(ensure_binary(json.dumps(data))))
|
||||
sender = 'plugin.video.jellycon'
|
||||
data = '"[%s]"' % json.dumps(data).replace('"', '\\"')
|
||||
|
||||
xbmc.executebuiltin('NotifyAll(%s, %s, %s)' % (sender, method, data))
|
||||
|
||||
|
||||
def datetime_from_string(time_string):
|
||||
|
||||
|
Before Width: | Height: | Size: 312 B After Width: | Height: | Size: 137 B |
|
Before Width: | Height: | Size: 263 B After Width: | Height: | Size: 109 B |
@@ -67,6 +67,7 @@ image_server = HttpImageServerThread()
|
||||
image_server.start()
|
||||
|
||||
# set up all the services
|
||||
monitor = Service()
|
||||
playback_service = PlaybackService(monitor)
|
||||
|
||||
home_window = HomeWindow()
|
||||
|
||||