6 Commits

Author SHA1 Message Date
mcarlton00
6121537216 Merge pull request #106 from mcarlton00/track-ordering
Some checks failed
Build JellyCon / build (py2) (push) Has been cancelled
Build JellyCon / build (py3) (push) Has been cancelled
Only set the cast if they exist
2021-12-12 17:04:12 -05:00
mcarlton00
2482f11a5a Merge pull request #105 from mcarlton00/stopped-playback-v2
Fix stopped playback reporting
2021-12-12 17:03:19 -05:00
Matt
ade08f74a4 Only set the cast if they exist 2021-12-12 13:43:45 -05:00
Matt
5eade9abe5 Fix stopped playback reporting 2021-12-11 21:00:28 -05:00
mcarlton00
203986d54c Merge pull request #104 from mcarlton00/exclude-git-history
Exclude git history from published addon
2021-12-09 20:14:30 -05:00
Matt
8e8c376df3 Exclude git history from published addon 2021-12-09 18:31:18 -05:00
4 changed files with 104 additions and 108 deletions

View File

@@ -1,70 +0,0 @@
import xml.etree.ElementTree as ET
import sys
import os
from datetime import datetime
import yaml
def indent(elem, level=0):
'''
Nicely formats output xml with newlines and spaces
https://stackoverflow.com/a/33956544
'''
i = "\n" + level*" "
if len(elem):
if not elem.text or not elem.text.strip():
elem.text = i + " "
if not elem.tail or not elem.tail.strip():
elem.tail = i
for elem in elem:
indent(elem, level+1)
if not elem.tail or not elem.tail.strip():
elem.tail = i
else:
if level and (not elem.tail or not elem.tail.strip()):
elem.tail = i
try:
py_version = sys.argv[1]
except IndexError:
print('No version specified')
sys.exit(1)
dir_path = os.path.dirname(os.path.realpath(__file__))
# Load template file
with open('{dir_path}/template.xml'.format(**locals()), 'r') as f:
tree = ET.parse(f)
root = tree.getroot()
# Load version dependencies
with open('{dir_path}/{py_version}.yaml'.format(**locals()), 'r') as f:
deps = yaml.safe_load(f)
# Load version and changelog
with open('jellyfin-kodi/release.yaml', 'r') as f:
data = yaml.safe_load(f)
# Populate xml template
for dep in deps:
ET.SubElement(root.find('requires'), 'import', attrib=dep)
# Update version string
addon_version = data.get('version')
root.attrib['version'] = '{addon_version}+{py_version}'.format(**locals())
# Changelog
date = datetime.today().strftime('%Y-%m-%d')
changelog = data.get('changelog')
for section in root.findall('extension'):
news = section.findall('news')
if news:
news[0].text = 'v{addon_version} ({date}):\n{changelog}'.format(**locals())
# Format xml tree
indent(root)
# Write addon.xml
tree.write('jellyfin-kodi/addon.xml', encoding='utf-8', xml_declaration=True)

View File

@@ -1,28 +1,28 @@
#!/usr/bin/env python
import argparse
from datetime import datetime
import os
from pathlib import Path
import xml.etree.ElementTree as ET
import zipfile
from datetime import datetime
from pathlib import Path
import yaml
def indent(elem, level=0):
'''
def indent(elem: ET.Element, level: int = 0) -> None:
"""
Nicely formats output xml with newlines and spaces
https://stackoverflow.com/a/33956544
'''
i = "\n" + level*" "
"""
i = "\n" + level * " "
if len(elem):
if not elem.text or not elem.text.strip():
elem.text = i + " "
if not elem.tail or not elem.tail.strip():
elem.tail = i
for elem in elem:
indent(elem, level+1)
indent(elem, level + 1)
if not elem.tail or not elem.tail.strip():
elem.tail = i
else:
@@ -30,10 +30,10 @@ def indent(elem, level=0):
elem.tail = i
def create_addon_xml(config, source, py_version):
'''
def create_addon_xml(config: dict, source: str, py_version: str) -> None:
"""
Create addon.xml from template file
'''
"""
# Load template file
with open('{}/.config/template.xml'.format(source), 'r') as f:
tree = ET.parse(f)
@@ -63,21 +63,54 @@ def create_addon_xml(config, source, py_version):
tree.write('{}/addon.xml'.format(source), encoding='utf-8', xml_declaration=True)
def zip_files(py_version, source, target):
'''
def zip_files(py_version: str, source: str, target: str, dev: bool) -> None:
"""
Create installable addon zip archive
'''
"""
archive_name = 'plugin.video.jellycon+{}.zip'.format(py_version)
with zipfile.ZipFile('{}/{}'.format(target, archive_name), 'w') as z:
for root, dirs, files in os.walk(args.source):
for filename in files:
if 'plugin.video.jellycon' not in filename and 'pyo' not in filename:
file_path = os.path.join(root, filename)
for filename in filter(file_filter, files):
file_path = os.path.join(root, filename)
if dev or folder_filter(file_path):
relative_path = os.path.join('plugin.video.jellycon', os.path.relpath(file_path, source))
z.write(file_path, relative_path)
def file_filter(file_name: str) -> bool:
"""
True if file_name is meant to be included
"""
return (
not (file_name.startswith('plugin.video.jellycon') and file_name.endswith('.zip'))
and not file_name.endswith('.pyo')
and not file_name.endswith('.pyc')
and not file_name.endswith('.pyd')
)
def folder_filter(folder_name: str) -> bool:
"""
True if folder_name is meant to be included
"""
filters = [
'.ci',
'.git',
'.github',
'.config',
'.mypy_cache',
'.pytest_cache',
'__pycache__',
]
for f in filters:
if f in folder_name.split(os.path.sep):
return False
return True
if __name__ == '__main__':
parser = argparse.ArgumentParser(description='Build flags:')
parser.add_argument(
@@ -96,13 +129,16 @@ if __name__ == '__main__':
type=Path,
default=Path(__file__).absolute().parent)
parser.add_argument('--dev', dest='dev', action='store_true')
parser.set_defaults(dev=False)
args = parser.parse_args()
# Load config file
config_path = os.path.join(args.source, 'release.yaml')
with open(config_path, 'r') as fh:
config = yaml.safe_load(fh)
release_config = yaml.safe_load(fh)
create_addon_xml(config, args.source, args.version)
create_addon_xml(release_config, args.source, args.version)
zip_files(args.version, args.source, args.target)
zip_files(args.version, args.source, args.target, args.dev)

View File

@@ -471,7 +471,7 @@ def add_gui_item(url, item_details, display_options, folder=True, default_sort=F
info_labels = {}
# add cast
if item_details.cast is not None:
if item_details.cast:
if kodi_version >= 17:
list_item.setCast(item_details.cast)
else:

View File

@@ -877,8 +877,7 @@ def external_subs(media_source, list_item, item_id):
def send_progress():
home_window = HomeWindow()
play_data_string = home_window.get_property('now_playing')
play_data = json.loads(play_data_string)
play_data = get_playing_data()
if play_data is None:
return
@@ -1011,7 +1010,15 @@ def prompt_for_stop_actions(item_id, data):
xbmc.executebuiltin("Container.Refresh")
def stop_all_playback(played_information):
def stop_all_playback():
home_window = HomeWindow()
played_information_string = home_window.get_property('played_information')
if played_information_string:
played_information = json.loads(played_information_string)
else:
played_information = {}
log.debug("stop_all_playback : {0}".format(played_information))
if len(played_information) == 0:
@@ -1020,8 +1027,7 @@ def stop_all_playback(played_information):
log.debug("played_information: {0}".format(played_information))
clear_entries = []
home_screen = HomeWindow()
home_screen.clear_property("currently_playing_id")
home_window.clear_property("currently_playing_id")
for item in played_information:
data = played_information.get(item)
@@ -1061,33 +1067,53 @@ def stop_all_playback(played_information):
for entry in clear_entries:
del played_information[entry]
home_window.set_property('played_information', json.dumps(played_information))
def get_playing_data():
player = xbmc.Player()
home_window = HomeWindow()
play_data_string = home_window.get_property('now_playing')
play_data = json.loads(play_data_string)
played_information_string = home_window.get_property('played_information')
if played_information_string:
played_information = json.loads(played_information_string)
else:
played_information = {}
playlist_data_string = home_window.get_property('playlist')
playlist_data = json.loads(playlist_data_string)
if playlist_data_string:
playlist_data = json.loads(playlist_data_string)
else:
playlist_data = {}
item_id = play_data.get("item_id")
settings = xbmcaddon.Addon()
server = settings.getSetting('server_address')
try:
playing_file = xbmc.Player().getPlayingFile()
playing_file = player.getPlayingFile()
except Exception as e:
log.error("get_playing_data : getPlayingFile() : {0}".format(e))
return None
log.debug("get_playing_data : getPlayingFile() : {0}".format(playing_file))
if server in playing_file:
if item_id is not None and item_id in playing_file:
return play_data
elif item_id is not None and item_id not in playing_file and playing_file in playlist_data:
if server in playing_file and item_id is not None:
play_time = player.getTime()
total_play_time = player.getTotalTime()
if item_id is not None and item_id not in playing_file and playing_file in playlist_data:
# if the current now_playing data isn't correct, pull it from the playlist_data
play_data = playlist_data.pop(playing_file)
# Update now_playing data
home_window.set_property('now_playing', json.dumps(play_data))
home_window.set_property('playlist', json.dumps(playlist_data))
return play_data
play_data["current_position"] = play_time
play_data["duration"] = total_play_time
played_information[item_id] = play_data
home_window.set_property('now_playing', json.dumps(play_data))
home_window.set_property('played_information', json.dumps(played_information))
return play_data
return {}
@@ -1096,11 +1122,10 @@ class Service(xbmc.Player):
def __init__(self, *args):
log.debug("Starting monitor service: {0}".format(args))
self.played_information = {}
def onPlayBackStarted(self):
# Will be called when xbmc starts playing a file
stop_all_playback(self.played_information)
stop_all_playback()
if not xbmc.Player().isPlaying():
log.debug("onPlayBackStarted: not playing file!")
@@ -1123,7 +1148,12 @@ class Service(xbmc.Player):
if jellyfin_item_id is None:
return
self.played_information[jellyfin_item_id] = play_data
home_window = HomeWindow()
played_information_string = home_window.get_property('played_information')
played_information = json.loads(played_information_string)
played_information[jellyfin_item_id] = play_data
home_window.set_property('played_information', json.dumps(played_information))
log.debug("Sending Playback Started")
postdata = {
'QueueableMediaTypes': "Video",
@@ -1145,12 +1175,12 @@ class Service(xbmc.Player):
def onPlayBackEnded(self):
# Will be called when kodi stops playing a file
log.debug("onPlayBackEnded")
stop_all_playback(self.played_information)
stop_all_playback()
def onPlayBackStopped(self):
# Will be called when user stops kodi playing a file
log.debug("onPlayBackStopped")
stop_all_playback(self.played_information)
stop_all_playback()
def onPlayBackPaused(self):
# Will be called when kodi pauses the video