Files

96 lines
3.3 KiB
Python

#!/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()