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:
commit
927195e28d
60 files changed
+488
No files matched your search
@@ -0,0 +1,95 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Writes resources/radio.m3u from tools/stations.txt and downloads the logos
|
||||
that are missing from resources/logos (512 px PNG, needs macOS sips).
|
||||
|
||||
Run with: python3 -I tools/build.py [--logos] (--logos downloads every logo again)
|
||||
"""
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
import unicodedata
|
||||
import urllib.parse
|
||||
import urllib.request
|
||||
|
||||
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
LOGOS = os.path.join(ROOT, 'resources', 'logos')
|
||||
UA = {'User-Agent': 'Mozilla/5.0'}
|
||||
|
||||
|
||||
def get(url):
|
||||
return urllib.request.urlopen(urllib.request.Request(url, headers=UA), timeout=20).read()
|
||||
|
||||
|
||||
def channel_id(name):
|
||||
name = unicodedata.normalize('NFKD', name.replace('+', ' mas')).encode('ascii', 'ignore').decode()
|
||||
return re.sub(r'[^a-z0-9]+', '-', name.lower()).strip('-')
|
||||
|
||||
|
||||
def stations():
|
||||
with open(os.path.join(ROOT, 'tools', 'stations.txt'), encoding='utf-8') as f:
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if line and not line.startswith('#'):
|
||||
yield line.split('|', 4)
|
||||
|
||||
|
||||
def logo_url(source):
|
||||
if source.startswith('rb:'):
|
||||
query = urllib.parse.urlencode({'name': source[3:], 'limit': 5, 'order': 'clickcount', 'reverse': 'true'})
|
||||
for s in json.loads(get('https://de1.api.radio-browser.info/json/stations/search?' + query)):
|
||||
if s['favicon']:
|
||||
return s['favicon']
|
||||
return None
|
||||
country, slug = source.split('.', 1)
|
||||
page = get('https://onlineradiobox.com/{}/{}/'.format(country, slug)).decode('utf-8', 'replace')
|
||||
m = re.search(r'og:image" content="https://cdn\.onlineradiobox\.com/img/fblogo/([^"]+)"', page)
|
||||
return 'https://cdn.onlineradiobox.com/img/l/' + m.group(1) if m else None # the logo, not the share banner
|
||||
|
||||
|
||||
def fetch_logo(source, dest):
|
||||
url = logo_url(source)
|
||||
if not url:
|
||||
return False
|
||||
tmp = dest + '.tmp'
|
||||
with open(tmp, 'wb') as f:
|
||||
f.write(get(url))
|
||||
try:
|
||||
subprocess.run(['sips', '-s', 'format', 'png', '-Z', '512', tmp, '--out', dest], check=True, capture_output=True)
|
||||
finally:
|
||||
os.remove(tmp)
|
||||
return True
|
||||
|
||||
|
||||
def main():
|
||||
refresh = '--logos' in sys.argv
|
||||
os.makedirs(LOGOS, exist_ok=True)
|
||||
lines, used = ['#EXTM3U'], set()
|
||||
for chno, name, groups, source, url in stations():
|
||||
cid = channel_id(name)
|
||||
logo = cid + '.png'
|
||||
path = os.path.join(LOGOS, logo)
|
||||
if source != '-' and (refresh or not os.path.exists(path)):
|
||||
try:
|
||||
if not fetch_logo(source, path):
|
||||
print('no logo found:', name)
|
||||
except Exception as e:
|
||||
print('logo failed:', name, e)
|
||||
attrs = 'tvg-id="{}" tvg-chno="{}" radio="true" group-title="{}"'.format(cid, chno, groups)
|
||||
if os.path.exists(path):
|
||||
attrs += ' tvg-logo="{}"'.format(logo)
|
||||
used.add(logo)
|
||||
else:
|
||||
print('no logo:', name)
|
||||
lines += ['#EXTINF:-1 {},{}'.format(attrs, name), url]
|
||||
for f in sorted(set(os.listdir(LOGOS)) - used):
|
||||
print('unused logo removed:', f)
|
||||
os.remove(os.path.join(LOGOS, f))
|
||||
with open(os.path.join(ROOT, 'resources', 'radio.m3u'), 'w', encoding='utf-8') as f:
|
||||
f.write('\n'.join(lines) + '\n')
|
||||
print(len(lines) // 2, 'stations')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Reference in new issue
Block a user