1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39 import os
40 import sys
41 import time
42 import datetime
43 import string
44 import random
45 import shout
46 import urllib
47 from threading import Thread
48 from __init__ import *
49
50
52 """a DeeFuzzer shouting station thread"""
53
54 - def __init__(self, station, q, logger, m3u):
55 Thread.__init__(self)
56 self.station = station
57 self.q = q
58 self.logger = logger
59 self.channel = shout.Shout()
60 self.id = 999999
61 self.counter = 0
62 self.command = 'cat '
63 self.delay = 0
64
65
66 self.media_dir = self.station['media']['dir']
67 self.channel.format = self.station['media']['format']
68 self.shuffle_mode = int(self.station['media']['shuffle'])
69 self.bitrate = self.station['media']['bitrate']
70 self.ogg_quality = self.station['media']['ogg_quality']
71 self.samplerate = self.station['media']['samplerate']
72 self.voices = self.station['media']['voices']
73
74
75 self.rss_dir = self.station['rss']['dir']
76 self.rss_enclosure = self.station['rss']['enclosure']
77
78
79 self.channel.url = self.station['infos']['url']
80 self.short_name = self.station['infos']['short_name']
81 self.channel.name = self.station['infos']['name'] + ' : ' + self.channel.url
82 self.channel.genre = self.station['infos']['genre']
83 self.channel.description = self.station['infos']['description']
84 self.base_name = self.rss_dir + os.sep + self.short_name + '_' + self.channel.format
85 self.rss_current_file = self.base_name + '_current.xml'
86 self.rss_playlist_file = self.base_name + '_playlist.xml'
87 self.m3u = m3u
88
89
90 self.channel.protocol = 'http'
91 self.channel.host = self.station['server']['host']
92 self.channel.port = int(self.station['server']['port'])
93 self.channel.user = 'source'
94 self.channel.password = self.station['server']['sourcepassword']
95 self.channel.mount = '/' + self.short_name + '.' + self.channel.format
96 self.channel.public = int(self.station['server']['public'])
97 self.channel.audio_info = { 'bitrate': self.bitrate,
98 'samplerate': self.samplerate,
99 'quality': self.ogg_quality,
100 'channels': self.voices,}
101 self.server_url = 'http://' + self.channel.host + ':' + str(self.channel.port)
102 self.channel_url = self.server_url + self.channel.mount
103 self.server_ping = False
104
105
106 self.playlist = self.get_playlist()
107 self.lp = len(self.playlist)
108
109
110 self.logger.write_info('Opening ' + self.short_name + ' - ' + self.channel.name + \
111 ' (' + str(self.lp) + ' tracks)...')
112
113 self.metadata_relative_dir = 'metadata'
114 self.metadata_url = self.channel.url + '/rss/' + self.metadata_relative_dir
115 self.metadata_dir = self.rss_dir + os.sep + self.metadata_relative_dir
116 if not os.path.exists(self.metadata_dir):
117 os.makedirs(self.metadata_dir)
118
119
120 self.player = Player()
121 self.player_mode = 0
122
123
124
125 self.jingles_mode = 0
126 if 'jingles' in self.station:
127 self.jingles_mode = int(self.station['jingles']['mode'])
128 self.jingles_shuffle = self.station['jingles']['shuffle']
129 self.jingles_dir = self.station['jingles']['dir']
130 if self.jingles_mode == 1:
131 self.jingles_callback('/jingles', [1])
132
133
134
135 self.relay_mode = 0
136 if 'relay' in self.station:
137 self.relay_mode = int(self.station['relay']['mode'])
138 self.relay_url = self.station['relay']['url']
139 self.relay_author = self.station['relay']['author']
140 if self.relay_mode == 1:
141 self.relay_callback('/media/relay', [1])
142
143
144
145 self.twitter_mode = 0
146 if 'twitter' in self.station:
147 self.twitter_mode = int(self.station['twitter']['mode'])
148 self.twitter_key = self.station['twitter']['key']
149 self.twitter_secret = self.station['twitter']['secret']
150 self.twitter_tags = self.station['twitter']['tags'].split(' ')
151 if self.twitter_mode == 1:
152 self.twitter_callback('/twitter', [1])
153
154
155
156 self.record_mode = 0
157 if 'record' in self.station:
158 self.record_mode = int(self.station['record']['mode'])
159 self.record_dir = self.station['record']['dir']
160 if self.record_mode == 1:
161 self.record_callback('/record', [1])
162
163
164
165 self.run_mode = 1
166
167
168 self.osc_control_mode = 0
169
170 if 'control' in self.station:
171 self.osc_control_mode = int(self.station['control']['mode'])
172 self.osc_port = self.station['control']['port']
173 if self.osc_control_mode == 1:
174 self.osc_controller = OSCController(self.osc_port)
175 self.osc_controller.start()
176
177 self.osc_controller.add_method('/media/next', 'i', self.media_next_callback)
178 self.osc_controller.add_method('/media/relay', 'i', self.relay_callback)
179 self.osc_controller.add_method('/twitter', 'i', self.twitter_callback)
180 self.osc_controller.add_method('/jingles', 'i', self.jingles_callback)
181 self.osc_controller.add_method('/record', 'i', self.record_callback)
182 self.osc_controller.add_method('/player', 'i', self.player_callback)
183 self.osc_controller.add_method('/run', 'i', self.run_callback)
184
186 value = value[0]
187 self.run_mode = value
188 message = "Station " + self.channel_url + " : received OSC message '%s' with arguments '%d'" % (path, value)
189 self.logger.write_info(message)
190
196
198 value = value[0]
199 if value == 1:
200 self.relay_mode = 1
201 self.player.start_relay(self.relay_url)
202 elif value == 0:
203 self.relay_mode = 0
204 self.player.stop_relay()
205 self.id = 0
206 self.next_media = 1
207 message = "Station " + self.channel_url + " : received OSC message '%s' with arguments '%d'" % (path, value)
208 self.logger.write_info(message)
209 message = "Station " + self.channel_url + " : relaying : %s" % self.relay_url
210 self.logger.write_info(message)
211
213 value = value[0]
214 import tinyurl
215 self.twitter = Twitter(self.twitter_key, self.twitter_secret)
216 self.twitter_mode = value
217 message = "Station " + self.channel_url + " : received OSC message '%s' with arguments '%d'" % (path, value)
218 self.m3u_tinyurl = tinyurl.create_one(self.channel.url + '/m3u/' + self.m3u.split(os.sep)[-1])
219 self.rss_tinyurl = tinyurl.create_one(self.channel.url + '/rss/' + self.rss_playlist_file.split(os.sep)[-1])
220 self.logger.write_info(message)
221
223 value = value[0]
224 if value == 1:
225 self.jingles_list = self.get_jingles()
226 self.jingles_length = len(self.jingles_list)
227 self.jingle_id = 0
228 self.jingles_mode = value
229 message = "Station " + self.channel_url + " : received OSC message '%s' with arguments '%d'" % (path, value)
230 self.logger.write_info(message)
231
233 value = value[0]
234 if value == 1:
235 if not os.path.exists(self.record_dir):
236 os.makedirs(self.record_dir)
237 self.rec_file = self.short_name + '-' + \
238 datetime.datetime.now().strftime("%x-%X").replace('/', '_') + '.' + self.channel.format
239 self.recorder = Recorder(self.record_dir)
240 self.recorder.open(self.rec_file)
241 elif value == 0:
242 self.recorder.close()
243 date = datetime.datetime.now().strftime("%Y")
244 if self.channel.format == 'mp3':
245 media = Mp3(self.record_dir + os.sep + self.rec_file)
246 if self.channel.format == 'ogg':
247 media = Ogg(self.record_dir + os.sep + self.rec_file)
248 media.metadata = {'artist': self.artist.encode('utf-8'),
249 'title': self.title.encode('utf-8'),
250 'album': self.short_name.encode('utf-8'),
251 'genre': self.channel.genre.encode('utf-8'),
252 'date' : date.encode('utf-8'),}
253 media.write_tags()
254 self.record_mode = value
255 message = "Station " + self.channel_url + " : received OSC message '%s' with arguments '%d'" % (path, value)
256 self.logger.write_info(message)
257
259 value = value[0]
260 self.player_mode = value
261 message = "Station " + self.channel_url + " : received OSC message '%s' with arguments '%d'" % (path, value)
262 self.logger.write_info(message)
263
265 file_list = []
266 for root, dirs, files in os.walk(self.media_dir):
267 for file in files:
268 s = file.split('.')
269 ext = s[len(s)-1]
270 if ext.lower() == self.channel.format and not os.sep+'.' in file:
271 file_list.append(root + os.sep + file)
272 file_list.sort()
273 return file_list
274
276 file_list = []
277 for root, dirs, files in os.walk(self.jingles_dir):
278 for file in files:
279 s = file.split('.')
280 ext = s[len(s)-1]
281 if ext.lower() == self.channel.format and not os.sep+'.' in file:
282 file_list.append(root + os.sep + file)
283 file_list.sort()
284 return file_list
285
345
355
357 rss_item_list = []
358 if not os.path.exists(self.rss_dir):
359 os.makedirs(self.rss_dir)
360 channel_subtitle = self.channel.name + ' ' + sub_title
361 _date_now = datetime.datetime.now()
362 date_now = str(_date_now)
363 media_absolute_playtime = _date_now
364
365 for media in media_list:
366 media_stats = os.stat(media.media)
367 media_date = time.localtime(media_stats[8])
368 media_date = time.strftime("%a, %d %b %Y %H:%M:%S +0200", media_date)
369 media.metadata['Duration'] = str(media.length).split('.')[0]
370 media.metadata['Bitrate'] = str(media.bitrate) + ' kbps'
371 media.metadata['Next play'] = str(media_absolute_playtime).split('.')[0]
372
373 media_description = '<table>'
374 media_description_item = '<tr><td>%s: </td><td><b>%s</b></td></tr>'
375 for key in media.metadata.keys():
376 if media.metadata[key] != '':
377 media_description += media_description_item % (key.capitalize(), media.metadata[key])
378 media_description += '</table>'
379
380 title = media.metadata['title']
381 artist = media.metadata['artist']
382 if not (title or artist):
383 song = str(media.file_title)
384 else:
385 song = artist + ' : ' + title
386
387 media_absolute_playtime += media.length
388
389 if self.rss_enclosure == '1':
390 media_link = self.channel.url + '/media/' + media.file_name
391 media_link = media_link.decode('utf-8')
392 rss_item_list.append(RSSItem(
393 title = song,
394 link = media_link,
395 description = media_description,
396 enclosure = Enclosure(media_link, str(media.size), 'audio/mpeg'),
397 guid = Guid(media_link),
398 pubDate = media_date,)
399 )
400 else:
401 media_link = self.metadata_url + '/' + media.file_name + '.xml'
402 media_link = media_link.decode('utf-8')
403 rss_item_list.append(RSSItem(
404 title = song,
405 link = media_link,
406 description = media_description,
407 guid = Guid(media_link),
408 pubDate = media_date,)
409 )
410
411 rss = RSS2(title = channel_subtitle,
412 link = self.channel.url,
413 description = self.channel.description.decode('utf-8'),
414 lastBuildDate = date_now,
415 items = rss_item_list,)
416 f = open(rss_file, 'w')
417 rss.write_xml(f, 'utf-8')
418 f.close()
419
427
429 self.prefix = '#nowplaying (relaying #LIVE)'
430 self.title = self.channel.description.encode('utf-8')
431 self.artist = self.relay_author.encode('utf-8')
432 self.title = self.title.replace('_', ' ')
433 self.artist = self.artist.replace('_', ' ')
434 self.song = self.artist + ' : ' + self.title
435 self.stream = self.player.relay_read()
436
438 self.prefix = '#nowplaying'
439 self.current_media_obj = self.media_to_objs([self.media])
440 self.title = self.current_media_obj[0].metadata['title']
441 self.artist = self.current_media_obj[0].metadata['artist']
442 self.title = self.title.replace('_', ' ')
443 self.artist = self.artist.replace('_', ' ')
444 if not (self.title or self.artist):
445 song = str(self.current_media_obj[0].file_name)
446 else:
447 song = self.artist + ' : ' + self.title
448 self.song = song.encode('utf-8')
449 self.artist = self.artist.encode('utf-8')
450 self.metadata_file = self.metadata_dir + os.sep + self.current_media_obj[0].file_name + '.xml'
451
452 self.update_rss(self.current_media_obj, self.rss_current_file, '(currently playing)')
453 self.logger.write_info('DeeFuzzing on %s : id = %s, name = %s' \
454 % (self.short_name, self.id, self.current_media_obj[0].file_name))
455 self.player.set_media(self.media)
456 if self.player_mode == 0:
457 self.stream = self.player.file_read_slow()
458 elif self.player_mode == 1:
459 self.stream = self.player.file_read_fast()
460
462 artist_names = self.artist.split(' ')
463 artist_tags = ' #'.join(list(set(artist_names)-set(['&', '-'])))
464 message = '%s %s on #%s' % (self.prefix, self.song, self.short_name)
465 tags = '#' + ' #'.join(self.twitter_tags)
466 message = message + ' ' + tags
467 message = message[:108] + ' M3U: ' + self.m3u_tinyurl
468 self.update_twitter(message)
469
471 self.channel.open()
472 self.channel_delay = self.channel.delay()
473
475 log = True
476 while not self.server_ping:
477 try:
478 self.q.get(1)
479 server = urllib.urlopen(self.server_url)
480 self.server_ping = True
481 self.logger.write_info('Station ' + self.channel_url + ' : channel available')
482 self.q.task_done()
483 except:
484 time.sleep(0.5)
485 if log:
486 self.logger.write_error('Station ' + self.channel_url + ' : could not connect the channel' )
487 log = False
488 self.q.task_done()
489 pass
490
492 self.ping_server()
493 self.q.get(1)
494 self.channel_open()
495 self.logger.write_info('Station ' + self.channel_url + ' : channel connected')
496 self.q.task_done()
497
498 while self.run_mode:
499 self.q.get(1)
500 self.next_media = 0
501 self.media = self.get_next_media()
502 self.counter += 1
503 if self.relay_mode:
504 self.set_relay_mode()
505 elif os.path.exists(self.media) and not os.sep+'.' in self.media:
506 if self.lp == 0:
507 self.logger.write_error('Station ' + self.channel_url + ' : has no media to stream !')
508 break
509 self.set_read_mode()
510 self.q.task_done()
511
512 self.q.get(1)
513 if (not (self.jingles_mode and (self.counter % 2)) or self.relay_mode) and self.twitter_mode:
514 try:
515 self.update_twitter_current()
516 except:
517 continue
518 try:
519 self.channel.set_metadata({'song': self.song, 'charset': 'utf-8',})
520 except:
521 continue
522 self.q.task_done()
523
524 for self.chunk in self.stream:
525 if self.next_media or not self.run_mode:
526 break
527 if self.record_mode:
528 try:
529 self.q.get(1)
530 self.recorder.write(self.chunk)
531 self.q.task_done()
532 except:
533 self.logger.write_error('Station ' + self.channel_url + ' : could not write the buffer to the file')
534 self.q.task_done()
535 continue
536 try:
537 self.q.get(1)
538 self.channel.send(self.chunk)
539 self.channel.sync()
540 self.q.task_done()
541 except:
542 self.logger.write_error('Station ' + self.channel_url + ' : could not send the buffer')
543 self.q.task_done()
544 try:
545 self.q.get(1)
546 self.channel.close()
547 self.logger.write_info('Station ' + self.channel_url + ' : channel closed')
548 self.q.task_done()
549 except:
550 self.logger.write_error('Station ' + self.channel_url + ' : could not close the channel')
551 self.q.task_done()
552 continue
553 try:
554 self.ping_server()
555 self.q.get(1)
556 self.channel_open()
557 self.channel.set_metadata({'song': self.song, 'charset': 'utf8',})
558 self.logger.write_info('Station ' + self.channel_url + ' : channel restarted')
559 self.q.task_done()
560 except:
561 self.logger.write_error('Station ' + self.channel_url + ' : could not restart the channel')
562 self.q.task_done()
563 continue
564 continue
565
566 if self.record_mode:
567 self.recorder.close()
568
569 self.channel.close()
570