From Python to shell script
- Allowing to run mpd + icecast2 + fip relay with metadatas on a VM with 128Mo of memory. - Calculating when to update (given the end field in the JSON)
This commit is contained in:
parent
d35735cf65
commit
bcafd50a3d
5 changed files with 52 additions and 213 deletions
24
README.txt
24
README.txt
|
|
@ -1,13 +1,14 @@
|
||||||
Usage :
|
Usage :
|
||||||
-------
|
-------
|
||||||
|
|
||||||
./fip_current.py [-c CONFIG.ini] [-u]
|
Edit the script to change the value of :
|
||||||
|
host -> icecast2 host & port
|
||||||
|
mount -> mountpoint name
|
||||||
|
login -> icecast2 login
|
||||||
|
passwd -> icecast2 password
|
||||||
|
|
||||||
#Show current song metadata
|
Then run :
|
||||||
./fip_current.py
|
./fip_current.sh
|
||||||
|
|
||||||
#Update icecast2 metadata
|
|
||||||
./fip_current.py -c CONFIG.ini -u
|
|
||||||
|
|
||||||
Instances :
|
Instances :
|
||||||
-----------
|
-----------
|
||||||
|
|
@ -19,8 +20,9 @@ Requierments :
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
icecast2
|
icecast2
|
||||||
python3
|
jq
|
||||||
python3-requests
|
curl
|
||||||
|
sed
|
||||||
|
|
||||||
Icecast2 configuration sample :
|
Icecast2 configuration sample :
|
||||||
-------------------------------
|
-------------------------------
|
||||||
|
|
@ -32,9 +34,3 @@ Icecast2 configuration sample :
|
||||||
<local-mount>/fip-metadata.mp3</local-mount>
|
<local-mount>/fip-metadata.mp3</local-mount>
|
||||||
<relay-shoutcast-metadata>0</relay-shoutcast-metadata>
|
<relay-shoutcast-metadata>0</relay-shoutcast-metadata>
|
||||||
</relay>
|
</relay>
|
||||||
|
|
||||||
Crontab :
|
|
||||||
---------
|
|
||||||
|
|
||||||
#Update every minute
|
|
||||||
* * * * * /path/fip_current.py -uc /path/conf.ini
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
[conf]
|
|
||||||
debug=false
|
|
||||||
loop-delay=15
|
|
||||||
host=127.0.0.1:8000
|
|
||||||
mount=/fip.mp3
|
|
||||||
login=admin
|
|
||||||
password=hackme
|
|
||||||
185
fip_current.py
185
fip_current.py
|
|
@ -1,185 +0,0 @@
|
||||||
#!/usr/bin/python3
|
|
||||||
#
|
|
||||||
# Copyright 2016 Yann Weber
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU General Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License
|
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
import sys
|
|
||||||
import time
|
|
||||||
import requests
|
|
||||||
import configparser
|
|
||||||
from argparse import ArgumentParser
|
|
||||||
|
|
||||||
API_URL = 'http://www.fipradio.fr/livemeta/7'
|
|
||||||
DEBUG = False
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
""" Parse arguments and run wanted function """
|
|
||||||
parser = ArgumentParser(description="Fetch FIP radio stream metadata")
|
|
||||||
parser.add_argument(
|
|
||||||
'-u', '--icecast-update',
|
|
||||||
dest='update',
|
|
||||||
action='store_const',
|
|
||||||
const=True,
|
|
||||||
default=False,
|
|
||||||
help="Run Icecast2 metadata update")
|
|
||||||
parser.add_argument(
|
|
||||||
'-c', '--config',
|
|
||||||
dest='conf',
|
|
||||||
type=str,
|
|
||||||
default='conf.ini',
|
|
||||||
help="Configuration file")
|
|
||||||
parser.add_argument(
|
|
||||||
'-l', '--loop',
|
|
||||||
dest='loop',
|
|
||||||
action='store_const',
|
|
||||||
const=True,
|
|
||||||
default=False,
|
|
||||||
help="Combined with -u enables loop update")
|
|
||||||
"""
|
|
||||||
parser.add_argument(
|
|
||||||
'-d', '--loop-delay',
|
|
||||||
dest='delay',
|
|
||||||
type=int,
|
|
||||||
default=15,
|
|
||||||
help="Loop delay in seconds")
|
|
||||||
"""
|
|
||||||
args = parser.parse_args()
|
|
||||||
conf = configparser.ConfigParser()
|
|
||||||
conf.read(args.conf)
|
|
||||||
debug = conf.get('conf', 'debug', fallback="False").lower() == 'true'
|
|
||||||
globals()['DEBUG'] = debug
|
|
||||||
if args.update:
|
|
||||||
host = conf.get('conf', 'host', fallback='127.0.0.1:8000')
|
|
||||||
mount = conf.get('conf', 'mount', fallback='/example.ogg')
|
|
||||||
login = conf.get('conf', 'login', fallback='admin')
|
|
||||||
password = conf.get('conf', 'password', fallback='hackme')
|
|
||||||
if args.loop:
|
|
||||||
delay = conf.get('conf', 'loop-delay', fallback='15')
|
|
||||||
try:
|
|
||||||
delay = int(delay)
|
|
||||||
except ValueError:
|
|
||||||
msg = "loop-delay expected to be an integer '%s' found"
|
|
||||||
raise ValueError( msg % delay)
|
|
||||||
prev = None
|
|
||||||
while True:
|
|
||||||
try:
|
|
||||||
if globals()['DEBUG']:
|
|
||||||
print("Update start");
|
|
||||||
prev = icecast_update(host, mount, login, password, prev)
|
|
||||||
if globals()['DEBUG']:
|
|
||||||
print("Updated");
|
|
||||||
time.sleep(delay)
|
|
||||||
except Exception as e:
|
|
||||||
prev = None
|
|
||||||
print(str(e), file=sys.stderr)
|
|
||||||
|
|
||||||
else:
|
|
||||||
icecast_update(host, mount, login, password)
|
|
||||||
else:
|
|
||||||
print(format_current())
|
|
||||||
|
|
||||||
|
|
||||||
def get_all():
|
|
||||||
""" Return a dict containing all FIP API metadatas """
|
|
||||||
res = requests.get(API_URL)
|
|
||||||
if res.status_code != 200:
|
|
||||||
msg = "Got status code %d for %s"
|
|
||||||
msg %= (res.status_code, API_URL)
|
|
||||||
raise RuntimeError(msg)
|
|
||||||
return res.json()
|
|
||||||
|
|
||||||
|
|
||||||
def get_current():
|
|
||||||
""" Return a dict containing currently playing song metadatas """
|
|
||||||
datas = get_all()
|
|
||||||
if len(datas['levels'])==2:
|
|
||||||
level = 1
|
|
||||||
else:
|
|
||||||
level = 0
|
|
||||||
position = datas['levels'][level]['position']
|
|
||||||
item_id = datas['levels'][level]['items'][position]
|
|
||||||
item = datas['steps'][item_id]
|
|
||||||
expt = ['authors', 'title', 'titreAlbum', 'visual', 'lienYoutube']
|
|
||||||
for k in expt:
|
|
||||||
if k not in item:
|
|
||||||
item[k] = ''
|
|
||||||
|
|
||||||
return item
|
|
||||||
|
|
||||||
|
|
||||||
def format_current():
|
|
||||||
""" Return a string representing formated current playing song
|
|
||||||
metadatas """
|
|
||||||
item = get_current()
|
|
||||||
infos = """Title :\t\t{title}
|
|
||||||
Authors :\t{author}
|
|
||||||
Album :\t\t{album}
|
|
||||||
Visual :\t{image}
|
|
||||||
Youtube :\t{youtube}
|
|
||||||
"""
|
|
||||||
res = infos.format(
|
|
||||||
title=item['title'].title(),
|
|
||||||
author=item['authors'].title(),
|
|
||||||
album=item['titreAlbum'].title(),
|
|
||||||
image=item['visual'],
|
|
||||||
youtube=item['lienYoutube'])
|
|
||||||
if globals()['DEBUG']:
|
|
||||||
res = "[debug mode]\n"+res
|
|
||||||
return res
|
|
||||||
|
|
||||||
|
|
||||||
def icecast_infos():
|
|
||||||
""" Return formated Icecast2 metadatas from FIP current song
|
|
||||||
metadatas """
|
|
||||||
item = get_current()
|
|
||||||
infos = item['title'].title()
|
|
||||||
if len(item['authors']) > 0:
|
|
||||||
infos += ' - '+item['authors'].title()
|
|
||||||
if len(item['titreAlbum']):
|
|
||||||
infos += ' ('+item['titreAlbum'].title()+')'
|
|
||||||
if globals()['DEBUG']:
|
|
||||||
infos = infos + str(time.time())
|
|
||||||
return infos
|
|
||||||
|
|
||||||
|
|
||||||
def icecast_update(host, mount, login=None, password=None, prev = None):
|
|
||||||
""" Update metadatas to an Icecast2 mount """
|
|
||||||
infos = icecast_infos()
|
|
||||||
url = "http://{host}/admin/metadata"
|
|
||||||
url = url.format(host=host)
|
|
||||||
params = {
|
|
||||||
'mount': mount,
|
|
||||||
'mode': 'updinfo',
|
|
||||||
'song': infos}
|
|
||||||
auth = None
|
|
||||||
if login is not None and password is not None:
|
|
||||||
auth = (login, password)
|
|
||||||
|
|
||||||
if infos != prev:
|
|
||||||
try:
|
|
||||||
res = requests.get(url, auth=auth, params=params)
|
|
||||||
except requests.exceptions.ConnectionError:
|
|
||||||
raise RuntimeError("Connection refuse for "+res.url)
|
|
||||||
|
|
||||||
if res.status_code != 200:
|
|
||||||
msg = "Got status code %d for %s"
|
|
||||||
msg %= (res.status_code, res.url)
|
|
||||||
raise RuntimeError(msg)
|
|
||||||
|
|
||||||
return infos
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
main()
|
|
||||||
38
fip_current.sh
Executable file
38
fip_current.sh
Executable file
|
|
@ -0,0 +1,38 @@
|
||||||
|
#!/bin/sh
|
||||||
|
host="ICECAST2_HOST:PORT"
|
||||||
|
mount="/MOUNTPOINT"
|
||||||
|
login="admin"
|
||||||
|
passwd="hackme"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
fip_url="https://www.fip.fr/livemeta/7"
|
||||||
|
fipmeta="/tmp/fip-meta"
|
||||||
|
start=$(date "+%s")
|
||||||
|
touch $fipmeta
|
||||||
|
while [ 1 ]
|
||||||
|
do
|
||||||
|
q='.["steps"][.["levels"][0]["items"][.["levels"][0]["position"]]] |.["end"], .["title"]+" - "+.["authors"]+" ("+.["titreAlbum"]+")"'
|
||||||
|
infos=$(curl -s $fip_url | jq -r "$q" )
|
||||||
|
title=$(echo $infos |cut -d" " -f"2-"| sed 's/[^ ]\+/\L\u&/g')
|
||||||
|
end=$(echo $infos |cut -d" " -f1)
|
||||||
|
|
||||||
|
if [ "$(cat $fipmeta)" != "$title" ]
|
||||||
|
then
|
||||||
|
echo -n $title > $fipmeta
|
||||||
|
echo $title
|
||||||
|
curl -s -G "http://${login}:${passwd}@${host}/admin/metadata" \
|
||||||
|
-d "mount=${mount}"
|
||||||
|
-d "mode=updinfo"
|
||||||
|
--data-urlencode "song=${title}" > /dev/null
|
||||||
|
fi
|
||||||
|
|
||||||
|
now=$(date "+%s")
|
||||||
|
if [ "$now" -gt "$end" ]
|
||||||
|
then
|
||||||
|
sleep 1
|
||||||
|
else
|
||||||
|
delay=$(expr $end - $now)
|
||||||
|
sleep $delay
|
||||||
|
fi
|
||||||
|
done
|
||||||
11
init_script
11
init_script
|
|
@ -9,14 +9,11 @@
|
||||||
# Description: Start updating Icecast2 metadatas using FIP radio wep API
|
# Description: Start updating Icecast2 metadatas using FIP radio wep API
|
||||||
### END INIT INFO
|
### END INIT INFO
|
||||||
|
|
||||||
DPATH=/PUT/SCRIPT/PATH/HERE
|
DPATH="PATH TO SCRIPT"
|
||||||
|
|
||||||
SCRIPT="fip_current.py"
|
DAEMON="${DPATH}/fip_current.sh"
|
||||||
DAEMON="${DPATH}/${SCRIPT}"
|
|
||||||
CONFIG="${DPATH}/conf.ini"
|
|
||||||
NAME="fip-current"
|
NAME="fip-current"
|
||||||
DESC="fip-current update script"
|
DESC="fip-current update script"
|
||||||
DAEMON_OPTS="-ul -c $CONFIG"
|
|
||||||
PIDFILE="/run/fip-current.pid"
|
PIDFILE="/run/fip-current.pid"
|
||||||
|
|
||||||
set_path()
|
set_path()
|
||||||
|
|
@ -38,14 +35,14 @@ case $1 in
|
||||||
echo -n " allready running"
|
echo -n " allready running"
|
||||||
log_end_msg 1
|
log_end_msg 1
|
||||||
else
|
else
|
||||||
start-stop-daemon --quiet --start --background -m -p $PIDFILE --exec $DAEMON -- $DAEMON_OPTS
|
start-stop-daemon --quiet --start --background -m -p $PIDFILE --exec $DAEMON
|
||||||
log_end_msg $?
|
log_end_msg $?
|
||||||
fi
|
fi
|
||||||
|
|
||||||
;;
|
;;
|
||||||
stop)
|
stop)
|
||||||
log_daemon_msg "Stopping $DESC"
|
log_daemon_msg "Stopping $DESC"
|
||||||
start-stop-daemon --stop -p $PIDFILE --remove-pidfile -x $DAEMON
|
start-stop-daemon --stop -p $PIDFILE --remove-pidfile
|
||||||
log_end_msg $?
|
log_end_msg $?
|
||||||
;;
|
;;
|
||||||
restart)
|
restart)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue