Skip to content

Commit

Permalink
Merge pull request #889 from MoojMidge/master
Browse files Browse the repository at this point in the history
v7.0.9.2
  • Loading branch information
MoojMidge authored Aug 25, 2024
2 parents 458cdd7 + 5691276 commit a3aa480
Show file tree
Hide file tree
Showing 9 changed files with 74 additions and 46 deletions.
2 changes: 1 addition & 1 deletion addon.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<addon id="plugin.video.youtube" name="YouTube" version="7.0.9.1" provider-name="anxdpanic, bromix, MoojMidge">
<addon id="plugin.video.youtube" name="YouTube" version="7.0.9.2" provider-name="anxdpanic, bromix, MoojMidge">
<requires>
<import addon="xbmc.python" version="3.0.0"/>
<import addon="script.module.requests" version="2.27.1"/>
Expand Down
6 changes: 6 additions & 0 deletions changelog.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
## v7.0.9.2
### Fixed
- Fix various Kodi 18 listitem setInfo compatibility issues
- Additional fixes and compatibility shims for playing AudioItems #873
- Fix early thread loop termination in My Subscriptions #888

## v7.0.9.1
### Fixed
- Add playlist_type_hint property to workaround issues with CPlayListPlayer::Play #873
Expand Down
6 changes: 3 additions & 3 deletions resources/lib/youtube_plugin/kodion/compatibility/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,9 +137,9 @@ def to_str(value):

# Kodi v20+
if hasattr(xbmcgui.ListItem, 'setDateTime'):
def datetime_infolabel(datetime_obj):
def datetime_infolabel(datetime_obj, *_args, **_kwargs):
return datetime_obj.replace(microsecond=0, tzinfo=None).isoformat()
# Compatibility shims for Kodi v18 and v19
else:
def datetime_infolabel(datetime_obj):
return datetime_obj.strftime('%d.%m.%Y')
def datetime_infolabel(datetime_obj, str_format='%Y-%m-%d %H:%M:%S'):
return datetime_obj.strftime(str_format)
2 changes: 1 addition & 1 deletion resources/lib/youtube_plugin/kodion/items/base_item.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ def set_date_from_datetime(self, date_time):
def get_date(self, as_text=False, short=False, as_info_label=False):
if self._date:
if as_info_label:
return datetime_infolabel(self._date)
return datetime_infolabel(self._date, '%d.%m.%Y')
if short:
return self._date.date().strftime('%x')
if as_text:
Expand Down
6 changes: 3 additions & 3 deletions resources/lib/youtube_plugin/kodion/items/media_item.py
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ def set_mediatype(self, mediatype):
self._mediatype = self._DEFAULT_MEDIATYPE

def get_mediatype(self):
return self._mediatype
return self._mediatype or self._DEFAULT_MEDIATYPE

def set_plot(self, plot):
try:
Expand Down Expand Up @@ -381,7 +381,7 @@ def playlist_item_id(self, value):


class AudioItem(MediaItem):
_ALLOWABLE_MEDIATYPES = {'song', 'album', 'artist'}
_ALLOWABLE_MEDIATYPES = {CONTENT.AUDIO_TYPE, 'song', 'album', 'artist'}
_DEFAULT_MEDIATYPE = CONTENT.AUDIO_TYPE

def __init__(self, name, uri, image='DefaultAudio.png', fanart=None):
Expand All @@ -396,7 +396,7 @@ def get_album_name(self):


