Update icecast2 FIP relay using HTTP/Json API http://zmpd.zered.net:8042/fip-metadata.mp3
python
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

fip_current.py 5.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  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. import sys
  18. import time
  19. import requests
  20. import configparser
  21. from argparse import ArgumentParser
  22. API_URL = 'http://www.fipradio.fr/livemeta/7'
  23. DEBUG = False
  24. def main():
  25. """ Parse arguments and run wanted function """
  26. parser = ArgumentParser(description="Fetch FIP radio stream metadata")
  27. parser.add_argument(
  28. '-u', '--icecast-update',
  29. dest='update',
  30. action='store_const',
  31. const=True,
  32. default=False,
  33. help="Run Icecast2 metadata update")
  34. parser.add_argument(
  35. '-c', '--config',
  36. dest='conf',
  37. type=str,
  38. default='conf.ini',
  39. help="Configuration file")
  40. parser.add_argument(
  41. '-l', '--loop',
  42. dest='loop',
  43. action='store_const',
  44. const=True,
  45. default=False,
  46. help="Combined with -u enables loop update")
  47. """
  48. parser.add_argument(
  49. '-d', '--loop-delay',
  50. dest='delay',
  51. type=int,
  52. default=15,
  53. help="Loop delay in seconds")
  54. """
  55. args = parser.parse_args()
  56. conf = configparser.ConfigParser()
  57. conf.read(args.conf)
  58. debug = conf.get('conf', 'debug', fallback="False").lower() == 'true'
  59. globals()['DEBUG'] = debug
  60. if args.update:
  61. host = conf.get('conf', 'host', fallback='127.0.0.1:8000')
  62. mount = conf.get('conf', 'mount', fallback='/example.ogg')
  63. login = conf.get('conf', 'login', fallback='admin')
  64. password = conf.get('conf', 'password', fallback='hackme')
  65. if args.loop:
  66. delay = conf.get('conf', 'loop-delay', fallback='15')
  67. try:
  68. delay = int(delay)
  69. except ValueError:
  70. msg = "loop-delay expected to be an integer '%s' found"
  71. raise ValueError( msg % delay)
  72. prev = None
  73. while True:
  74. try:
  75. if globals()['DEBUG']:
  76. print("Update start");
  77. prev = icecast_update(host, mount, login, password, prev)
  78. if globals()['DEBUG']:
  79. print("Updated");
  80. time.sleep(delay)
  81. except Exception as e:
  82. prev = None
  83. print(str(e), file=sys.stderr)
  84. else:
  85. icecast_update(host, mount, login, password)
  86. else:
  87. print(format_current())
  88. def get_all():
  89. """ Return a dict containing all FIP API metadatas """
  90. res = requests.get(API_URL)
  91. if res.status_code != 200:
  92. msg = "Got status code %d for %s"
  93. msg %= (res.status_code, API_URL)
  94. raise RuntimeError(msg)
  95. return res.json()
  96. def get_current():
  97. """ Return a dict containing currently playing song metadatas """
  98. datas = get_all()
  99. if len(datas['levels'])==2:
  100. level = 1
  101. else:
  102. level = 0
  103. position = datas['levels'][level]['position']
  104. item_id = datas['levels'][level]['items'][position]
  105. item = datas['steps'][item_id]
  106. expt = ['authors', 'title', 'titreAlbum', 'visual', 'lienYoutube']
  107. for k in expt:
  108. if k not in item:
  109. item[k] = ''
  110. return item
  111. def format_current():
  112. """ Return a string representing formated current playing song
  113. metadatas """
  114. item = get_current()
  115. infos = """Title :\t\t{title}
  116. Authors :\t{author}
  117. Album :\t\t{album}
  118. Visual :\t{image}
  119. Youtube :\t{youtube}
  120. """
  121. res = infos.format(
  122. title=item['title'].title(),
  123. author=item['authors'].title(),
  124. album=item['titreAlbum'].title(),
  125. image=item['visual'],
  126. youtube=item['lienYoutube'])
  127. if globals()['DEBUG']:
  128. res = "[debug mode]\n"+res
  129. return res
  130. def icecast_infos():
  131. """ Return formated Icecast2 metadatas from FIP current song
  132. metadatas """
  133. item = get_current()
  134. infos = item['title'].title()
  135. if len(item['authors']) > 0:
  136. infos += ' - '+item['authors'].title()
  137. if len(item['titreAlbum']):
  138. infos += ' ('+item['titreAlbum'].title()+')'
  139. if globals()['DEBUG']:
  140. infos = infos + str(time.time())
  141. return infos
  142. def icecast_update(host, mount, login=None, password=None, prev = None):
  143. """ Update metadatas to an Icecast2 mount """
  144. infos = icecast_infos()
  145. url = "http://{host}/admin/metadata"
  146. url = url.format(host=host)
  147. params = {
  148. 'mount': mount,
  149. 'mode': 'updinfo',
  150. 'song': infos}
  151. auth = None
  152. if login is not None and password is not None:
  153. auth = (login, password)
  154. if infos != prev:
  155. try:
  156. res = requests.get(url, auth=auth, params=params)
  157. except requests.exceptions.ConnectionError:
  158. raise RuntimeError("Connection refuse for "+res.url)
  159. if res.status_code != 200:
  160. msg = "Got status code %d for %s"
  161. msg %= (res.status_code, res.url)
  162. raise RuntimeError(msg)
  163. return infos
  164. if __name__ == '__main__':
  165. main()