Radios de Vigo: Vigo FM dial and UK/US/Portugal news radio for Kodi

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
XoséandClaude Opus 5.5 committed 2026-11-12 22:19:10 +01:00
commit 927195e28d
60 files changed
+488

No files matched your search

+127
View File
@@ -0,0 +1,127 @@
# -*- coding: utf-8 -*-
"""Keeps an IPTV Simple instance that plays this add-on's radio.m3u.
Runs when Kodi starts and again after every add-on update. Writes the
instance settings, then restarts IPTV Simple (once nothing is playing) if the
settings or the station list changed since the last run.
"""
import glob
import hashlib
import io
import json
import os
import xbmc
import xbmcaddon
import xbmcvfs
ADDON = xbmcaddon.Addon()
ADDON_ID = ADDON.getAddonInfo('id')
HOME = 'special://home/addons/{}/resources/'.format(ADDON_ID)
FIRST_INSTANCE = 95 # KodiMov+ uses 91 (VAIO) and 93 (.49)
SETTINGS = '''<settings version="2">
<setting id="kodi_addon_instance_name">Radios de Vigo</setting>
<setting id="kodi_addon_instance_enabled">true</setting>
<setting id="m3uPathType">0</setting>
<setting id="m3uPath">{home}radio.m3u</setting>
<setting id="m3uUrl" default="true" />
<setting id="m3uCache" default="true">true</setting>
<setting id="startNum" default="true">1</setting>
<setting id="numberByOrder" default="true">false</setting>
<setting id="m3uRefreshMode" default="true">0</setting>
<setting id="epgPathType">0</setting>
<setting id="epgPath" default="true" />
<setting id="epgUrl" default="true" />
<setting id="logoPathType">0</setting>
<setting id="logoPath">{home}logos/</setting>
<setting id="useLogosLocalPathOnly" default="true">false</setting>
<setting id="logoFromEpg">0</setting>
<setting id="useFFmpegReconnect" default="true">true</setting>
<setting id="useInputstreamAdaptiveforHls" default="true">false</setting>
</settings>
'''.format(home=HOME)
def log(msg):
xbmc.log('[{}] {}'.format(ADDON_ID, msg), xbmc.LOGINFO)
def rpc(method, **params):
return json.loads(xbmc.executeJSONRPC(json.dumps(
{'jsonrpc': '2.0', 'id': 1, 'method': method, 'params': params})))
def read(path):
try:
with io.open(path, 'r', encoding='utf-8') as f:
return f.read()
except (IOError, OSError):
return None
def write(path, content):
tmp = path + '.tmp'
with io.open(tmp, 'w', encoding='utf-8', newline='') as f:
f.write(content)
os.replace(tmp, path)
def instance_file(pvr_dir):
"""Our instance file: the one that already reads radio.m3u, else the
first free number from FIRST_INSTANCE on."""
for path in glob.glob(os.path.join(pvr_dir, 'instance-settings-*.xml')):
if HOME + 'radio.m3u' in (read(path) or ''):
return path
n = FIRST_INSTANCE
while os.path.exists(os.path.join(pvr_dir, 'instance-settings-{}.xml'.format(n))):
n += 1
return os.path.join(pvr_dir, 'instance-settings-{}.xml'.format(n))
def restart_iptv_simple():
for enabled in (False, True):
rpc('Addons.SetAddonEnabled', addonid='pvr.iptvsimple', enabled=enabled)
xbmc.sleep(3000)
def main():
monitor, player = xbmc.Monitor(), xbmc.Player()
profile = xbmcvfs.translatePath(ADDON.getAddonInfo('profile'))
pvr_dir = xbmcvfs.translatePath('special://profile/addon_data/pvr.iptvsimple/')
for d in (profile, pvr_dir):
if not os.path.isdir(d):
os.makedirs(d)
path = instance_file(pvr_dir)
if read(path) != SETTINGS:
write(path, SETTINGS)
log('wrote ' + path)
numbers_set = os.path.join(profile, 'numbers-set')
if not os.path.exists(numbers_set):
# Show the stations' own numbers (Vigo ones are their FM frequency).
# With more than one IPTV Simple instance Kodi ignores them unless
# "always" is on too; that also keeps KodiMov+'s TV numbers.
for setting in ('pvrmanager.usebackendchannelnumbers', 'pvrmanager.usebackendchannelnumbersalways'):
rpc('Settings.SetSettingValue', setting=setting, value=True)
write(numbers_set, '')
log('turned on backend channel numbers')
m3u = read(xbmcvfs.translatePath(HOME + 'radio.m3u')) or ''
state = hashlib.sha1((SETTINGS + m3u).encode('utf-8')).hexdigest()
if read(os.path.join(profile, 'state')) == state:
return
while player.isPlaying(): # restarting IPTV Simple stops the radio or TV playing
if monitor.waitForAbort(10):
return
if monitor.waitForAbort(5):
return
log('station list or settings changed, restarting IPTV Simple')
restart_iptv_simple()
write(os.path.join(profile, 'state'), state)
if __name__ == '__main__':
main()