1.0.0+kodimov.13: updates don't stop live TV; IPTV Simple restarts only when idle
- After an add-on update the new service found port 57031 still held by the old proxy for a moment and moved to a random port; the stream playing kept asking 57031 for its manifest and died a minute later (.49, 2026-11-13). The proxy now waits up to 10 s for the port, and SO_REUSEADDR / allow_reuse_address are set before binding (upstream set them after, so they did nothing). - IPTV Simple is restarted only when nothing plays and no key was pressed for 30 s: on .49 a channel opened during a restart failed with an error. - After start or update, changed instance files (duplicate removed, refresh timer) are picked up by the guide reload instead of a restart of their own; the service restarts IPTV Simple itself only if that reload didn't happen within 10 minutes. 3 restarts after kodimov.12 -> 2. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
69a37ff064
commit
7873b50203
6 files changed
+63
-15
No files matched your search
@@ -18,7 +18,8 @@ What it adds:
|
||||
- **Gets along with Radios de Vigo** (`service.radios.vigo`), which keeps its own IPTV Simple instance for the Radio section. Kodi only lets *Use channel numbers from backend* be changed while it applies (one PVR instance loaded, or several and *always* on), so with a second instance it had refused the setting. Both add-ons now check it every so often: if it is hidden they turn *always* on, and they turn the setting itself on once; neither ever turns anything off, and turning it off by hand afterwards is respected. They also take turns to restart IPTV Simple, through the `pvr.iptvsimple.restarting` property of Kodi's home window.
|
||||
- **One IPTV Simple instance per channel list**: the TV guide setup rewrites the instance that already reads KodiMov+'s list (one set up with the original add-on, or by hand) instead of adding `instance-settings-91.xml` next to it, and the service deletes any extra one at Kodi start (keeping the one that isn't 91, which holds what was watched): two of them showed every channel twice.
|
||||
- Fixes the programme guide export of upstream 1.0.0 (the amazon.tv guide is a flat list).
|
||||
- Its own proxy port (57031), so it can run next to the original.
|
||||
- Its own proxy port (57031), so it can run next to the original. After an update the new proxy waits for the old one to free the port instead of moving to a random one, so the channel being watched keeps playing (upstream sets `allow_reuse_address` and `SO_REUSEADDR` too late to take effect).
|
||||
- **Restarts IPTV Simple only while idle**: nothing playing and no key pressed for 30 seconds (a channel opened during a restart fails). After start or update a single guide reload also picks up changed instance files.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<addon id="plugin.video.kodimovplus"
|
||||
name="KodiMov+"
|
||||
version="1.0.0+kodimov.12"
|
||||
version="1.0.0+kodimov.13"
|
||||
provider-name="Paco8, xocko">
|
||||
<requires>
|
||||
<!--- <import addon="xbmc.python" version="2.25.0"/> -->
|
||||
@@ -21,7 +21,8 @@
|
||||
<summary lang="es_ES">Movistar+ para Kodi, con inicio de sesión automático desde la red de Movistar</summary>
|
||||
<description lang="en_GB">Fork of Paco8's Movistar+ add-on (plugin.video.movistarplus). Logs in by itself from the Movistar home network, keeps the channel list and numbers up to date, plays the LALIGA, DAZN LALIGA and Liga de Campeones channels through Movistar's new servers (from the Movistar home network), hides the channels it can't play, adds free Galician channels (TVG2, TeleVigo) and writes a programme guide for every channel. Requires a Movistar+ subscription.</description>
|
||||
<description lang="es_ES">Fork del addon Movistar+ de Paco8 (plugin.video.movistarplus). Inicia sesión solo desde la red de Movistar, mantiene la lista y los números de los canales al día, reproduce los canales de LALIGA, DAZN LALIGA y Liga de Campeones a través de los servidores nuevos de Movistar (desde la red de Movistar de casa), oculta los canales que no puede reproducir, añade canales gallegos gratuitos (TVG2, TeleVigo) y genera la guía de programación de todos los canales. Se necesita estar abonado a Movistar+.</description>
|
||||
<news>1.0.0+kodimov.12: no more channels twice in the TV guide on boxes where the TV guide setup was run over an existing setup (the extra IPTV Simple instance is removed, and the setup now rewrites the existing one). LALIGA, DAZN LALIGA and Liga de Campeones no longer go missing for 6 hours when Movistar's new servers refuse the box's registration as a web player once: it is tried again, and the TV guide list is rewritten half an hour later.
|
||||
<news>1.0.0+kodimov.13: updating the add-on no longer stops the channel being watched (the proxy got a new port and the stream lost it). IPTV Simple is restarted only while nothing plays and nobody has used the remote for 30 seconds, and fewer times after an update.
|
||||
1.0.0+kodimov.12: no more channels twice in the TV guide on boxes where the TV guide setup was run over an existing setup (the extra IPTV Simple instance is removed, and the setup now rewrites the existing one). LALIGA, DAZN LALIGA and Liga de Campeones no longer go missing for 6 hours when Movistar's new servers refuse the box's registration as a web player once: it is tried again, and the TV guide list is rewritten half an hour later.
|
||||
1.0.0+kodimov.11: Movistar's channel numbers also show on boxes with more than one IPTV Simple instance (Radios de Vigo, a leftover empty one), where Kodi had refused the setting and numbered the channels 1, 2, 3...; existing TV guide setups are put right by themselves. KodiMov+ and Radios de Vigo no longer restart IPTV Simple at the same time.
|
||||
1.0.0+kodimov.10: the LALIGA, DAZN LALIGA and Liga de Campeones channels are back, live and catch-up, on boxes connected to the Movistar home network (their streams are now served only through Movistar's new servers). New setting to always play at the best quality, up to 1080p, instead of the 576p Kodi stays at on automatic (off by default). The "Error 4027" message no longer pops up when the add-on recovers from it by itself.
|
||||
1.0.0+kodimov.9: after Kodi starts or the add-on updates, a new programme guide shows up in Kodi within a couple of minutes instead of at the next hourly reload (only while nothing is playing).
|
||||
|
||||
@@ -492,25 +492,51 @@ def reload_iptv_guide(pvr_dir, addon_id):
|
||||
restart it with the hourly timer. Restarting stops live TV, so this does
|
||||
nothing if something is playing."""
|
||||
import xbmc
|
||||
monitor, player = xbmc.Monitor(), xbmc.Player()
|
||||
if player.isPlaying(): return
|
||||
monitor = xbmc.Monitor()
|
||||
if not wait_until_idle(timeout=600): return
|
||||
if not set_iptv_refresh(pvr_dir, addon_id, 1): return
|
||||
try:
|
||||
restart_iptv_simple()
|
||||
monitor.waitForAbort(90)
|
||||
finally:
|
||||
set_iptv_refresh(pvr_dir, addon_id, 60)
|
||||
while player.isPlaying(): # until then it keeps reloading every minute
|
||||
if monitor.waitForAbort(10): return
|
||||
if not monitor.abortRequested():
|
||||
if wait_until_idle(): # until then it keeps reloading every minute
|
||||
restart_iptv_simple()
|
||||
|
||||
|
||||
def is_idle(seconds=30):
|
||||
"""Nothing playing and nobody pressed a key for a while. Restarting IPTV
|
||||
Simple stops live TV, and a channel opened while it restarts fails."""
|
||||
import xbmc
|
||||
return not xbmc.Player().isPlaying() and xbmc.getGlobalIdleTime() >= seconds
|
||||
|
||||
|
||||
def wait_until_idle(timeout=None):
|
||||
"""Waits until is_idle(). False if Kodi is closing or the timeout ran out."""
|
||||
import xbmc
|
||||
monitor = xbmc.Monitor()
|
||||
end = time.time() + timeout if timeout else None
|
||||
while not is_idle():
|
||||
if monitor.waitForAbort(5) or (end and time.time() > end): return False
|
||||
return not monitor.abortRequested()
|
||||
|
||||
|
||||
# IPTV Simple is shared with other add-ons (Radios de Vigo keeps its own
|
||||
# instance for the Radio section). Restarting it restarts every instance, so
|
||||
# the add-ons take turns: whoever restarts it says so in this property of
|
||||
# Kodi's home window (the time it started), and the others wait.
|
||||
IPTV_RESTART_PROPERTY = 'pvr.iptvsimple.restarting'
|
||||
# When this add-on last restarted it, so the service can skip a restart that
|
||||
# one from the plugin (the guide reload) already did
|
||||
LAST_RESTART_PROPERTY = 'kodimovplus.iptvsimple.restarted'
|
||||
|
||||
|
||||
def last_iptv_restart():
|
||||
import xbmcgui
|
||||
try:
|
||||
return float(xbmcgui.Window(10000).getProperty(LAST_RESTART_PROPERTY) or 0)
|
||||
except ValueError:
|
||||
return 0
|
||||
|
||||
|
||||
def restart_iptv_simple():
|
||||
@@ -526,6 +552,7 @@ def restart_iptv_simple():
|
||||
if not busy: break
|
||||
xbmc.sleep(1000)
|
||||
window.setProperty(IPTV_RESTART_PROPERTY, str(time.time()))
|
||||
window.setProperty(LAST_RESTART_PROPERTY, str(time.time()))
|
||||
try:
|
||||
for enabled in (False, True):
|
||||
xbmc.executeJSONRPC(json.dumps({'jsonrpc': '2.0', 'id': 1, 'method': 'Addons.SetAddonEnabled',
|
||||
|
||||
@@ -835,7 +835,7 @@ def export_epg_now(quiet=False, reload_guide=False):
|
||||
if True: #not addon.getSettingBool('use_external_epg'):
|
||||
notify(addon.getLocalizedString(30311))
|
||||
changed = m.export_epg_to_xml(epg_filename, addon.getSettingInt('export_days'), report_progress, only_subscribed)
|
||||
if changed and reload_guide:
|
||||
if reload_guide == 'force' or (changed and reload_guide):
|
||||
from . import kodimov
|
||||
try:
|
||||
pvr_dir = translatePath(xbmcaddon.Addon('pvr.iptvsimple').getAddonInfo('profile'))
|
||||
@@ -941,7 +941,7 @@ def router(paramstring):
|
||||
elif params['action'] == 'create_iptv_settings':
|
||||
create_iptv_settings()
|
||||
elif params['action'] == 'export_epg_now':
|
||||
export_epg_now(quiet=params.get('quiet') == '1', reload_guide=params.get('reload_guide') == '1')
|
||||
export_epg_now(quiet=params.get('quiet') == '1', reload_guide=params.get('reload_guide'))
|
||||
elif params['action'] == 'to_wishlist':
|
||||
to_wishlist(params)
|
||||
elif 'iptv' in params['action']:
|
||||
|
||||
+13
-1
@@ -274,6 +274,10 @@ PORT = 57031
|
||||
|
||||
class ThreadedHTTPServer(ThreadingMixIn, HTTPServer):
|
||||
daemon_threads = True
|
||||
# KodiMov+: must be set before the server binds (setting it on the
|
||||
# instance afterwards did nothing): connections of the previous proxy
|
||||
# left in TIME_WAIT would otherwise keep the port taken
|
||||
allow_reuse_address = True
|
||||
|
||||
class Proxy(object):
|
||||
started = False
|
||||
@@ -281,8 +285,8 @@ class Proxy(object):
|
||||
def check_port(self, port=0, default=False):
|
||||
try:
|
||||
with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as s:
|
||||
s.bind((HOST, port))
|
||||
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
s.bind((HOST, port))
|
||||
return s.getsockname()[1]
|
||||
except:
|
||||
return default
|
||||
@@ -292,6 +296,14 @@ class Proxy(object):
|
||||
return
|
||||
|
||||
port = self.check_port(PORT)
|
||||
# KodiMov+: when the add-on updates, the previous service may still
|
||||
# hold the port for a few seconds. Wait for it: a stream that is
|
||||
# playing keeps asking this port for its manifest, and dies if the
|
||||
# proxy moves to another one.
|
||||
for _ in range(20):
|
||||
if port: break
|
||||
time.sleep(0.5)
|
||||
port = self.check_port(PORT)
|
||||
if not port:
|
||||
port = self.check_port(0)
|
||||
LOG('port: {}'.format(port))
|
||||
|
||||
+11
-4
@@ -29,7 +29,8 @@ if __name__ == '__main__':
|
||||
# programme guide a minute after Kodi starts and then every 6 hours; a
|
||||
# refresh that failed is tried again half an hour later. Opening the add-on
|
||||
# also renews the 10-day Movistar login.
|
||||
next_check = time.time() + 60
|
||||
started = time.time()
|
||||
next_check = started + 60
|
||||
max_age = 0 # always refresh once after Kodi starts
|
||||
new_api_retries = 6
|
||||
try:
|
||||
@@ -39,12 +40,17 @@ if __name__ == '__main__':
|
||||
except RuntimeError: # IPTV Simple not installed or disabled
|
||||
pvr_dir = None
|
||||
restart_iptv = False
|
||||
player = xbmc.Player()
|
||||
# A changed instance file needs IPTV Simple restarted. The guide reload
|
||||
# after start (below) restarts it anyway, so that one is left to do it;
|
||||
# this is only the fallback, 10 minutes later, if it didn't happen.
|
||||
restart_after = started + 10 * 60
|
||||
monitor = xbmc.Monitor()
|
||||
while not monitor.abortRequested():
|
||||
if monitor.waitForAbort(1):
|
||||
break
|
||||
if restart_iptv and not player.isPlaying(): # restarting stops live TV
|
||||
if restart_iptv and kodimov.last_iptv_restart() > started:
|
||||
restart_iptv = False
|
||||
if restart_iptv and time.time() >= restart_after and kodimov.is_idle():
|
||||
restart_iptv = False
|
||||
kodimov.restart_iptv_simple()
|
||||
if time.time() >= next_check:
|
||||
@@ -57,13 +63,14 @@ if __name__ == '__main__':
|
||||
age_limit, max_age = max_age, 6 * 3600 - 120
|
||||
# After Kodi starts (or this add-on updates) also get the new guide into Kodi now
|
||||
reload_guide = '&reload_guide=1' if age_limit == 0 else ''
|
||||
if restart_iptv: reload_guide = '&reload_guide=force' # also for the changed instance files
|
||||
# The new servers failed (they at times refuse everything for minutes):
|
||||
# the list lacks LALIGA, DAZN LALIGA, Liga de Campeones. Try again in
|
||||
# half an hour, a few times, instead of in 6 hours.
|
||||
if new_api_retries and kodimov.new_api_failed(profile_dir):
|
||||
new_api_retries -= 1
|
||||
age_limit = 0
|
||||
reload_guide = '&reload_guide=1'
|
||||
reload_guide = reload_guide or '&reload_guide=1'
|
||||
if addon.getSettingBool('auto_export_epg'): # channels + programme guide
|
||||
if file_age(os.path.join(profile_dir, 'epg.xml')) > age_limit:
|
||||
exporting = True
|
||||
|
||||
Reference in new issue
Block a user