def __init__(self): super(RootCommand, self).__init__() self.set(base_verbosity_level=0) self.add_argument( '-h', '--help', action='help', help='Show this message and exit') self.add_argument( '--version', action='version', version='Mopidy %s' % versioning.get_version()) self.add_argument( '-q', '--quiet', action='store_const', const=-1, dest='verbosity_level', help='less output (warning level)') self.add_argument( '-v', '--verbose', action='count', dest='verbosity_level', default=0, help='more output (repeat up to 3 times for even more)') self.add_argument( '--save-debug-log', action='store_true', dest='save_debug_log', help='save debug log to "./mopidy.log"') self.add_argument( '--config', action='store', dest='config_files', type=config_files_type, default=DEFAULT_CONFIG, metavar='FILES', help='config files to use, colon seperated, later files override') self.add_argument( '-o', '--option', action='append', dest='config_overrides', type=config_override_type, metavar='OPTIONS', help='`section/key=value` values to override config options')
def __init__(self): super(RootCommand, self).__init__() self.set(base_verbosity_level=0) self.add_argument("-h", "--help", action="help", help="Show this message and exit") self.add_argument("--version", action="version", version="Mopidy %s" % versioning.get_version()) self.add_argument( "-q", "--quiet", action="store_const", const=-1, dest="verbosity_level", help="less output (warning level)" ) self.add_argument( "-v", "--verbose", action="count", dest="verbosity_level", default=0, help="more output (debug level)" ) self.add_argument( "--save-debug-log", action="store_true", dest="save_debug_log", help='save debug log to "./mopidy.log"' ) self.add_argument( "--config", action="store", dest="config_files", type=config_files_type, default=b"$XDG_CONFIG_DIR/mopidy/mopidy.conf", metavar="FILES", help="config files to use, colon seperated, later files override", ) self.add_argument( "-o", "--option", action="append", dest="config_overrides", type=config_override_type, metavar="OPTIONS", help="`section/key=value` values to override config options", )
def parse_options(): parser = optparse.OptionParser(version="Mopidy %s" % versioning.get_version()) # NOTE First argument to add_option must be bytestrings on Python < 2.6.2 # See https://github.com/mopidy/mopidy/issues/302 for details parser.add_option( b"-q", "--quiet", action="store_const", const=0, dest="verbosity_level", help="less output (warning level)" ) parser.add_option( b"-v", "--verbose", action="count", default=1, dest="verbosity_level", help="more output (debug level)" ) return parser.parse_args(args=mopidy_args)[0]
def parse_options(): parser = optparse.OptionParser( version='Mopidy %s' % versioning.get_version()) parser.add_option( '-q', '--quiet', action='store_const', const=0, dest='verbosity_level', help='less output (warning level)') parser.add_option( '-v', '--verbose', action='count', default=1, dest='verbosity_level', help='more output (debug level)') return parser.parse_args(args=mopidy_args)[0]
def parse_options(): parser = optparse.OptionParser( version='Mopidy %s' % versioning.get_version()) # NOTE First argument to add_option must be bytestrings on Python < 2.6.2 # See https://github.com/mopidy/mopidy/issues/302 for details parser.add_option( b'-q', '--quiet', action='store_const', const=0, dest='verbosity_level', help='less output (warning level)') parser.add_option( b'-v', '--verbose', action='count', default=1, dest='verbosity_level', help='more output (debug level)') return parser.parse_args(args=mopidy_args)[0]
def parse_options(): parser = optparse.OptionParser(version='Mopidy %s' % versioning.get_version()) # Ugly extension of optparse type checking magic :/ optparse.Option.TYPES += ('config_override', ) optparse.Option.TYPE_CHECKER['config_override'] = check_config_override # NOTE First argument to add_option must be bytestrings on Python < 2.6.2 # See https://github.com/mopidy/mopidy/issues/302 for details parser.add_option(b'-q', '--quiet', action='store_const', const=0, dest='verbosity_level', help='less output (warning level)') parser.add_option(b'-v', '--verbose', action='count', default=1, dest='verbosity_level', help='more output (debug level)') parser.add_option(b'--save-debug-log', action='store_true', dest='save_debug_log', help='save debug log to "./mopidy.log"') parser.add_option(b'--show-config', action='callback', callback=show_config_callback, help='show current config') parser.add_option(b'--show-deps', action='callback', callback=deps.show_deps_optparse_callback, help='show dependencies and their versions') parser.add_option( b'--config', action='store', dest='config', default=b'$XDG_CONFIG_DIR/mopidy/mopidy.conf', help='config files to use, colon seperated, later files override') parser.add_option( b'-o', b'--option', action='append', dest='overrides', type='config_override', help='`section/key=value` values to override config options') return parser.parse_args(args=mopidy_args)[0]
def format_initial(extensions): config_dir = os.path.dirname(__file__) defaults = [read(os.path.join(config_dir, 'default.conf'))] defaults.extend(e.get_default_config() for e in extensions) raw_config = _load([], defaults, []) schemas = _schemas[:] schemas.extend(e.get_config_schema() for e in extensions) config, errors = _validate(raw_config, schemas) versions = ['Mopidy %s' % versioning.get_version()] for extension in sorted(extensions, key=lambda ext: ext.dist_name): versions.append('%s %s' % (extension.dist_name, extension.version)) description = _INITIAL_HELP.strip() % {'versions': '\n# '.join(versions)} return description + '\n\n' + _format(config, {}, schemas, False, True)
def parse_args(): parser = argparse.ArgumentParser() parser.add_argument('--version', action='version', version='Mopidy %s' % versioning.get_version()) parser.add_argument('-q', '--quiet', action='store_const', const=0, dest='verbosity_level', help='less output (warning level)') parser.add_argument('-v', '--verbose', action='count', default=1, dest='verbosity_level', help='more output (debug level)') return parser.parse_args(args=mopidy_args)
def parse_options(): parser = optparse.OptionParser(version='Mopidy %s' % versioning.get_version()) # NOTE First argument to add_option must be bytestrings on Python < 2.6.2 # See https://github.com/mopidy/mopidy/issues/302 for details parser.add_option(b'-q', '--quiet', action='store_const', const=0, dest='verbosity_level', help='less output (warning level)') parser.add_option(b'-v', '--verbose', action='count', default=1, dest='verbosity_level', help='more output (debug level)') return parser.parse_args(args=mopidy_args)[0]
def format_initial(extensions): config_dir = os.path.dirname(__file__) defaults = [read(os.path.join(config_dir, 'default.conf'))] defaults.extend(e.get_default_config() for e in extensions) raw_config = _load([], defaults, []) schemas = _schemas[:] schemas.extend(e.get_config_schema() for e in extensions) config, errors = _validate(raw_config, schemas) versions = ['Mopidy %s' % versioning.get_version()] for extension in sorted(extensions, key=lambda ext: ext.dist_name): versions.append('%s %s' % (extension.dist_name, extension.version)) header = _INITIAL_HELP.strip() % {'versions': '\n# '.join(versions)} formatted_config = _format( config=config, comments={}, schemas=schemas, display=False, disable=True).decode('utf-8') return header + '\n\n' + formatted_config
def parse_options(): parser = optparse.OptionParser( version='Mopidy %s' % versioning.get_version()) # Ugly extension of optparse type checking magic :/ optparse.Option.TYPES += ('config_override',) optparse.Option.TYPE_CHECKER['config_override'] = check_config_override # NOTE First argument to add_option must be bytestrings on Python < 2.6.2 # See https://github.com/mopidy/mopidy/issues/302 for details parser.add_option( b'-q', '--quiet', action='store_const', const=0, dest='verbosity_level', help='less output (warning level)') parser.add_option( b'-v', '--verbose', action='count', default=1, dest='verbosity_level', help='more output (debug level)') parser.add_option( b'--save-debug-log', action='store_true', dest='save_debug_log', help='save debug log to "./mopidy.log"') parser.add_option( b'--show-config', action='callback', callback=show_config_callback, help='show current config') parser.add_option( b'--show-deps', action='callback', callback=deps.show_deps_optparse_callback, help='show dependencies and their versions') parser.add_option( b'--config', action='store', dest='config', default=b'$XDG_CONFIG_DIR/mopidy/mopidy.conf', help='config files to use, colon seperated, later files override') parser.add_option( b'-o', b'--option', action='append', dest='overrides', type='config_override', help='`section/key=value` values to override config options') return parser.parse_args(args=mopidy_args)[0]
def parse_options(): parser = optparse.OptionParser( version='Mopidy %s' % versioning.get_version()) # NOTE First argument to add_option must be bytestrings on Python < 2.6.2 # See https://github.com/mopidy/mopidy/issues/302 for details parser.add_option( b'--help-gst', action='store_true', dest='help_gst', help='show GStreamer help options') parser.add_option( b'-i', '--interactive', action='store_true', dest='interactive', help='ask interactively for required settings which are missing') parser.add_option( b'-q', '--quiet', action='store_const', const=0, dest='verbosity_level', help='less output (warning level)') parser.add_option( b'-v', '--verbose', action='count', default=1, dest='verbosity_level', help='more output (debug level)') parser.add_option( b'--save-debug-log', action='store_true', dest='save_debug_log', help='save debug log to "./mopidy.log"') parser.add_option( b'--list-settings', action='callback', callback=settings_utils.list_settings_optparse_callback, help='list current settings') parser.add_option( b'--list-deps', action='callback', callback=deps.list_deps_optparse_callback, help='list dependencies and their versions') parser.add_option( b'--debug-thread', action='store_true', dest='debug_thread', help='run background thread that dumps tracebacks on SIGUSR1') return parser.parse_args(args=mopidy_args)[0]
class SpotifySessionManager(process.BaseThread, PyspotifySessionManager): cache_location = None settings_location = None appkey_file = os.path.join(os.path.dirname(__file__), 'spotify_appkey.key') user_agent = 'Mopidy %s' % versioning.get_version() def __init__(self, config, audio, backend_ref): self.cache_location = config['spotify']['cache_dir'] self.settings_location = config['spotify']['cache_dir'] PyspotifySessionManager.__init__( self, config['spotify']['username'], config['spotify']['password'], proxy=config['proxy']['hostname'], proxy_username=config['proxy']['username'], proxy_password=config['proxy']['password']) process.BaseThread.__init__(self) self.name = 'SpotifyThread' self.audio = audio self.backend = None self.backend_ref = backend_ref self.bitrate = config['spotify']['bitrate'] self.connected = threading.Event() self.push_audio_data = True self.buffer_timestamp = 0 self.container_manager = None self.playlist_manager = None self._initial_data_receive_completed = False def run_inside_try(self): self.backend = self.backend_ref.proxy() self.connect() def logged_in(self, session, error): """Callback used by pyspotify""" if error: logger.error('Spotify login error: %s', error) return logger.info('Connected to Spotify') # To work with both pyspotify 1.9 and 1.10 if not hasattr(self, 'session'): self.session = session logger.debug('Preferred Spotify bitrate is %d kbps', self.bitrate) session.set_preferred_bitrate(BITRATES[self.bitrate]) self.container_manager = SpotifyContainerManager(self) self.playlist_manager = SpotifyPlaylistManager(self) self.container_manager.watch(session.playlist_container()) self.connected.set() def logged_out(self, session): """Callback used by pyspotify""" logger.info('Disconnected from Spotify') self.connected.clear() def metadata_updated(self, session): """Callback used by pyspotify""" logger.debug('Callback called: Metadata updated') def connection_error(self, session, error): """Callback used by pyspotify""" if error is None: logger.info('Spotify connection OK') else: logger.error('Spotify connection error: %s', error) if self.audio.state.get() == audio.PlaybackState.PLAYING: self.backend.playback.pause() def message_to_user(self, session, message): """Callback used by pyspotify""" logger.debug('User message: %s', message.strip()) def music_delivery(self, session, frames, frame_size, num_frames, sample_type, sample_rate, channels): """Callback used by pyspotify""" # pylint: disable = R0913 # Too many arguments (8/5) if not self.push_audio_data: return 0 assert sample_type == 0, 'Expects 16-bit signed integer samples' capabilites = """ audio/x-raw-int, endianness=(int)1234, channels=(int)%(channels)d, width=(int)16, depth=(int)16, signed=(boolean)true, rate=(int)%(sample_rate)d """ % { 'sample_rate': sample_rate, 'channels': channels, } duration = audio.calculate_duration(num_frames, sample_rate) buffer_ = audio.create_buffer(bytes(frames), capabilites=capabilites, timestamp=self.buffer_timestamp, duration=duration) self.buffer_timestamp += duration if self.audio.emit_data(buffer_).get(): return num_frames else: return 0 def play_token_lost(self, session): """Callback used by pyspotify""" logger.debug('Play token lost') self.backend.playback.pause() def log_message(self, session, data): """Callback used by pyspotify""" logger.debug('System message: %s' % data.strip()) if 'offline-mgr' in data and 'files unlocked' in data: # XXX This is a very very fragile and ugly hack, but we get no # proper event when libspotify is done with initial data loading. # We delay the expensive refresh of Mopidy's playlists until this # message arrives. This way, we avoid doing the refresh once for # every playlist or other change. This reduces the time from # startup until the Spotify backend is ready from 35s to 12s in one # test with clean Spotify cache. In cases with an outdated cache # the time improvements should be a lot greater. if not self._initial_data_receive_completed: self._initial_data_receive_completed = True self.refresh_playlists() def end_of_track(self, session): """Callback used by pyspotify""" logger.debug('End of data stream reached') self.audio.emit_end_of_stream() def refresh_playlists(self): """Refresh the playlists in the backend with data from Spotify""" if not self._initial_data_receive_completed: logger.debug('Still getting data; skipped refresh of playlists') return playlists = [] for spotify_playlist in self.session.playlist_container(): playlists.append( translator.to_mopidy_playlist(spotify_playlist, bitrate=self.bitrate, username=self.username)) playlists.append( translator.to_mopidy_playlist(self.session.starred(), bitrate=self.bitrate, username=self.username)) playlists = filter(None, playlists) self.backend.playlists.playlists = playlists logger.info('Loaded %d Spotify playlists', len(playlists)) BackendListener.send('playlists_loaded') def logout(self): """Log out from spotify""" logger.debug('Logging out from Spotify') # To work with both pyspotify 1.9 and 1.10 if getattr(self, 'session', None): self.session.logout()
def get_version(self): """Get version of the Mopidy core API""" return versioning.get_version()
#source_encoding = 'utf-8' # The master toctree document. master_doc = 'index' # General information about the project. project = 'Mopidy' copyright = '2010-2012, Stein Magnus Jodal and contributors' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The full version, including alpha/beta/rc tags. from mopidy.utils.versioning import get_version release = get_version() # The short X.Y version. version = '.'.join(release.split('.')[:2]) # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. #language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: #today = '' # Else, today_fmt is used as the format for a strftime call. #today_fmt = '%B %d, %Y' # List of documents that shouldn't be included in the build.
def config_override_type(value): try: section, remainder = value.split(b'/', 1) key, value = remainder.split(b'=', 1) return (section.strip(), key.strip(), value.strip()) except ValueError: raise argparse.ArgumentTypeError( '%s must have the format section/key=value' % value) parser = argparse.ArgumentParser() parser.add_argument('--version', action='version', version='Mopidy %s' % versioning.get_version()) parser.add_argument('-q', '--quiet', action='store_const', const=-1, dest='verbosity_level', help='less output (warning level)') parser.add_argument('-v', '--verbose', action='count', dest='verbosity_level', help='more output (debug level)') parser.add_argument('--save-debug-log', action='store_true', dest='save_debug_log', help='save debug log to "./mopidy.log"')
def test_version(self): self.assertEqual(self.core.version, versioning.get_version())
def main(): log.bootstrap_delayed_logging() logger.info('Starting Mopidy %s', versioning.get_version()) signal.signal(signal.SIGTERM, process.exit_handler) # Windows does not have signal.SIGUSR1 if hasattr(signal, 'SIGUSR1'): signal.signal(signal.SIGUSR1, pykka.debug.log_thread_tracebacks) try: registry = ext.Registry() root_cmd = commands.RootCommand() config_cmd = commands.ConfigCommand() deps_cmd = commands.DepsCommand() root_cmd.set(extension=None, registry=registry) root_cmd.add_child('config', config_cmd) root_cmd.add_child('deps', deps_cmd) installed_extensions = ext.load_extensions() for extension in installed_extensions: ext_cmd = extension.get_command() if ext_cmd: ext_cmd.set(extension=extension) root_cmd.add_child(extension.ext_name, ext_cmd) args = root_cmd.parse(mopidy_args) create_file_structures_and_config(args, installed_extensions) check_old_locations() config, config_errors = config_lib.load( args.config_files, installed_extensions, args.config_overrides) verbosity_level = args.base_verbosity_level if args.verbosity_level: verbosity_level += args.verbosity_level log.setup_logging(config, verbosity_level, args.save_debug_log) extensions = { 'validate': [], 'config': [], 'disabled': [], 'enabled': []} for extension in installed_extensions: if not ext.validate_extension(extension): config[extension.ext_name] = {'enabled': False} config_errors[extension.ext_name] = { 'enabled': 'extension disabled by self check.'} extensions['validate'].append(extension) elif not config[extension.ext_name]['enabled']: config[extension.ext_name] = {'enabled': False} config_errors[extension.ext_name] = { 'enabled': 'extension disabled by user config.'} extensions['disabled'].append(extension) elif config_errors.get(extension.ext_name): config[extension.ext_name]['enabled'] = False config_errors[extension.ext_name]['enabled'] = ( 'extension disabled due to config errors.') extensions['config'].append(extension) else: extensions['enabled'].append(extension) log_extension_info(installed_extensions, extensions['enabled']) # Config and deps commands are simply special cased for now. if args.command == config_cmd: return args.command.run( config, config_errors, installed_extensions) elif args.command == deps_cmd: return args.command.run() check_config_errors(config, config_errors, extensions) if not extensions['enabled']: logger.error('No extension enabled, exiting...') sys.exit(1) # Read-only config from here on, please. proxied_config = config_lib.Proxy(config) if args.extension and args.extension not in extensions['enabled']: logger.error( 'Unable to run command provided by disabled extension %s', args.extension.ext_name) return 1 for extension in extensions['enabled']: extension.setup(registry) # Anything that wants to exit after this point must use # mopidy.utils.process.exit_process as actors can have been started. try: return args.command.run(args, proxied_config) except NotImplementedError: print(root_cmd.format_help()) return 1 except KeyboardInterrupt: pass except Exception as ex: logger.exception(ex) raise
class SpotifySessionManager(process.BaseThread, PyspotifySessionManager): cache_location = settings.SPOTIFY_CACHE_PATH settings_location = cache_location appkey_file = os.path.join(os.path.dirname(__file__), 'spotify_appkey.key') user_agent = 'Mopidy %s' % versioning.get_version() def __init__(self, username, password, audio, backend_ref, proxy=None, proxy_username=None, proxy_password=None): PyspotifySessionManager.__init__( self, username, password, proxy=proxy, proxy_username=proxy_username, proxy_password=proxy_password) process.BaseThread.__init__(self) self.name = 'SpotifyThread' self.audio = audio self.backend = None self.backend_ref = backend_ref self.connected = threading.Event() self.session = None self.container_manager = None self.playlist_manager = None self._initial_data_receive_completed = False def run_inside_try(self): self.backend = self.backend_ref.proxy() self.connect() def logged_in(self, session, error): """Callback used by pyspotify""" if error: logger.error('Spotify login error: %s', error) return logger.info('Connected to Spotify') self.session = session logger.debug( 'Preferred Spotify bitrate is %s kbps', settings.SPOTIFY_BITRATE) self.session.set_preferred_bitrate(BITRATES[settings.SPOTIFY_BITRATE]) self.container_manager = SpotifyContainerManager(self) self.playlist_manager = SpotifyPlaylistManager(self) self.container_manager.watch(self.session.playlist_container()) self.connected.set() def logged_out(self, session): """Callback used by pyspotify""" logger.info('Disconnected from Spotify') def metadata_updated(self, session): """Callback used by pyspotify""" logger.debug('Callback called: Metadata updated') def connection_error(self, session, error): """Callback used by pyspotify""" if error is None: logger.info('Spotify connection OK') else: logger.error('Spotify connection error: %s', error) if self.audio.state.get() == audio.PlaybackState.PLAYING: self.backend.playback.pause() def message_to_user(self, session, message): """Callback used by pyspotify""" logger.debug('User message: %s', message.strip()) def music_delivery(self, session, frames, frame_size, num_frames, sample_type, sample_rate, channels): """Callback used by pyspotify""" # pylint: disable = R0913 # Too many arguments (8/5) assert sample_type == 0, 'Expects 16-bit signed integer samples' capabilites = """ audio/x-raw-int, endianness=(int)1234, channels=(int)%(channels)d, width=(int)16, depth=(int)16, signed=(boolean)true, rate=(int)%(sample_rate)d """ % { 'sample_rate': sample_rate, 'channels': channels, } buffer_ = gst.Buffer(bytes(frames)) buffer_.set_caps(gst.caps_from_string(capabilites)) if self.audio.emit_data(buffer_).get(): return num_frames else: return 0 def play_token_lost(self, session): """Callback used by pyspotify""" logger.debug('Play token lost') self.backend.playback.pause() def log_message(self, session, data): """Callback used by pyspotify""" logger.debug('System message: %s' % data.strip()) if 'offline-mgr' in data and 'files unlocked' in data: # XXX This is a very very fragile and ugly hack, but we get no # proper event when libspotify is done with initial data loading. # We delay the expensive refresh of Mopidy's playlists until this # message arrives. This way, we avoid doing the refresh once for # every playlist or other change. This reduces the time from # startup until the Spotify backend is ready from 35s to 12s in one # test with clean Spotify cache. In cases with an outdated cache # the time improvements should be a lot greater. self._initial_data_receive_completed = True self.refresh_playlists() def end_of_track(self, session): """Callback used by pyspotify""" logger.debug('End of data stream reached') self.audio.emit_end_of_stream() def refresh_playlists(self): """Refresh the playlists in the backend with data from Spotify""" if not self._initial_data_receive_completed: logger.debug('Still getting data; skipped refresh of playlists') return playlists = map( translator.to_mopidy_playlist, self.session.playlist_container()) playlists = filter(None, playlists) self.backend.playlists.playlists = playlists logger.info('Loaded %d Spotify playlist(s)', len(playlists)) BackendListener.send('playlists_loaded') def search(self, query, queue): """Search method used by Mopidy backend""" def callback(results, userdata=None): # TODO Include results from results.albums(), etc. too # TODO Consider launching a second search if results.total_tracks() # is larger than len(results.tracks()) tracks = [ translator.to_mopidy_track(t) for t in results.tracks()] queue.put(tracks) self.connected.wait() self.session.search( query, callback, track_count=100, album_count=0, artist_count=0) def logout(self): """Log out from spotify""" logger.debug('Logging out from Spotify') if self.session: self.session.logout()
#source_encoding = 'utf-8' # The master toctree document. master_doc = 'index' # General information about the project. project = 'Mopidy' copyright = '2009-2013, Stein Magnus Jodal and contributors' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The full version, including alpha/beta/rc tags. from mopidy.utils.versioning import get_version release = get_version() # The short X.Y version. version = '.'.join(release.split('.')[:2]) # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. #language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: #today = '' # Else, today_fmt is used as the format for a strftime call. #today_fmt = '%B %d, %Y' # List of documents that shouldn't be included in the build. #unused_docs = []
def get_version(self): return versioning.get_version()