comparison src/plugins/plugin_misc_radiocol.py @ 765:787ee59dba9c

plugins radiocol, xep-0054: better handling of upload errors: - radiocolSongAdded is now asynchronous - _buildAvatar return a Failure if the image is not readable
author souliane <souliane@mailoo.org>
date Tue, 17 Dec 2013 18:44:53 +0100
parents d0e809014ea2
children bfabeedbf32e
comparison
equal deleted inserted replaced
764:d0e809014ea2 765:787ee59dba9c
19 19
20 from logging import debug, info, warning, error 20 from logging import debug, info, warning, error
21 from twisted.words.xish import domish 21 from twisted.words.xish import domish
22 from twisted.internet import reactor 22 from twisted.internet import reactor
23 from twisted.words.protocols.jabber import jid 23 from twisted.words.protocols.jabber import jid
24 24 from twisted.internet import threads, defer
25 from sat.core import exceptions
25 import os.path 26 import os.path
26 import copy 27 import copy
27 import time 28 import time
28 from os import unlink 29 from os import unlink
29 from mutagen.oggvorbis import OggVorbis, OggVorbisHeaderError 30 from mutagen.oggvorbis import OggVorbis, OggVorbisHeaderError
63 RoomGame._init_(self, host, PLUGIN_INFO, (NC_RADIOCOL, RADIOC_TAG), 64 RoomGame._init_(self, host, PLUGIN_INFO, (NC_RADIOCOL, RADIOC_TAG),
64 game_init={'queue': [], 'upload': True, 'playing': False, 'to_delete': {}}) 65 game_init={'queue': [], 'upload': True, 'playing': False, 'to_delete': {}})
65 self.host = host 66 self.host = host
66 host.bridge.addMethod("radiocolLaunch", ".plugin", in_sign='asss', out_sign='', method=self.prepareRoom) 67 host.bridge.addMethod("radiocolLaunch", ".plugin", in_sign='asss', out_sign='', method=self.prepareRoom)
67 host.bridge.addMethod("radiocolCreate", ".plugin", in_sign='sass', out_sign='', method=self.createGame) 68 host.bridge.addMethod("radiocolCreate", ".plugin", in_sign='sass', out_sign='', method=self.createGame)
68 host.bridge.addMethod("radiocolSongAdded", ".plugin", in_sign='sss', out_sign='', method=self.radiocolSongAdded) 69 host.bridge.addMethod("radiocolSongAdded", ".plugin", in_sign='sss', out_sign='', method=self.radiocolSongAdded, async=True)
69 host.bridge.addSignal("radiocolPlayers", ".plugin", signature='ssass') # room_jid, referee, players, profile 70 host.bridge.addSignal("radiocolPlayers", ".plugin", signature='ssass') # room_jid, referee, players, profile
70 host.bridge.addSignal("radiocolStarted", ".plugin", signature='ssasais') # room_jid, referee, players, [QUEUE_TO_START, QUEUE_LIMIT], profile 71 host.bridge.addSignal("radiocolStarted", ".plugin", signature='ssasais') # room_jid, referee, players, [QUEUE_TO_START, QUEUE_LIMIT], profile
71 host.bridge.addSignal("radiocolSongRejected", ".plugin", signature='sss') # room_jid, reason, profile 72 host.bridge.addSignal("radiocolSongRejected", ".plugin", signature='sss') # room_jid, reason, profile
72 host.bridge.addSignal("radiocolPreload", ".plugin", signature='sssssss') # room_jid, timestamp, filename, title, artist, album, profile 73 host.bridge.addSignal("radiocolPreload", ".plugin", signature='sssssss') # room_jid, timestamp, filename, title, artist, album, profile
73 host.bridge.addSignal("radiocolPlay", ".plugin", signature='sss') # room_jid, filename, profile 74 host.bridge.addSignal("radiocolPlay", ".plugin", signature='sss') # room_jid, filename, profile
92 # be streamed to the backend using XMPP file copy 93 # be streamed to the backend using XMPP file copy
93 # Here we cheat because we know we are on the same host, and we don't 94 # Here we cheat because we know we are on the same host, and we don't
94 # check data. Referee will have to parse the song himself to check it 95 # check data. Referee will have to parse the song himself to check it
95 client = self.host.getClient(profile) 96 client = self.host.getClient(profile)
96 if not client: 97 if not client:
97 error(_("Can't access profile's data")) 98 raise exceptions.NotConnectedProfileError(_("Can't access profile's data"))
98 return
99 try: 99 try:
100 song = OggVorbis(song_path) 100 song = OggVorbis(song_path)
101 except OggVorbisHeaderError: 101 except OggVorbisHeaderError:
102 #this file is not ogg vorbis, we reject it 102 #this file is not ogg vorbis, we reject it
103 self.deleteFile(song_path) # FIXME: same host trick (see note above) 103 self.deleteFile(song_path) # FIXME: same host trick (see note above)
104 self.host.bridge.radiocolSongRejected(jid.JID(referee).userhost(), 104 return defer.fail(exceptions.DataError("Uploaded file is not Ogg Vorbis song, only Ogg Vorbis songs are acceptable"))
105 "Uploaded file is not Ogg Vorbis song, only Ogg Vorbis songs are acceptable", profile)
106 """mess = self.createGameElt(jid.JID(referee))
107 reject_elt = mess.firstChildElement().addElement(('','song_rejected'))
108 reject_elt['sender'] = client.jid
109 reject_elt['reason'] = "Uploaded file is not Ogg Vorbis song, only Ogg Vorbis songs are acceptable"
110 #FIXME: add an error code
111 self.host.profiles[profile].xmlstream.send(mess)"""
112 return
113 attrs = {'filename': os.path.basename(song_path), 105 attrs = {'filename': os.path.basename(song_path),
114 'title': song.get("title", ["Unknown"])[0], 106 'title': song.get("title", ["Unknown"])[0],
115 'artist': song.get("artist", ["Unknown"])[0], 107 'artist': song.get("artist", ["Unknown"])[0],
116 'album': song.get("album", ["Unknown"])[0], 108 'album': song.get("album", ["Unknown"])[0],
117 'length': str(song.info.length) 109 'length': str(song.info.length)
118 } 110 }
119 self.send(jid.JID(referee), ('', 'song_added'), attrs, profile=profile)
120
121 radio_data = self.games[jid.JID(referee).userhost()] # FIXME: referee comes from Libervia's client side, it's unsecure 111 radio_data = self.games[jid.JID(referee).userhost()] # FIXME: referee comes from Libervia's client side, it's unsecure
122 radio_data['to_delete'][attrs['filename']] = song_path # FIXME: works only because of the same host trick, see the note under the docstring 112 radio_data['to_delete'][attrs['filename']] = song_path # FIXME: works only because of the same host trick, see the note under the docstring
113 return threads.deferToThread(self.send, jid.JID(referee), ('', 'song_added'), attrs, profile=profile)
123 114
124 def playNext(self, room_jid, profile): 115 def playNext(self, room_jid, profile):
125 """"Play next song in queue if exists, and put a timer 116 """"Play next song in queue if exists, and put a timer
126 which trigger after the song has been played to play next one""" 117 which trigger after the song has been played to play next one"""
127 #TODO: songs need to be erased once played or found invalids 118 #TODO: songs need to be erased once played or found invalids