1.0.0+kodimov.12: no duplicate TV guide instance; retry the web player registration
- The TV guide setup always wrote instance-settings-91.xml, so on a box already set up with another instance (from the original add-on) both read channels.m3u8 and every channel showed twice. The setup now rewrites the instance that already reads the list, and the service deletes extra ones at start (keeps the one that isn't 91, which holds what was watched) and restarts IPTV Simple when nothing plays. - The web player registration for the new servers got one 401 error page and gave up, and the TV guide list then lacked LALIGA, DAZN LALIGA and Liga de Campeones until the next export 6 hours later. The registration is tried 3 times, and after a failure the service exports the list again every half hour, up to 6 times. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
b3bc561c35
commit
69a37ff064
5 files changed
+71
-8
No files matched your search
@@ -16,6 +16,7 @@ What it adds:
|
|||||||
- **Extra free channels** in the TV guide list: TVG2 (10) and TeleVigo (15).
|
- **Extra free channels** in the TV guide list: TVG2 (10) and TeleVigo (15).
|
||||||
- **The TV guide stays current**: channel list and programme guide re-exported every 6 hours, numbered with Movistar's own dial numbers. Listings come from Movistar (with catch-up links) for its channels and from the public EPG_dobleM guide for the extras.
|
- **The TV guide stays current**: channel list and programme guide re-exported every 6 hours, numbered with Movistar's own dial numbers. Listings come from Movistar (with catch-up links) for its channels and from the public EPG_dobleM guide for the extras.
|
||||||
- **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.
|
- **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).
|
- 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.
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
<addon id="plugin.video.kodimovplus"
|
<addon id="plugin.video.kodimovplus"
|
||||||
name="KodiMov+"
|
name="KodiMov+"
|
||||||
version="1.0.0+kodimov.11"
|
version="1.0.0+kodimov.12"
|
||||||
provider-name="Paco8, xocko">
|
provider-name="Paco8, xocko">
|
||||||
<requires>
|
<requires>
|
||||||
<!--- <import addon="xbmc.python" version="2.25.0"/> -->
|
<!--- <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>
|
<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="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>
|
<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.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.
|
<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.
|
||||||
|
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.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).
|
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).
|
||||||
1.0.0+kodimov.8: the programme guide refresh no longer fails at random inside Kodi, and a failed refresh is tried again half an hour later instead of 6 hours later.
|
1.0.0+kodimov.8: the programme guide refresh no longer fails at random inside Kodi, and a failed refresh is tried again half an hour later instead of 6 hours later.
|
||||||
|
|||||||
@@ -320,7 +320,9 @@ def _web_device_id(m, account_number):
|
|||||||
m.cache.save_file('web_device_id.conf', own)
|
m.cache.save_file('web_device_id.conf', own)
|
||||||
return own
|
return own
|
||||||
token = _autologin(m, uuid.uuid4().hex)
|
token = _autologin(m, uuid.uuid4().hex)
|
||||||
status, text = _soter(m, 'post', SOTER_DEVICES_URL.format(account=account_number), token, attempts=1)
|
# Like the other calls, it at times gets a 401 error page for no reason
|
||||||
|
# (seen 2026-11-13: refused once, registered on the next try)
|
||||||
|
status, text = _soter(m, 'post', SOTER_DEVICES_URL.format(account=account_number), token, attempts=3)
|
||||||
device_id = text.strip().strip('"')
|
device_id = text.strip().strip('"')
|
||||||
if status not in (200, 201) or len(device_id) != 32:
|
if status not in (200, 201) or len(device_id) != 32:
|
||||||
raise ValueError('device registration refused ({})'.format(status))
|
raise ValueError('device registration refused ({})'.format(status))
|
||||||
@@ -385,6 +387,16 @@ def new_api_ready(m):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def new_api_failed(profile_dir):
|
||||||
|
"""True if the last try to reach the new servers failed and none ever
|
||||||
|
worked: the TV guide list was written without LALIGA, DAZN LALIGA and
|
||||||
|
Liga de Campeones, so the service exports it again sooner."""
|
||||||
|
import glob
|
||||||
|
for stamp in glob.glob(os.path.join(profile_dir, 'account_*', 'new_api.stamp')):
|
||||||
|
if not os.path.exists(os.path.join(os.path.dirname(stamp), 'new_api.json')): return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
def _token_life(m, token):
|
def _token_life(m, token):
|
||||||
"""Seconds until the token expires (negative: expired or unreadable)."""
|
"""Seconds until the token expires (negative: expired or unreadable)."""
|
||||||
props = m.get_token_properties(token) if token else None
|
props = m.get_token_properties(token) if token else None
|
||||||
@@ -523,16 +535,51 @@ def restart_iptv_simple():
|
|||||||
window.clearProperty(IPTV_RESTART_PROPERTY)
|
window.clearProperty(IPTV_RESTART_PROPERTY)
|
||||||
|
|
||||||
|
|
||||||
def has_iptv_instance(pvr_dir, addon_id):
|
SETUP_INSTANCE_FILE = 'instance-settings-91.xml' # written by "Create IPTV settings"
|
||||||
"""True if an IPTV Simple instance reads this add-on's channel list."""
|
|
||||||
|
|
||||||
|
def iptv_instance_files(pvr_dir, addon_id):
|
||||||
|
"""The IPTV Simple instance files that read this add-on's channel list,
|
||||||
|
the one to keep first: a box set up before (with the original add-on, or
|
||||||
|
by hand) has its instance besides 91, and that one holds what was watched;
|
||||||
|
91 is the one the TV guide setup writes."""
|
||||||
import glob
|
import glob
|
||||||
|
res = []
|
||||||
for filename in glob.glob(os.path.join(pvr_dir, 'instance-settings-*.xml')):
|
for filename in glob.glob(os.path.join(pvr_dir, 'instance-settings-*.xml')):
|
||||||
try:
|
try:
|
||||||
with io.open(filename, 'r', encoding='utf-8') as f:
|
with io.open(filename, 'r', encoding='utf-8') as f:
|
||||||
if 'plugin.video.{}/channels.m3u8'.format(addon_id) in f.read(): return True
|
if 'plugin.video.{}/channels.m3u8'.format(addon_id) in f.read(): res.append(filename)
|
||||||
except (IOError, OSError):
|
except (IOError, OSError):
|
||||||
pass
|
pass
|
||||||
return False
|
def number(filename):
|
||||||
|
try:
|
||||||
|
return int(os.path.basename(filename)[len('instance-settings-'):-len('.xml')])
|
||||||
|
except ValueError:
|
||||||
|
return 0
|
||||||
|
res.sort(key=lambda f: (os.path.basename(f) == SETUP_INSTANCE_FILE, number(f)))
|
||||||
|
return res
|
||||||
|
|
||||||
|
|
||||||
|
def has_iptv_instance(pvr_dir, addon_id):
|
||||||
|
"""True if an IPTV Simple instance reads this add-on's channel list."""
|
||||||
|
return bool(iptv_instance_files(pvr_dir, addon_id))
|
||||||
|
|
||||||
|
|
||||||
|
def remove_duplicate_instances(pvr_dir, addon_id):
|
||||||
|
"""Two instances reading the same channel list put every channel twice in
|
||||||
|
the TV guide. That happened when the TV guide setup (instance 91) was run
|
||||||
|
on a box already set up with another instance. Keeps one and deletes the
|
||||||
|
others. Returns True if a file was deleted (IPTV Simple must be restarted
|
||||||
|
to drop it)."""
|
||||||
|
removed = False
|
||||||
|
for filename in iptv_instance_files(pvr_dir, addon_id)[1:]:
|
||||||
|
try:
|
||||||
|
os.remove(filename)
|
||||||
|
LOG('remove_duplicate_instances: removed {}'.format(filename))
|
||||||
|
removed = True
|
||||||
|
except OSError as e:
|
||||||
|
LOG('remove_duplicate_instances: {}: {}'.format(filename, e))
|
||||||
|
return removed
|
||||||
|
|
||||||
|
|
||||||
def ensure_channel_numbers(marker):
|
def ensure_channel_numbers(marker):
|
||||||
|
|||||||
@@ -781,6 +781,11 @@ def create_iptv_settings():
|
|||||||
pvr_dir = translatePath(pvr_addon.getAddonInfo('profile'))
|
pvr_dir = translatePath(pvr_addon.getAddonInfo('profile'))
|
||||||
LOG('pvr_dir: {}'.format(pvr_dir))
|
LOG('pvr_dir: {}'.format(pvr_dir))
|
||||||
filename = os.path.join(pvr_dir, output_file)
|
filename = os.path.join(pvr_dir, output_file)
|
||||||
|
if kodi_version > 19:
|
||||||
|
# Rewrite the instance that already reads this add-on's list, if any:
|
||||||
|
# a second one would show every channel twice
|
||||||
|
existing = kodimov.iptv_instance_files(pvr_dir, 'kodimovplus')
|
||||||
|
if existing: filename = existing[0]
|
||||||
if os.path.exists(filename):
|
if os.path.exists(filename):
|
||||||
res = xbmcgui.Dialog().yesno(addon.getLocalizedString(30322), addon.getLocalizedString(30323))
|
res = xbmcgui.Dialog().yesno(addon.getLocalizedString(30322), addon.getLocalizedString(30323))
|
||||||
if res == False: return
|
if res == False: return
|
||||||
|
|||||||
+10
-1
@@ -31,9 +31,11 @@ if __name__ == '__main__':
|
|||||||
# also renews the 10-day Movistar login.
|
# also renews the 10-day Movistar login.
|
||||||
next_check = time.time() + 60
|
next_check = time.time() + 60
|
||||||
max_age = 0 # always refresh once after Kodi starts
|
max_age = 0 # always refresh once after Kodi starts
|
||||||
|
new_api_retries = 6
|
||||||
try:
|
try:
|
||||||
pvr_dir = translatePath(xbmcaddon.Addon('pvr.iptvsimple').getAddonInfo('profile'))
|
pvr_dir = translatePath(xbmcaddon.Addon('pvr.iptvsimple').getAddonInfo('profile'))
|
||||||
restart_iptv = kodimov.set_iptv_refresh(pvr_dir, 'kodimovplus')
|
restart_iptv = kodimov.remove_duplicate_instances(pvr_dir, 'kodimovplus')
|
||||||
|
restart_iptv = kodimov.set_iptv_refresh(pvr_dir, 'kodimovplus') or restart_iptv
|
||||||
except RuntimeError: # IPTV Simple not installed or disabled
|
except RuntimeError: # IPTV Simple not installed or disabled
|
||||||
pvr_dir = None
|
pvr_dir = None
|
||||||
restart_iptv = False
|
restart_iptv = False
|
||||||
@@ -55,6 +57,13 @@ if __name__ == '__main__':
|
|||||||
age_limit, max_age = max_age, 6 * 3600 - 120
|
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
|
# 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 ''
|
reload_guide = '&reload_guide=1' if age_limit == 0 else ''
|
||||||
|
# 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'
|
||||||
if addon.getSettingBool('auto_export_epg'): # channels + programme guide
|
if addon.getSettingBool('auto_export_epg'): # channels + programme guide
|
||||||
if file_age(os.path.join(profile_dir, 'epg.xml')) > age_limit:
|
if file_age(os.path.join(profile_dir, 'epg.xml')) > age_limit:
|
||||||
exporting = True
|
exporting = True
|
||||||
|
|||||||
Reference in new issue
Block a user