class VideoItem(MediaItem):
_ALLOWABLE_MEDIATYPES = {'video',
_ALLOWABLE_MEDIATYPES = {CONTENT.VIDEO_TYPE,
'movie',
'tvshow', 'season', 'episode',
'musicvideo'}
Expand Down
27 changes: 19 additions & 8 deletions resources/lib/youtube_plugin/kodion/items/xbmc/xbmc_items.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ def set_info(list_item, item, properties, set_play_count=True, resume=True):
else:
return

value = item.get_artists_string()
value = item.get_artists()
if value is not None:
info_labels['artist'] = value

Expand Down Expand Up @@ -321,12 +321,20 @@ def set_info(list_item, item, properties, set_play_count=True, resume=True):

resume_time = resume and item.get_start_time()
duration = item.get_duration()
if resume_time and duration:
info_tag.setResumePoint(resume_time, float(duration))
elif resume_time:
info_tag.setResumePoint(resume_time)
if info_type == 'video' and duration:
info_tag.addVideoStream(xbmc.VideoStreamDetail(duration=duration))
if info_type == 'video':
if resume_time and duration:
info_tag.setResumePoint(resume_time, float(duration))
elif resume_time:
info_tag.setResumePoint(resume_time)
if duration:
info_tag.addVideoStream(xbmc.VideoStreamDetail(duration=duration))
elif info_type == 'music':
# These properties are deprecated but there is no other way to set these
# details for a ListItem with a MusicInfoTag
if resume_time:
properties['ResumeTime'] = str(resume_time)
if duration:
properties['TotalTime'] = str(duration)

# duration: int
# As seconds
Expand All @@ -346,7 +354,10 @@ def set_info(list_item, item, properties, set_play_count=True, resume=True):
value = item.get_play_count()
if value is not None:
if set_play_count:
info_tag.setPlaycount(value)
if info_type == 'video':
info_tag.setPlaycount(value)
elif info_type == 'music':
info_tag.setPlayCount(value)
properties[PLAY_COUNT] = value

# count: int
Expand Down
2 changes: 1 addition & 1 deletion resources/lib/youtube_plugin/kodion/network/requests.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ def cert_verify(self, conn, url, verify, cert):
self._ssl_context.check_hostname = bool(verify)
return super(SSLHTTPAdapter, self).cert_verify(conn, url, verify, cert)


class BaseRequestsClass(object):
_session = Session()
_session.mount('https://', SSLHTTPAdapter(
Expand All @@ -50,7 +51,6 @@ class BaseRequestsClass(object):
total=3,
backoff_factor=0.1,
status_forcelist={500, 502, 503, 504},
allowed_methods=None,
)
))
atexit.register(_session.close)
Expand Down
63 changes: 36 additions & 27 deletions resources/lib/youtube_plugin/youtube/client/youtube.py
Original file line number Diff line number Diff line change
Expand Up @@ -1636,15 +1636,14 @@ def _threaded_fetch(kwargs,
input_wait.release()
if kwargs:
continue
complete = True
break
else:
complete = True
break

try:
success, complete = worker(output, **_kwargs)
except Exception as exc:
except Exception:
msg = 'get_my_subscriptions._threaded_fetch - {exc}'
self._context.log_error(msg.format(exc=format_exc()))
continue
Expand All @@ -1654,31 +1653,35 @@ def _threaded_fetch(kwargs,
else:
threads['balance'].clear()

current_thread = threading.current_thread()
threads['available'].release()
threads['counter'].release()
if complete:
threads['pool_counts'][pool_id] = None
threads['counts'][pool_id] = None
else:
threads['pool_counts'][pool_id] -= 1
threads['pool_counts']['all'] -= 1
threads['current'].discard(current_thread)
threads['counts'][pool_id] -= 1
threads['counts']['all'] -= 1
threads['current'].discard(threading.current_thread())
threads['loop'].set()

try:
num_cores = cpu_count() or 1
except NotImplementedError:
num_cores = 1
max_threads = min(32, 2 * (num_cores + 4))
counts = {
'all': 0,
}
current_threads = set()
counter = threading.Semaphore(max_threads)
balance_enable = threading.Event()
loop_enable = threading.Event()
threads = {
'max': max_threads,
'available': threading.Semaphore(max_threads),
'current': set(),
'pool_counts': {
'all': 0,
},
'balance': threading.Event(),
'loop': threading.Event(),
'balance': balance_enable,
'loop': loop_enable,
'counter': counter,
'counts': counts,
'current': current_threads,
}

payloads = {}
if logged_in:
payloads[1] = {
Expand All @@ -1688,6 +1691,7 @@ def _threaded_fetch(kwargs,
'threads': threads,
'limit': 1,
'input_wait': None,
'input_wait_for': None,
}
payloads.update({
2: {
Expand All @@ -1697,6 +1701,7 @@ def _threaded_fetch(kwargs,
'threads': threads,
'limit': 1,
'input_wait': threading.Lock(),
'input_wait_for': 1,
},
3: {
'worker': _get_feed,
Expand All @@ -1705,18 +1710,19 @@ def _threaded_fetch(kwargs,
'threads': threads,
'limit': None,
'input_wait': threading.Lock(),
'input_wait_for': 2,
},
})

completed = []
iterator = iter(payloads)
threads['loop'].set()
while threads['loop'].wait():
loop_enable.set()
while loop_enable.wait():
try:
pool_id = next(iterator)
except StopIteration:
threads['loop'].clear()
if not threads['current']:
loop_enable.clear()
if not current_threads:
break
for pool_id in completed:
del payloads[pool_id]
Expand All @@ -1726,7 +1732,7 @@ def _threaded_fetch(kwargs,

payload = payloads[pool_id]
payload['pool_id'] = pool_id
current_num = threads['pool_counts'].setdefault(pool_id, 0)
current_num = counts.setdefault(pool_id, 0)
if current_num is None:
completed.append(pool_id)
continue
Expand All @@ -1736,15 +1742,18 @@ def _threaded_fetch(kwargs,
if input_wait and input_wait.locked():
input_wait.release()
else:
input_wait_for = payload['input_wait_for']
if not input_wait_for or input_wait_for not in payloads:
completed.append(pool_id)
continue

available = threads['max'] - threads['pool_counts']['all']
available = max_threads - counts['all']
limit = payload['limit']
if limit:
if current_num >= limit:
continue
if available <= 0:
threads['balance'].set()
balance_enable.set()
elif available <= 0:
continue

Expand All @@ -1753,10 +1762,10 @@ def _threaded_fetch(kwargs,
kwargs=payload,
)
new_thread.daemon = True
threads['current'].add(new_thread)
threads['pool_counts'][pool_id] += 1
threads['pool_counts']['all'] += 1
threads['available'].acquire(True)
current_threads.add(new_thread)
counts[pool_id] += 1
counts['all'] += 1
counter.acquire(True)
new_thread.start()

items = _parse_feeds(threaded_output['feeds'])
Expand Down
6 changes: 4 additions & 2 deletions resources/lib/youtube_plugin/youtube/helper/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
from math import log10

from ...kodion.constants import CONTENT, LICENSE_TOKEN, LICENSE_URL, PATHS
from ...kodion.items import DirectoryItem, menu_items
from ...kodion.items import AudioItem, DirectoryItem, menu_items
from ...kodion.utils import (
datetime_parser,
friendly_number,
Expand Down Expand Up @@ -431,7 +431,9 @@ def update_video_infos(provider, context, video_id_dict,

media_item = video_id_dict[video_id]
media_item.set_mediatype(
CONTENT.AUDIO_TYPE if audio_only else CONTENT.VIDEO_TYPE
CONTENT.AUDIO_TYPE
if audio_only or isinstance(media_item, AudioItem) else
CONTENT.VIDEO_TYPE
)

play_data = use_play_data and yt_item.get('play_data')
Expand Down

0 comments on commit a3aa480

Please sign in to comment.