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
@@ -320,7 +320,9 @@ def _web_device_id(m, account_number):
|
||||
m.cache.save_file('web_device_id.conf', own)
|
||||
return own
|
||||
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('"')
|
||||
if status not in (200, 201) or len(device_id) != 32:
|
||||
raise ValueError('device registration refused ({})'.format(status))
|
||||
@@ -385,6 +387,16 @@ def new_api_ready(m):
|
||||
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):
|
||||
"""Seconds until the token expires (negative: expired or unreadable)."""
|
||||
props = m.get_token_properties(token) if token else None
|
||||
@@ -523,16 +535,51 @@ def restart_iptv_simple():
|
||||
window.clearProperty(IPTV_RESTART_PROPERTY)
|
||||
|
||||
|
||||
def has_iptv_instance(pvr_dir, addon_id):
|
||||
"""True if an IPTV Simple instance reads this add-on's channel list."""
|
||||
SETUP_INSTANCE_FILE = 'instance-settings-91.xml' # written by "Create IPTV settings"
|
||||
|
||||
|
||||
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
|
||||
res = []
|
||||
for filename in glob.glob(os.path.join(pvr_dir, 'instance-settings-*.xml')):
|
||||
try:
|
||||
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):
|
||||
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):
|
||||
|
||||
@@ -781,6 +781,11 @@ def create_iptv_settings():
|
||||
pvr_dir = translatePath(pvr_addon.getAddonInfo('profile'))
|
||||
LOG('pvr_dir: {}'.format(pvr_dir))
|
||||
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):
|
||||
res = xbmcgui.Dialog().yesno(addon.getLocalizedString(30322), addon.getLocalizedString(30323))
|
||||
if res == False: return
|
||||
|
||||
Reference in new issue
Block a user