def lineReceived(self, raw_message): try: log.debug('ctrl:mpv: received %s' % raw_message) msg = json.loads(raw_message.decode('utf-8')) except ValueError: self.transport.loseConnection() else: if 'request_id' in msg \ and int(msg['request_id']) in self.__commands_cb: cb = self.__commands_cb[int(msg['request_id'])] cb.callback(msg) elif 'error' in msg: if msg['error'] != 'success': self.factory.handler.error(msg['error']) elif 'event' in msg: try: f = getattr(self.factory.handler, 'EVENT_%s' % msg['event'].replace('-', '_')) except AttributeError: log.debug('ctrl:mpv: unknown event received: %s' % msg['event']) else: for unwanted_arg in ('event', 'id'): if unwanted_arg in msg: del msg[unwanted_arg] f(**msg) else: log.err('ctrl:mpv: unhandled message received: %s' % msg)
def str_to_bytes(data, encoding="utf-8", errors="strict"): try: return data.encode(encoding, errors=errors) except UnicodeDecodeError as ex: data = data.encode(encoding, errors="replace") log.err("Unable to encode string %s" % data) raise ex
def update(self, force=False, sync=False): if self.updating_state["running"]: log.err(_("A library update is already running")) return self.updating_state["id"] += 1 if sync: # synchrone update self.walk_directory('', force=force) self.state["last_update"] = time.time() else: # asynchrone update self.updating_state["running"] = True defered = threads.deferToThread(self.update_in_thread, '', force) defered.pause() # Add callback functions defered.addCallback(lambda *x: self.end_update()) # Add errback functions def error_handler(failure, db_class): # Log the exception to debug pb later failure.printTraceback() db_class.end_update(False) return False defered.addErrback(error_handler, self) defered.unpause() return dict([(self.TYPE + "_updating_db", self.updating_state["id"])])
def _find_timer_TS_(self, buffer): c = 0 while c + TS_PACKET_LENGTH < len(buffer): if buffer[c] == buffer[c + TS_PACKET_LENGTH] == TS_SYNC: break c += 1 else: return None while c + TS_PACKET_LENGTH < len(buffer): start = buffer[c + 1] & 0x40 if not start: c += TS_PACKET_LENGTH continue tsid = ((buffer[c + 1] & 0x3F) << 8) + buffer[c + 2] adapt = (buffer[c + 3] & 0x30) >> 4 offset = 4 if adapt & 0x02: # meta info present, skip it for now offset += buffer[c + offset] + 1 if adapt & 0x01: timestamp = self.ReadPESHeader(c + offset, buffer[c + offset:], tsid)[1] if timestamp is None: # this should not happen log.err('bad TS') return None return c + offset + timestamp c += TS_PACKET_LENGTH return None
def __init__(self, file): core.AVContainer.__init__(self) # read the header h = file.read(12) if h[:4] not in (b"RIFF", b'SDSS', b'RMP3', ): raise ParseError('unsupported RIFF header: %s' % h[:4]) self.has_idx = False self.header = {} self.junkStart = None self.infoStart = None self.type = h[8:12] if self.type == b'AVI ': self.mime = 'video/avi' elif self.type == b'WAVE': self.mime = 'audio/wav' try: while self._parseRIFFChunk(file): pass except IOError: log.err('error in file, stop parsing') self._find_subtitles(file.name) if not self.has_idx and self.media == core.MEDIA_AV: log.debug('WARNING: avi has no index') self._set('corrupt', True)
def __try_connect(self): if not self.factory.conn: if self.__connect_tries < 5: reactor.connectUNIX(self.socket_path(), self.factory) reactor.callLater(1, self.__try_connect) else: log.err('ctrl:mpv: Could not connect to player process, ' 'giving up.')
def get_position(self): if self.bin is not None and Gst.State.NULL != self.__get_gst_state()\ and self.bin.get_property('current-uri'): ok, p = self.bin.query_position(Gst.Format.TIME) if not ok: log.err(_("Gstreamer: unable to get stream position")) return 0 p //= Gst.SECOND return p return 0
def end_update(self, result=True): self.updating_state["running"] = False if result: log.msg(_("The %s library has been updated") % self.TYPE) self.dispatch_signame(self.UPDATE_SIGNAL_NAME) self.state["last_update"] = time.time() else: msg = _("Unable to update the %s library. See log.") % self.TYPE log.err(msg) self.updating_state["error"] = msg return True
def add_webradio(self, source, name, urls, cat=None): provided_urls = [] for url in urls: if url.lower().startswith("http://") or \ url.lower().startswith("https://"): try: if url.lower().endswith(".pls"): provided_urls.extend(get_uris_from_pls(url)) elif url.lower().endswith(".m3u"): provided_urls.extend(get_uris_from_m3u(url)) else: provided_urls.append(url) except IOError: log.err(_("Could not parse %s") % url) pass needed_urls = [] for url in provided_urls: try: protocol = url.split(':')[0] if protocol not in ( 'http', 'https', 'rtsp', ): raise ValueError except ValueError: log.err( _("Discarding %s : webradio protocol not supported.") % url) else: if url not in needed_urls: needed_urls.append(url) if len(needed_urls) < 1: raise DeejaydError( _("Given urls %s is not " "supported") % ",".join(urls)) cats = cat is not None and [cat] or [] webradio = Session.query(Webradio)\ .filter(Webradio.source == source)\ .filter(Webradio.name == name)\ .one_or_none() if webradio is not None: raise DeejaydError(_("Webradio %s already exists") % name) webradio = Webradio(source=source, name=name) Session.add(webradio) for c in cats: webradio.categories.append(Session.query(WebradioCategory).get(c)) for url in needed_urls: webradio.entries.append(WebradioEntry(url=url))
def __message(self, bus, message): if message.type == Gst.MessageType.EOS: self._end() elif message.type == Gst.MessageType.TAG: self.__update_metadata(message.parse_tag()) elif message.type == Gst.MessageType.ERROR: err, debug = message.parse_error() log.err("Gstreamer Error: %s" % str(err)) log.debug("Gstreamer Error debug: %s" % str(debug)) elif message.type == Gst.MessageType.STREAM_START: if self.__in_gapless_transition: self._end() return True
def __init__(self, start_inotify=True, library_update=True): super(DeejayDaemonCore, self).__init__() config = DeejaydConfig() self.player = player.init(config) self.put_sub_handler('player', self.player) self.audiolib, self.videolib, self.watcher = library.init(self.player, config) self.put_sub_handler('audiolib', self.audiolib) if self.videolib is not None: self.put_sub_handler('videolib', self.videolib) self.recpls = DeejaydRecordedPlaylist(self.audiolib) self.put_sub_handler('recpls', self.recpls) # add audio queue/playlist and video playlist self.sources = sources.init(self.player, self.audiolib, self.videolib, config) for source in list(self.sources.sources.values()): self.put_sub_handler(source.name, source) setattr(self, source.name, source) # add webradio if player can play http stream if self.player.is_supported_uri("http"): self.webradio = DeejaydWebradio(self.player) self.put_sub_handler('webradio', self.webradio) else: log.err(_("Player is not able to play http streams")) self.webradio = None if library_update: self.audiolib.update() if self.videolib is not None: self.videolib.update() # enable JSON-RPC introspection self.put_sub_handler('introspection', JSONRPCIntrospection(self)) # start inotify thread when we are sure that all init stuff are ok if self.watcher and start_inotify: log.debug(_("Start inotify watcher")) self.watcher.start() # record changes and close session after the initialization Session.commit() Session.remove()
def build_entity(self, inbuf): self.compute_id(inbuf) if self.id_len == 0: log.err('EBML entity not found, bad file format') raise ParseError() self.entity_len, self.len_size = self.compute_len(inbuf[self.id_len:]) self.entity_data = inbuf[self.get_header_len() : self.get_total_len()] self.ebml_length = self.entity_len self.entity_len = min(len(self.entity_data), self.entity_len) # if the data size is 8 or less, it could be a numeric value self.value = 0 if self.entity_len <= 8: for pos, shift in zip(list(range(self.entity_len)), list(range((self.entity_len - 1) * 8, -1, -8))): self.value |= self.entity_data[pos] << shift
def lineReceived(self, line): # use str instead of bytes to decode json commands # and return answer line = line.strip(b"\r").decode("utf-8") delimiter = self.delimiter.decode("utf-8") try: parsed = loads_request(line) args, function_path = parsed['params'], parsed["method"] if function_path.startswith("signal"): # it's a command linked with this connection method = function_path.split(self.separator, 1)[1] function = self.get_function(method) elif function_path == "close": function = self.close else: function = self.deejayd_core.get_function(function_path) except Fault as f: try: r_id = parsed["id"] except: r_id = None ans = JSONRPCResponse(f, r_id) else: # explicitly init session for this request Session() try: result = function(*args) Session.commit() except Exception as ex: Session.rollback() if not isinstance(ex, Fault): log.err(traceback.format_exc()) result = Fault(self.FAILURE, _("error, see deejayd log")) else: result = ex finally: Session.remove() ans = JSONRPCResponse(result, parsed["id"]) self.send_buffer(ans.to_json()+delimiter) if self.__need_to_close: self.transport.loseConnection() self.__need_to_close = False
def init(player, config): audio_library, video_library, lib_watcher = None, None, None audio_dir = config.get("mediadb", "music_directory") try: audio_library = AudioLibrary(audio_dir) except DeejaydError as msg: log.err(_("Unable to init audio library : %s") % msg, fatal=True) if config.getboolean("video", "enabled"): video_dir = config.get('mediadb', 'video_directory') try: video_library = VideoLibrary(video_dir) except DeejaydError as msg: log.err(_("Unable to init video library : %s") % msg, fatal=True) if inotify is not None: lib_watcher = inotify.DeejaydInotify(audio_library, video_library) return audio_library, video_library, lib_watcher
def init(config): media_backend = config.get("general", "media_backend") if media_backend == "auto": backend_it = iter([DEFAULT_BACKEND] + AVAILABLE_BACKENDS) media_backend = None try: while not media_backend: backend = next(backend_it) try: backend_module = get_backend_module(backend) except ImportError: # Do nothing, simply ignore pass else: media_backend = backend config.set('general', 'mediabackend', backend) log.msg(_("Autodetected %s backend." % backend)) except StopIteration: log.err(_("Could not find suitable media backend."), fatal=True) elif media_backend in AVAILABLE_BACKENDS: backend_module = get_backend_module(media_backend) else: log.err(_("Invalid media backend %s" % media_backend), fatal=True) try: player_class = getattr(backend_module, '%sPlayer' % media_backend.capitalize()) player = player_class(config) except PlayerError as err: log.err(str(err), fatal=True) return player
def _parseAVIH(self, t): retval = {} v = struct.unpack('<IIIIIIIIIIIIII', t[0:56]) (retval['dwMicroSecPerFrame'], retval['dwMaxBytesPerSec'], retval['dwPaddingGranularity'], retval['dwFlags'], retval['dwTotalFrames'], retval['dwInitialFrames'], retval['dwStreams'], retval['dwSuggestedBufferSize'], retval['dwWidth'], retval['dwHeight'], retval['dwScale'], retval['dwRate'], retval['dwStart'], retval['dwLength']) = v if retval['dwMicroSecPerFrame'] == 0: log.err("ERROR: Corrupt AVI") raise ParseError() return retval
def error(self, msg): log.err('ctrl:mpv: error received: %s' % msg)
def processEnded(self, status): if status.value.exitCode not in self.manager.EXIT_SUCCESS: log.err('ctrl: child process ended with status: %s' % status) self.manager._process_gone()
def __on_reload_error(self, failure): log.err(_("Unable to update icecast webradio, see exception below")) log.err(failure)
def lineLengthExceeded(self, line): log.err(_("Request too long, close the connection")) self.transport.loseConnection()
def _readatom(self, file): s = file.read(8) if len(s) < 8: return 0 atomsize, atomtype = struct.unpack('>I4s', s) if not atomtype.decode('latin1').isalnum(): # stop at nonsense data return 0 log.debug('%r [%X]' % (atomtype, atomsize)) if atomtype == b'udta': # Userdata (Metadata) pos = 0 tabl = {} i18ntabl = {} atomdata = file.read(atomsize - 8) while pos < atomsize - 12: (datasize, datatype) = struct.unpack('>I4s', atomdata[pos:pos + 8]) if datatype[0] == 169: # i18n Metadata... mypos = 8 + pos while mypos + 4 < datasize + pos: # first 4 Bytes are i18n header (tlen, lang) = struct.unpack('>HH', atomdata[mypos:mypos + 4]) i18ntabl[lang] = i18ntabl.get(lang, {}) l = atomdata[mypos + 4:mypos + tlen + 4] i18ntabl[lang][datatype[1:]] = l mypos += tlen + 4 elif datatype == b'WLOC': # Drop Window Location pass else: if atomdata[pos + 8:pos + datasize][0] > 1: tabl[datatype] = atomdata[pos + 8:pos + datasize] pos += datasize if len(i18ntabl) > 0: for k in i18ntabl: if k in QTLANGUAGES and QTLANGUAGES[k] == 'en': self._appendtable('QTUDTA', i18ntabl[k]) self._appendtable('QTUDTA', tabl) else: log.debug('NO i18') self._appendtable('QTUDTA', tabl) elif atomtype == b'trak': atomdata = file.read(atomsize - 8) pos = 0 trackinfo = {} tracktype = None while pos < atomsize - 8: (datasize, datatype) = struct.unpack('>I4s', atomdata[pos:pos + 8]) if datatype == b'tkhd': tkhd = struct.unpack('>6I8x4H36xII', atomdata[pos + 8:pos + datasize]) trackinfo['width'] = tkhd[10] >> 16 trackinfo['height'] = tkhd[11] >> 16 trackinfo['id'] = tkhd[3] try: # XXX Timestamp of Seconds is since January 1st 1904! # XXX 2082844800 is the difference between Unix and # XXX Apple time. FIXME to work on Apple, too self.timestamp = int(tkhd[1]) - 2082844800 except Exception as e: log.err('There was trouble extracting timestamp') elif datatype == b'mdia': pos += 8 datasize -= 8 log.debug('--> mdia information') while datasize: mdia = struct.unpack('>I4s', atomdata[pos:pos + 8]) if mdia[1] == b'mdhd': # Parse based on version of mdhd header. See # http://wiki.multimedia.cx/index.php?title=QuickTime_container#mdhd ver = atomdata[pos + 8] if ver == 0: mdhd = struct.unpack( '>IIIIIhh', atomdata[pos + 8:pos + 8 + 24]) elif ver == 1: mdhd = struct.unpack( '>IQQIQhh', atomdata[pos + 8:pos + 8 + 36]) else: mdhd = None if mdhd: # duration / time scale trackinfo['length'] = mdhd[4] / mdhd[3] if mdhd[5] in QTLANGUAGES: trackinfo['language'] = QTLANGUAGES[ mdhd[5]] # mdhd[6] == quality self.length = max(self.length, mdhd[4] / mdhd[3]) elif mdia[1] == b'minf': # minf has only atoms inside pos -= (mdia[0] - 8) datasize += (mdia[0] - 8) elif mdia[1] == b'stbl': # stbl has only atoms inside pos -= (mdia[0] - 8) datasize += (mdia[0] - 8) elif mdia[1] == b'hdlr': hdlr = struct.unpack( '>I4s4s', atomdata[pos + 8:pos + 8 + 12]) if hdlr[1] == b'mhlr': if hdlr[2] == b'vide': tracktype = 'video' if hdlr[2] == b'soun': tracktype = 'audio' elif mdia[1] == b'stsd': stsd = struct.unpack('>2I', atomdata[pos + 8:pos + 8 + 8]) if stsd[1] > 0: codec = atomdata[pos + 16:pos + 16 + 8] codec = struct.unpack('>I4s', codec) trackinfo['codec'] = codec[1] if codec[1] == b'jpeg': tracktype = 'image' elif mdia[1] == b'dinf': dref = struct.unpack('>I4s', atomdata[pos + 8:pos + 8 + 8]) log.debug(' --> %r, %r (useless)' % mdia) if dref[1] == b'dref': num = struct.unpack( '>I', atomdata[pos + 20:pos + 20 + 4])[0] rpos = pos + 20 + 4 for ref in range(num): # FIXME: do somthing if this references ref = struct.unpack( '>I3s', atomdata[rpos:rpos + 7]) data = atomdata[rpos + 7:rpos + ref[0]] rpos += ref[0] else: if mdia[1].startswith(b'st'): log.debug(' --> %r, %r (sample)' % mdia) elif mdia[1] == b'vmhd' and not tracktype: # indicates that this track is video tracktype = 'video' elif mdia[1] in [b'vmhd', b'smhd' ] and not tracktype: # indicates that this track is audio tracktype = 'audio' else: log.debug(' --> %r, %r (unknown)' % mdia) pos += mdia[0] datasize -= mdia[0] elif datatype == b'udta': log.debug(str(struct.unpack('>I4s', atomdata[:8]))) else: if datatype == b'edts': log.debug('--> %r [%d] (edit list)' % \ (datatype, datasize)) else: log.debug('--> %r [%d] (unknown)' % \ (datatype, datasize)) pos += datasize info = None if tracktype == 'video': info = core.VideoStream() self.video.append(info) if tracktype == 'audio': info = core.AudioStream() self.audio.append(info) if info: for key, value in list(trackinfo.items()): setattr(info, key, value) elif atomtype == b'mvhd': # movie header mvhd = struct.unpack('>6I2h', file.read(28)) self.length = max(self.length, mvhd[4] / mvhd[3]) self.volume = mvhd[6] file.seek(atomsize - 8 - 28, 1) elif atomtype == b'cmov': # compressed movie datasize, atomtype = struct.unpack('>I4s', file.read(8)) if not atomtype == b'dcom': return atomsize method = struct.unpack('>4s', file.read(datasize - 8))[0] datasize, atomtype = struct.unpack('>I4s', file.read(8)) if not atomtype == b'cmvd': return atomsize if method == b'zlib': data = file.read(datasize - 8) try: decompressed = zlib.decompress(data) except Exception as e: try: decompressed = zlib.decompress(data[4:]) except Exception as e: log.err('There was a proble decompressiong atom') return atomsize decompressedIO = io.StringIO(decompressed) while self._readatom(decompressedIO): pass else: log.info('unknown compression %r' % method) # unknown compression method file.seek(datasize - 8, 1) elif atomtype == b'moov': # decompressed movie info while self._readatom(file): pass elif atomtype == b'mdat': pos = file.tell() + atomsize - 8 # maybe there is data inside the mdat log.info('parsing mdat') while self._readatom(file): pass log.info('end of mdat') file.seek(pos, 0) elif atomtype == b'rmra': # reference list while self._readatom(file): pass elif atomtype == b'rmda': # reference atomdata = file.read(atomsize - 8) pos = 0 url = '' quality = 0 datarate = 0 while pos < atomsize - 8: (datasize, datatype) = struct.unpack('>I4s', atomdata[pos:pos + 8]) if datatype == b'rdrf': rflags, rtype, rlen = struct.unpack( '>I4sI', atomdata[pos + 8:pos + 20]) if rtype == b'url ': url = atomdata[pos + 20:pos + 20 + rlen] if url.find('\0') > 0: url = url[:url.find('\0')] elif datatype == b'rmqu': quality = struct.unpack('>I', atomdata[pos + 8:pos + 12])[0] elif datatype == b'rmdr': datarate = struct.unpack('>I', atomdata[pos + 12:pos + 16])[0] pos += datasize if url: self._references.append((url, quality, datarate)) else: if not atomtype in [b'wide', b'free']: log.info('unhandled base atom %r' % atomtype) # Skip unknown atoms try: file.seek(atomsize - 8, 1) except IOError: return 0 return atomsize