import urllib
import mimetypes
from threading import Thread
-from __init__ import *
+from tools import *
class Station(Thread):
"""a DeeFuzzer shouting station thread"""
+ id = 999999
+ counter = 0
+ command = 'cat '
+ delay = 0
+ start_time = time.time()
+
def __init__(self, station, q, logger, m3u):
Thread.__init__(self)
self.station = station
self.q = q
self.logger = logger
- self.channel = shout.Shout()
- self.id = 999999
- self.counter = 0
- self.command = 'cat '
- self.delay = 0
- self.start_time = time.time()
+ self.m3u = m3u
+ self.server_ping = False
# Media
self.media_dir = self.station['media']['dir']
- self.channel.format = self.station['media']['format']
+ self.media_format = self.station['media']['format']
self.shuffle_mode = int(self.station['media']['shuffle'])
self.bitrate = self.station['media']['bitrate']
self.ogg_quality = self.station['media']['ogg_quality']
self.samplerate = self.station['media']['samplerate']
self.voices = self.station['media']['voices']
- # Infos
- self.channel.url = self.station['infos']['url']
+ # Server
self.short_name = self.station['infos']['short_name']
+ self.mount = '/' + self.short_name
+
+ if 'type' in self.station['server']:
+ self.type = self.station['server']['type'] # 'icecast' | 'stream-m'
+ else:
+ self.type = 'icecast'
+
+ if 'stream-m' in self.type:
+ self.channel = HTTPStreamer()
+ self.channel.mount = self.mount
+ else:
+ self.channel = shout.Shout()
+ self.channel.mount = self.mount + '.' + self.media_format
+
+ self.channel.url = self.station['infos']['url']
self.channel.name = self.station['infos']['name'] + ' : ' + self.channel.url
self.channel.genre = self.station['infos']['genre']
self.channel.description = self.station['infos']['description']
- self.m3u = m3u
+ self.channel.format = self.media_format
+ self.channel.host = self.station['server']['host']
+ self.channel.port = int(self.station['server']['port'])
+ self.channel.user = 'source'
+ self.channel.password = self.station['server']['sourcepassword']
+ self.channel.public = int(self.station['server']['public'])
+ self.channel.genre = self.station['infos']['genre']
+ self.channel.description = self.station['infos']['description']
+ self.channel.audio_info = { 'bitrate': self.bitrate,
+ 'samplerate': self.samplerate,
+ 'quality': self.ogg_quality,
+ 'channels': self.voices,}
+ self.server_url = 'http://' + self.channel.host + ':' + str(self.channel.port)
+ self.channel_url = self.server_url + self.channel.mount
# RSS
self.rss_dir = self.station['rss']['dir']
self.base_name = self.rss_dir + os.sep + self.short_name + '_' + self.channel.format
self.rss_current_file = self.base_name + '_current.xml'
self.rss_playlist_file = self.base_name + '_playlist.xml'
-
- # Server
- self.channel.protocol = 'http' # | 'xaudiocast' | 'icy'
- self.channel.host = self.station['server']['host']
- self.channel.port = int(self.station['server']['port'])
- self.channel.user = 'source'
- self.channel.password = self.station['server']['sourcepassword']
- self.channel.mount = '/' + self.short_name + '.' + self.channel.format
- self.channel.public = int(self.station['server']['public'])
- self.channel.audio_info = { 'bitrate': self.bitrate,
- 'samplerate': self.samplerate,
- 'quality': self.ogg_quality,
- 'channels': self.voices,}
- self.server_url = 'http://' + self.channel.host + ':' + str(self.channel.port)
- self.channel_url = self.server_url + self.channel.mount
- self.server_ping = False
-
+
# Playlist
self.playlist = self.get_playlist()
self.lp = len(self.playlist)
self.twitter_messages = list(self.twitter_messages)
except:
pass
-
+
if self.twitter_mode == 1:
self.twitter_callback('/twitter', [1])
value = value[0]
if value == 1:
self.relay_mode = 1
- self.player.start_relay(self.relay_url)
+ if self.type == 'icecast':
+ self.player.start_relay(self.relay_url)
elif value == 0:
self.relay_mode = 0
- self.player.stop_relay()
+ if self.type == 'icecast':
+ self.player.stop_relay()
self.id = 0
self.next_media = 1
message = "Station " + self.channel_url + " : received OSC message '%s' with arguments '%d'" % (path, value)
playlist_set = set(playlist)
new_tracks = new_playlist_set - playlist_set
self.new_tracks = list(new_tracks.copy())
-
+
if len(new_tracks) != 0:
new_tracks_objs = self.media_to_objs(self.new_tracks)
for media_obj in new_tracks_objs:
message = '#NEWTRACK ! %s #%s on #%s RSS: ' % (song.replace('_', ' '), artist_tags, self.short_name)
message = message[:113] + self.rss_tinyurl
self.update_twitter(message)
-
+
# Shake it, Fuzz it !
if self.shuffle_mode == 1:
random.shuffle(playlist)
-
+
# Play new tracks first
for track in self.new_tracks:
playlist.insert(0, track)
self.playlist = playlist
-
+
self.logger.write_info('Station ' + self.channel_url + \
' : generating new playlist (' + str(self.lp) + ' tracks)')
self.update_rss(self.media_to_objs(self.playlist), self.rss_playlist_file, '(playlist)')
self.title = self.title.replace('_', ' ')
self.artist = self.artist.replace('_', ' ')
self.song = self.artist + ' : ' + self.title
- self.stream = self.player.relay_read()
+ if self.type == 'stream-m':
+ self.channel.set_callback(RelayReader(self.relay_url).read_callback)
+ else:
+ self.stream = self.player.relay_read()
def set_read_mode(self):
self.prefix = '#nowplaying'
def channel_open(self):
self.channel.open()
self.channel_delay = self.channel.delay()
-
+
def ping_server(self):
log = True
while not self.server_ping:
log = False
self.q.task_done()
pass
-
+
def run(self):
- self.ping_server()
self.q.get(1)
- self.channel_open()
- self.logger.write_info('Station ' + self.channel_url + ' : channel connected')
+ self.ping_server()
self.q.task_done()
-
- while self.run_mode:
+
+ if self.type == 'stream-m':
self.q.get(1)
- self.next_media = 0
- self.media = self.get_next_media()
- self.counter += 1
if self.relay_mode:
self.set_relay_mode()
- elif os.path.exists(self.media) and not os.sep+'.' in self.media:
- if self.lp == 0:
- self.logger.write_error('Station ' + self.channel_url + ' : has no media to stream !')
- break
- self.set_read_mode()
+ self.channel_open()
+ self.channel.start()
self.q.task_done()
+ if self.type == 'icecast':
self.q.get(1)
- if (not (self.jingles_mode and (self.counter % 2)) or self.relay_mode) and self.twitter_mode:
- try:
- self.update_twitter_current()
- except:
- continue
- try:
- self.channel.set_metadata({'song': self.song, 'charset': 'utf-8',})
- except:
- continue
+ self.channel_open()
+ self.logger.write_info('Station ' + self.channel_url + ' : channel connected')
self.q.task_done()
- for self.chunk in self.stream:
- if self.next_media or not self.run_mode:
- break
- if self.record_mode:
+ while self.run_mode:
+ self.q.get(1)
+ self.next_media = 0
+ self.media = self.get_next_media()
+ self.counter += 1
+ if self.relay_mode:
+ self.set_relay_mode()
+ elif os.path.exists(self.media) and not os.sep+'.' in self.media:
+ if self.lp == 0:
+ self.logger.write_error('Station ' + self.channel_url + ' : has no media to stream !')
+ break
+ self.set_read_mode()
+ self.q.task_done()
+
+ self.q.get(1)
+ if (not (self.jingles_mode and (self.counter % 2)) or self.relay_mode) and self.twitter_mode:
try:
- self.q.get(1)
- self.recorder.write(self.chunk)
- self.q.task_done()
+ self.update_twitter_current()
except:
- self.logger.write_error('Station ' + self.channel_url + ' : could not write the buffer to the file')
- self.q.task_done()
continue
try:
- self.q.get(1)
- self.channel.send(self.chunk)
- self.channel.sync()
- self.q.task_done()
+ self.channel.set_metadata({'song': self.song, 'charset': 'utf-8',})
except:
- self.logger.write_error('Station ' + self.channel_url + ' : could not send the buffer')
- self.q.task_done()
- try:
- self.q.get(1)
- self.channel.close()
- self.logger.write_info('Station ' + self.channel_url + ' : channel closed')
- self.q.task_done()
- except:
- self.logger.write_error('Station ' + self.channel_url + ' : could not close the channel')
- self.q.task_done()
- continue
+ continue
+ self.q.task_done()
+
+
+ for self.chunk in self.stream:
+ if self.next_media or not self.run_mode:
+ break
+ if self.record_mode:
+ try:
+ self.q.get(1)
+ self.recorder.write(self.chunk)
+ self.q.task_done()
+ except:
+ self.logger.write_error('Station ' + self.channel_url + ' : could not write the buffer to the file')
+ self.q.task_done()
+ continue
try:
- self.ping_server()
self.q.get(1)
- self.channel_open()
- self.channel.set_metadata({'song': self.song, 'charset': 'utf8',})
- self.logger.write_info('Station ' + self.channel_url + ' : channel restarted')
+ self.channel.send(self.chunk)
+ self.channel.sync()
self.q.task_done()
except:
- self.logger.write_error('Station ' + self.channel_url + ' : could not restart the channel')
+ self.logger.write_error('Station ' + self.channel_url + ' : could not send the buffer')
self.q.task_done()
+ try:
+ self.q.get(1)
+ self.channel.close()
+ self.logger.write_info('Station ' + self.channel_url + ' : channel closed')
+ self.q.task_done()
+ except:
+ self.logger.write_error('Station ' + self.channel_url + ' : could not close the channel')
+ self.q.task_done()
+ continue
+ try:
+ self.ping_server()
+ self.q.get(1)
+ self.channel_open()
+ self.channel.set_metadata({'song': self.song, 'charset': 'utf8',})
+ self.logger.write_info('Station ' + self.channel_url + ' : channel restarted')
+ self.q.task_done()
+ except:
+ self.logger.write_error('Station ' + self.channel_url + ' : could not restart the channel')
+ self.q.task_done()
+ continue
continue
- continue
- if self.record_mode:
- self.recorder.close()
+ if self.record_mode:
+ self.recorder.close()
+
+ self.channel.close()
+
+
+
+
+
- self.channel.close()
-
--- /dev/null
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2006-2011 Guillaume Pellerin
+
+# <yomguy@parisson.com>
+
+# This software is a computer program whose purpose is to stream audio
+# and video data through icecast2 servers.
+
+# This software is governed by the CeCILL license under French law and
+# abiding by the rules of distribution of free software. You can use,
+# modify and/ or redistribute the software under the terms of the CeCILL
+# license as circulated by CEA, CNRS and INRIA at the following URL
+# "http://www.cecill.info".
+
+# As a counterpart to the access to the source code and rights to copy,
+# modify and redistribute granted by the license, users are provided only
+# with a limited warranty and the software's author, the holder of the
+# economic rights, and the successive licensors have only limited
+# liability.
+
+# In this respect, the user's attention is drawn to the risks associated
+# with loading, using, modifying and/or developing or reproducing the
+# software by the user in light of its specific status of free software,
+# that may mean that it is complicated to manipulate, and that also
+# therefore means that it is reserved for developers and experienced
+# professionals having in-depth computer knowledge. Users are therefore
+# encouraged to load and test the software's suitability as regards their
+# requirements in conditions enabling the security of their systems and/or
+# data to be ensured and, more generally, to use and operate it in the
+# same conditions as regards security.
+
+# The fact that you are presently reading this means that you have had
+# knowledge of the CeCILL license and that you accept its terms.
+
+# Author: Guillaume Pellerin <yomguy@parisson.com>
+
+from threading import Thread
+import pycurl
+
+class HTTPStreamer(Thread):
+
+ protocol = 'http'
+ host = str
+ port = str
+ mount = str
+ user = str
+ password = str
+ public = str
+ audio_info = dict
+ name = str
+ genre = str
+ decription = str
+ format = str
+ url = str
+ delay = 0
+
+ def __init__(self):
+ Thread.__init__(self)
+ self.curl = pycurl.Curl()
+
+ def set_callback(self, read_callback):
+ self.read_callback = read_callback
+
+ def delay(self):
+ return self.delay
+
+ def open(self):
+ self.uri = self.protocol + '://' + self.host + ':' + str(self.port) + self.mount + '?' + 'password=' + self.password
+
+ self.curl.setopt(pycurl.URL, self.uri)
+ self.curl.setopt(pycurl.UPLOAD, 1)
+ self.curl.setopt(pycurl.READFUNCTION, self.read_callback)
+
+ def run(self):
+ self.curl.perform()
+
+ def close(self):
+ self.curl.close()