|
@@ -1,185 +0,0 @@
|
1
|
|
-#!/usr/bin/python3
|
2
|
|
-#
|
3
|
|
-# Copyright 2016 Yann Weber
|
4
|
|
-#
|
5
|
|
-# This program is free software: you can redistribute it and/or modify
|
6
|
|
-# it under the terms of the GNU General Public License as published by
|
7
|
|
-# the Free Software Foundation, either version 3 of the License, or
|
8
|
|
-# any later version.
|
9
|
|
-#
|
10
|
|
-# This program is distributed in the hope that it will be useful,
|
11
|
|
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
|
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
|
|
-# GNU General Public License for more details.
|
14
|
|
-#
|
15
|
|
-# You should have received a copy of the GNU General Public License
|
16
|
|
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
17
|
|
-
|
18
|
|
-import sys
|
19
|
|
-import time
|
20
|
|
-import requests
|
21
|
|
-import configparser
|
22
|
|
-from argparse import ArgumentParser
|
23
|
|
-
|
24
|
|
-API_URL = 'http://www.fipradio.fr/livemeta/7'
|
25
|
|
-DEBUG = False
|
26
|
|
-
|
27
|
|
-
|
28
|
|
-def main():
|
29
|
|
- """ Parse arguments and run wanted function """
|
30
|
|
- parser = ArgumentParser(description="Fetch FIP radio stream metadata")
|
31
|
|
- parser.add_argument(
|
32
|
|
- '-u', '--icecast-update',
|
33
|
|
- dest='update',
|
34
|
|
- action='store_const',
|
35
|
|
- const=True,
|
36
|
|
- default=False,
|
37
|
|
- help="Run Icecast2 metadata update")
|
38
|
|
- parser.add_argument(
|
39
|
|
- '-c', '--config',
|
40
|
|
- dest='conf',
|
41
|
|
- type=str,
|
42
|
|
- default='conf.ini',
|
43
|
|
- help="Configuration file")
|
44
|
|
- parser.add_argument(
|
45
|
|
- '-l', '--loop',
|
46
|
|
- dest='loop',
|
47
|
|
- action='store_const',
|
48
|
|
- const=True,
|
49
|
|
- default=False,
|
50
|
|
- help="Combined with -u enables loop update")
|
51
|
|
- """
|
52
|
|
- parser.add_argument(
|
53
|
|
- '-d', '--loop-delay',
|
54
|
|
- dest='delay',
|
55
|
|
- type=int,
|
56
|
|
- default=15,
|
57
|
|
- help="Loop delay in seconds")
|
58
|
|
- """
|
59
|
|
- args = parser.parse_args()
|
60
|
|
- conf = configparser.ConfigParser()
|
61
|
|
- conf.read(args.conf)
|
62
|
|
- debug = conf.get('conf', 'debug', fallback="False").lower() == 'true'
|
63
|
|
- globals()['DEBUG'] = debug
|
64
|
|
- if args.update:
|
65
|
|
- host = conf.get('conf', 'host', fallback='127.0.0.1:8000')
|
66
|
|
- mount = conf.get('conf', 'mount', fallback='/example.ogg')
|
67
|
|
- login = conf.get('conf', 'login', fallback='admin')
|
68
|
|
- password = conf.get('conf', 'password', fallback='hackme')
|
69
|
|
- if args.loop:
|
70
|
|
- delay = conf.get('conf', 'loop-delay', fallback='15')
|
71
|
|
- try:
|
72
|
|
- delay = int(delay)
|
73
|
|
- except ValueError:
|
74
|
|
- msg = "loop-delay expected to be an integer '%s' found"
|
75
|
|
- raise ValueError( msg % delay)
|
76
|
|
- prev = None
|
77
|
|
- while True:
|
78
|
|
- try:
|
79
|
|
- if globals()['DEBUG']:
|
80
|
|
- print("Update start");
|
81
|
|
- prev = icecast_update(host, mount, login, password, prev)
|
82
|
|
- if globals()['DEBUG']:
|
83
|
|
- print("Updated");
|
84
|
|
- time.sleep(delay)
|
85
|
|
- except Exception as e:
|
86
|
|
- prev = None
|
87
|
|
- print(str(e), file=sys.stderr)
|
88
|
|
-
|
89
|
|
- else:
|
90
|
|
- icecast_update(host, mount, login, password)
|
91
|
|
- else:
|
92
|
|
- print(format_current())
|
93
|
|
-
|
94
|
|
-
|
95
|
|
-def get_all():
|
96
|
|
- """ Return a dict containing all FIP API metadatas """
|
97
|
|
- res = requests.get(API_URL)
|
98
|
|
- if res.status_code != 200:
|
99
|
|
- msg = "Got status code %d for %s"
|
100
|
|
- msg %= (res.status_code, API_URL)
|
101
|
|
- raise RuntimeError(msg)
|
102
|
|
- return res.json()
|
103
|
|
-
|
104
|
|
-
|
105
|
|
-def get_current():
|
106
|
|
- """ Return a dict containing currently playing song metadatas """
|
107
|
|
- datas = get_all()
|
108
|
|
- if len(datas['levels'])==2:
|
109
|
|
- level = 1
|
110
|
|
- else:
|
111
|
|
- level = 0
|
112
|
|
- position = datas['levels'][level]['position']
|
113
|
|
- item_id = datas['levels'][level]['items'][position]
|
114
|
|
- item = datas['steps'][item_id]
|
115
|
|
- expt = ['authors', 'title', 'titreAlbum', 'visual', 'lienYoutube']
|
116
|
|
- for k in expt:
|
117
|
|
- if k not in item:
|
118
|
|
- item[k] = ''
|
119
|
|
-
|
120
|
|
- return item
|
121
|
|
-
|
122
|
|
-
|
123
|
|
-def format_current():
|
124
|
|
- """ Return a string representing formated current playing song
|
125
|
|
- metadatas """
|
126
|
|
- item = get_current()
|
127
|
|
- infos = """Title :\t\t{title}
|
128
|
|
-Authors :\t{author}
|
129
|
|
-Album :\t\t{album}
|
130
|
|
-Visual :\t{image}
|
131
|
|
-Youtube :\t{youtube}
|
132
|
|
-"""
|
133
|
|
- res = infos.format(
|
134
|
|
- title=item['title'].title(),
|
135
|
|
- author=item['authors'].title(),
|
136
|
|
- album=item['titreAlbum'].title(),
|
137
|
|
- image=item['visual'],
|
138
|
|
- youtube=item['lienYoutube'])
|
139
|
|
- if globals()['DEBUG']:
|
140
|
|
- res = "[debug mode]\n"+res
|
141
|
|
- return res
|
142
|
|
-
|
143
|
|
-
|
144
|
|
-def icecast_infos():
|
145
|
|
- """ Return formated Icecast2 metadatas from FIP current song
|
146
|
|
- metadatas """
|
147
|
|
- item = get_current()
|
148
|
|
- infos = item['title'].title()
|
149
|
|
- if len(item['authors']) > 0:
|
150
|
|
- infos += ' - '+item['authors'].title()
|
151
|
|
- if len(item['titreAlbum']):
|
152
|
|
- infos += ' ('+item['titreAlbum'].title()+')'
|
153
|
|
- if globals()['DEBUG']:
|
154
|
|
- infos = infos + str(time.time())
|
155
|
|
- return infos
|
156
|
|
-
|
157
|
|
-
|
158
|
|
-def icecast_update(host, mount, login=None, password=None, prev = None):
|
159
|
|
- """ Update metadatas to an Icecast2 mount """
|
160
|
|
- infos = icecast_infos()
|
161
|
|
- url = "http://{host}/admin/metadata"
|
162
|
|
- url = url.format(host=host)
|
163
|
|
- params = {
|
164
|
|
- 'mount': mount,
|
165
|
|
- 'mode': 'updinfo',
|
166
|
|
- 'song': infos}
|
167
|
|
- auth = None
|
168
|
|
- if login is not None and password is not None:
|
169
|
|
- auth = (login, password)
|
170
|
|
-
|
171
|
|
- if infos != prev:
|
172
|
|
- try:
|
173
|
|
- res = requests.get(url, auth=auth, params=params)
|
174
|
|
- except requests.exceptions.ConnectionError:
|
175
|
|
- raise RuntimeError("Connection refuse for "+res.url)
|
176
|
|
-
|
177
|
|
- if res.status_code != 200:
|
178
|
|
- msg = "Got status code %d for %s"
|
179
|
|
- msg %= (res.status_code, res.url)
|
180
|
|
- raise RuntimeError(msg)
|
181
|
|
-
|
182
|
|
- return infos
|
183
|
|
-
|
184
|
|
-if __name__ == '__main__':
|
185
|
|
- main()
|