From: Guillaume Pellerin Date: Mon, 31 Mar 2014 10:22:41 +0000 (+0200) Subject: cleanup, better exception handling, add partial WebM support, add a curl based stream... X-Git-Url: https://git.parisson.com/?a=commitdiff_plain;h=a69b9ddb6dae7bfed03dd3459f3c708b6e687795;p=deefuzzer.git cleanup, better exception handling, add partial WebM support, add a curl based streaming object --- diff --git a/deefuzzer/core.py b/deefuzzer/core.py index 92251cf..6099c07 100644 --- a/deefuzzer/core.py +++ b/deefuzzer/core.py @@ -48,6 +48,9 @@ from deefuzzer.tools import * class DeeFuzzer(Thread): """a DeeFuzzer diffuser""" + m3u = None + rss = None + def __init__(self, conf_file): Thread.__init__(self) self.conf_file = conf_file @@ -112,7 +115,9 @@ class DeeFuzzer(Thread): station = self.conf['deefuzzer']['station'][i] self.stations.append(Station(station, q, self.logger, self.m3u)) - self.set_m3u_playlist() + if self.m3u: + self.set_m3u_playlist() + p = Producer(q) p.start() diff --git a/deefuzzer/station.py b/deefuzzer/station.py index 32ce0cc..bf86675 100644 --- a/deefuzzer/station.py +++ b/deefuzzer/station.py @@ -53,6 +53,7 @@ from relay import * from streamer import * from tools import * + class Station(Thread): """a DeeFuzzer shouting station thread""" @@ -60,6 +61,16 @@ class Station(Thread): counter = 0 delay = 0 start_time = time.time() + server_ping = False + playlist = [] + lp = 1 + player_mode = 0 + osc_control_mode = 0 + twitter_mode = 0 + jingles_mode = 0 + relay_mode = 0 + record_mode = 0 + run_mode = 1 def __init__(self, station, q, logger, m3u): Thread.__init__(self) @@ -67,7 +78,6 @@ class Station(Thread): self.q = q self.logger = logger self.m3u = m3u - self.server_ping = False # Media self.media_dir = self.station['media']['dir'] @@ -126,8 +136,10 @@ class Station(Thread): self.channel_url = self.server_url + self.channel.mount # RSS - self.rss_dir = self.station['rss']['dir'] - self.rss_enclosure = self.station['rss']['enclosure'] + if 'rss' in self.station: + self.rss_mode = int(self.station['rss']['mode']) + self.rss_dir = self.station['rss']['dir'] + self.rss_enclosure = self.station['rss']['enclosure'] if 'media_url' in self.station['rss']: self.rss_media_url = self.station['rss']['media_url'] @@ -140,10 +152,6 @@ class Station(Thread): self.rss_current_file = self.base_name + '_current.xml' self.rss_playlist_file = self.base_name + '_playlist.xml' - # Playlist - self.playlist = self.get_playlist() - self.lp = len(self.playlist) - # Logging self.logger.write_info('Opening ' + self.short_name + ' - ' + self.channel.name + \ ' (' + str(self.lp) + ' tracks)...') @@ -156,10 +164,8 @@ class Station(Thread): # The station's player self.player = Player(self.type) - self.player_mode = 0 - # OSCing - self.osc_control_mode = 0 + # OSCing # mode = 0 means Off, mode = 1 means On if 'control' in self.station: self.osc_control_mode = int(self.station['control']['mode']) @@ -177,8 +183,6 @@ class Station(Thread): self.osc_controller.start() # Jingling between each media. - # mode = 0 means Off, mode = 1 means On - self.jingles_mode = 0 if 'jingles' in self.station: self.jingles_mode = int(self.station['jingles']['mode']) self.jingles_shuffle = self.station['jingles']['shuffle'] @@ -187,8 +191,6 @@ class Station(Thread): self.jingles_callback('/jingles', [1]) # Relaying - # mode = 0 means Off, mode = 1 means On - self.relay_mode = 0 if 'relay' in self.station: self.relay_mode = int(self.station['relay']['mode']) self.relay_url = self.station['relay']['url'] @@ -197,8 +199,6 @@ class Station(Thread): self.relay_callback('/media/relay', [1]) # Twitting - # mode = 0 means Off, mode = 1 means On - self.twitter_mode = 0 if 'twitter' in self.station: self.twitter_mode = int(self.station['twitter']['mode']) self.twitter_key = self.station['twitter']['key'] @@ -215,18 +215,12 @@ class Station(Thread): self.twitter_callback('/twitter', [1]) # Recording - # mode = 0 means Off, mode = 1 means On - self.record_mode = 0 if 'record' in self.station: self.record_mode = int(self.station['record']['mode']) self.record_dir = self.station['record']['dir'] if self.record_mode: self.record_callback('/record', [1]) - # Running - # mode = 0 means Off, mode = 1 means On - self.run_mode = 1 - def run_callback(self, path, value): value = value[0] self.run_mode = value @@ -371,8 +365,12 @@ class Station(Thread): if len(new_tracks): new_tracks_objs = self.media_to_objs(self.new_tracks) for media_obj in new_tracks_objs: - title = media_obj.metadata['title'] - artist = media_obj.metadata['artist'] + title = '' + artist = '' + if media_obj.metadata.has_key('title'): + title = media_obj.metadata['title'] + if media_obj.metadata.has_key('artist'): + artist = media_obj.metadata['artist'] if not (title or artist): song = str(media_obj.file_name) else: @@ -398,7 +396,8 @@ class Station(Thread): self.logger.write_info('Station ' + self.channel_url + \ ' : generating new playlist (' + str(self.lp) + ' tracks)') - self.update_rss(self.media_to_objs(self.playlist), + if self.rss_mode: + self.update_rss(self.media_to_objs(self.playlist), self.rss_playlist_file, '(playlist)') if self.jingles_mode and not (self.counter % 2) and self.jingles_length: @@ -417,16 +416,21 @@ class Station(Thread): media_objs = [] for media in media_list: file_name, file_title, file_ext = get_file_info(media) - if file_ext.lower() == 'mp3' and mimetypes.guess_type(media)[0] == 'audio/mpeg': + if file_ext.lower() == 'mp3' or mimetypes.guess_type(media)[0] == 'audio/mpeg': try: media_objs.append(Mp3(media)) except: continue - elif file_ext.lower() == 'ogg' and mimetypes.guess_type(media)[0] == 'audio/ogg': + elif file_ext.lower() == 'ogg' or mimetypes.guess_type(media)[0] == 'audio/ogg': try: media_objs.append(Ogg(media)) except: continue + elif file_ext.lower() == 'webm' or mimetypes.guess_type(media)[0] == 'video/webm': + try: + media_objs.append(WebM(media)) + except: + continue return media_objs def update_rss(self, media_list, rss_file, sub_title): @@ -524,8 +528,13 @@ class Station(Thread): def set_read_mode(self): self.prefix = '#nowplaying' self.current_media_obj = self.media_to_objs([self.media]) - self.title = self.current_media_obj[0].metadata['title'] - self.artist = self.current_media_obj[0].metadata['artist'] + try: + self.title = self.current_media_obj[0].metadata['title'] + self.artist = self.current_media_obj[0].metadata['artist'] + except: + self.title = 'title' + self.artist = 'artist' + self.title = self.title.replace('_', ' ') self.artist = self.artist.replace('_', ' ') @@ -537,15 +546,15 @@ class Station(Thread): self.song = song.encode('utf-8') self.artist = self.artist.encode('utf-8') self.metadata_file = self.metadata_dir + os.sep + self.current_media_obj[0].file_name + '.xml' - #self.update_rss(self.current_media_obj, self.metadata_file, '') - self.update_rss(self.current_media_obj, self.rss_current_file, '(currently playing)') + if self.rss_mode: + self.update_rss(self.current_media_obj, self.rss_current_file, '(currently playing)') self.logger.write_info('DeeFuzzing on %s : id = %s, name = %s' \ % (self.short_name, self.id, self.current_media_obj[0].file_name)) self.player.set_media(self.media) - if self.player_mode == 0: + if self.player_mode: self.stream = self.player.file_read_slow() - elif self.player_mode == 1: + else: self.stream = self.player.file_read_fast() def set_webm_read_mode(self): @@ -584,7 +593,6 @@ class Station(Thread): self.q.task_done() pass - def run(self): self.q.get(1) self.ping_server() diff --git a/deefuzzer/tools/__init__.py b/deefuzzer/tools/__init__.py index 03fd06d..6dc964d 100644 --- a/deefuzzer/tools/__init__.py +++ b/deefuzzer/tools/__init__.py @@ -3,6 +3,7 @@ from xmltodict import * from PyRSS2Gen import * from mp3 import * from ogg import * +from webm import * from logger import * from osc import * from twitt import * diff --git a/deefuzzer/tools/ogg.py b/deefuzzer/tools/ogg.py index 6467715..9b3a85f 100644 --- a/deefuzzer/tools/ogg.py +++ b/deefuzzer/tools/ogg.py @@ -83,10 +83,10 @@ class Ogg: return 'ogg' def get_mime_type(self): - return 'application/ogg' + return 'audio/ogg' def get_description(self): - return 'FIXME' + return 'OGG Vorbis' def get_file_info(self): try: diff --git a/deefuzzer/tools/streamer.py b/deefuzzer/tools/streamer.py new file mode 100644 index 0000000..1d11091 --- /dev/null +++ b/deefuzzer/tools/streamer.py @@ -0,0 +1,81 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (C) 2006-2011 Guillaume Pellerin + +# + +# 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 + +from threading import Thread + +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) + import pycurl + self.curl = pycurl.Curl() + + def set_callback(self, read_callback): + self.read_callback = read_callback + + def delay(self): + return self.delay + + def open(self): + import pycurl + 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() diff --git a/deefuzzer/tools/webm.py b/deefuzzer/tools/webm.py new file mode 100644 index 0000000..389149d --- /dev/null +++ b/deefuzzer/tools/webm.py @@ -0,0 +1,56 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright Guillaume Pellerin (2006-2009) + +# + +# 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 + +import os +import string +import datetime +from utils import * + + +class WebM(object): + """An WebM file object""" + + def __init__(self, media): + self.media = media + self.item_id = '' + self.source = self.media + self.mime_type = 'video/webm' + self.extension = 'webm' + self.description = 'WebM' + self.metadata = {} + self.file_name, self.file_title, self.file_ext = get_file_info(media)