Skip to content

Instantly share code, notes, and snippets.

@chew-z
Last active January 10, 2023 16:47
Show Gist options
  • Save chew-z/b450199cf629943e134fcc4f25e8d4e0 to your computer and use it in GitHub Desktop.
Save chew-z/b450199cf629943e134fcc4f25e8d4e0 to your computer and use it in GitHub Desktop.
Simplistic script for playing radio in terminal with mpv underneath
[
{
"id": 0,
"station": {
"name": "Machine Geist",
"url": "http://178.209.52.163:7331/maschinengeist.org.128.aacp"
}
},
{
"id": 1,
"station": {
"name": "Freeform Radio the Way it Oughta Be",
"url": "http://stream0.wfmu.org/freeform-128k"
}
},
{
"id": 2,
"station": {
"name": "Jazz Radio New Orleans",
"url": "http://jazz-wr03.ice.infomaniak.ch/jazz-wr03-128.mp3"
}
},
{
"id": 3,
"station": {
"name": "Wereldmuziek",
"url": "http://streams.greenhost.nl:8080/wereldmuziek.m3u"
}
},
{
"id": 4,
"station": {
"name": "worldwidefm.net",
"url": "http://worldwidefm.out.airtime.pro:8000/worldwidefm_a"
}
},
{
"id": 5,
"station": {
"name": "Wassoulou",
"url": "http://listen.radionomy.com/radio-wassoulou-internationale.m3u"
}
},
{
"id": 6,
"station": {
"name": "Asian Star 101.6FM",
"url": "http://icecast.commedia.org.uk:8000/asianstar.mp3.m3u"
}
},
{
"id": 7,
"station": {
"name": "ZemaRadio (Ethiopian)",
"url": "http://listen.radionomy.com/zema-radio.m3u"
}
},
{
"id": 8,
"station": {
"name": "Bongo African Grooves",
"url": "http://www.bongoradio.com/african-grooves/listen128k.pls"
}
},
{
"id": 9,
"station": {
"name": "Bongo East African",
"url": "http://www.bongoradio.com/east-african/listen128k.pls"
}
},
{
"id": 10,
"station": {
"name": "Chilled Out",
"url": "http://relay.181.fm:8700"
}
},
{
"id": 11,
"station": {
"name": "Yerevan Nights",
"url": "http://www.yerevannights.com/Radio.pls"
}
},
{
"id": 12,
"station": {
"name": "Salsa LatiN 181fm",
"url": "http://relay.181.fm:8098"
}
},
{
"id": 13,
"station": {
"name": "Trance Jazz 181fm",
"url": "http://icyrelay.181.fm/181-trancejazz_128k.mp3"
}
},
{
"id": 14,
"station": {
"name": "Mantra (radiolla)",
"url": "http://air.radiolla.com/mantra192k"
}
},
{
"id": 15,
"station": {
"name": "Radio Mississipi Blues",
"url": "http://listen.radionomy.com:80/RadioMississipi-Blues"
}
},
{
"id": 16,
"station": {
"name": "BackPorch Bluegrass",
"url": "http://listen.radionomy.com:80/BackPorchBluegrass"
}
},
{
"id": 17,
"station": {
"name": "Antenne Bayern Chillout",
"url": "http://mp3channels.webradio.antenne.de/chillout"
}
},
{
"id": 18,
"station": {
"name": "A Jazz Dream",
"url": "http://streaming.radionomy.com/AJAZZDREAM-Classic-NewJazz24H"
}
},
{
"id": 19,
"station": {
"name": "Bombay Beats India Radio",
"url": "http://205.164.62.15:8017"
}
},
{
"id": 20,
"station": {
"name": "Motown Classics",
"url": "http://streaming.radionomy.com/motown-classics"
}
},
{
"id": 21,
"station": {
"name": "RnB Cream",
"url": "http://streaming.radionomy.com/_rb_cream"
}
}
]
#!/usr/bin/env python
import argparse
import json
import logging
import os
import signal
import subprocess
def playStation(url='http://178.209.52.163:7331/maschinengeist.org.128.aacp'):
params = {
'player': '/usr/local/bin/mpv',
'profile': 'radio',
'url': url
}
command = "%(player)s --profile=\"%(profile)s\" \"%(url)s\"" % params
logging.info(command)
try:
# return commands.getoutput(command)
# return subprocess.getoutput(command)
# The os.setsid() is passed in the argument preexec_fn so
# it's run after the fork() and before exec() to run the shell.
return subprocess.Popen(command, stdout=subprocess.PIPE, shell=True, preexec_fn=os.setsid)
except Exception as e:
logging.exception("Sending notification failed\n{}".format(e))
raise
def displayCandidates(candidates, pageStart, nStations):
print("{:2} stations found. Please select from following:".format(nStations))
fmtStr = "{:2}) {:20}"
for i, s in enumerate(candidates):
print(fmtStr.format(i + pageStart, s["station"]["name"]))
def selectStation(stations):
nStations = len(stations)
page = 0
pageSize = 15
msg = "\nEnter number to select (default=0), 's' to skip."
if nStations > pageSize:
msg += " 'n' to next page, 'p' to previous page.\n>>>_"
else:
msg += "\n>>>_"
while True:
start = page * pageSize
end = start + pageSize
# go to alternate screen
os.system("tput smcup")
print(chr(27) + "[2J")
displayCandidates(stations[start:end], start, nStations)
ans = input(msg)
logging.info("User ans = '{}'".format(ans))
# go back to main screen
os.system("tput rmcup")
if ans.lower() == "s":
print("Skiping station {}, {}".format(
stations["id"], stations["station"]["name"]))
return None
elif ans.lower() == "n":
if page + 1 > int(nStations / pageSize):
pass
else:
page += 1
elif ans.lower() == "p":
if page == 0:
pass
else:
page -= 1
elif ans.isdigit():
return stations[int(ans)]
else:
return stations[0]
def getArgs(argv=None):
parser = argparse.ArgumentParser(description='Play radiostations with mpv',
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
parser.add_argument('-p', '--playlist',
default='radio.json',
help='List of radiostations')
return parser.parse_args(argv)
if __name__ == '__main__':
FORMAT = '%(asctime)s - %(levelname)s - %(message)s'
try:
os.remove('radio.log')
except BaseException:
pass
logging.basicConfig(filename='radio.log', level=logging.DEBUG,
format=FORMAT, datefmt='%a, %d %b %Y %H:%M:%S',)
logging.info('--- radio.py logging started ---.')
args = getArgs()
fpath = "./{}".format(args.playlist)
with open(fpath, 'r') as json_data:
st = json.load(json_data)
selected = selectStation(st)
logging.info(selected)
url = selected["station"]["url"]
print("Playing station {} from {}".format(
selected["station"]["name"], url))
process = playStation(url)
logging.info(process)
# sleep(10)
input("Press Enter to stop playback...")
try:
# Send the signal to all the process groups
os.killpg(os.getpgid(process.pid), signal.SIGTERM)
except Exception as e:
logging.exception(e)
pass
logging.info('--- radio.py logging finished ---.')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment