def __init__(self, m, d, i): RanaModule.__init__(self, m, d, i) self.nodes = [] self.pos = 0 self.numNodes = 0 self.updateTime = 0 self.replayPeriod = 1 # second
def __init__(self, m, d, i): RanaModule.__init__(self, m, d, i) self.layers = {} self.threadLayers = {} self.currentStorageVersion = 1 self.maxDbFileSizeGibiBytes = 3.7 # maximum database file size (to avoid the FAT32 file size limitation) in GibiBytes self.maxTilesInQueue = 50 self.sqliteTileQueue = Queue.Queue(self.maxTilesInQueue) """if there are more tiles in the buffer than maxTilesInBuffer, the whole buffer will be processed at once (flushed) to avoid a potential memory leak """ self.processPerUpdate = 1 #how many tiles will be processed per update (updates should happen every 100ms) self.commitInterval = 5 # how often we commit to the database (only happens when there is something in the queue) self.lastCommit = time.time() self.dirty = set() # a set of connections, that have uncommitted data # locks # TODO: this lock might not be needed for python2.6+, # as their sqlite version should be thread safe self.lookupConnectionLock = threading.RLock() self._mapTiles = None self._mapLayers = None self.tileFolder = "/dev/null"
def __init__(self, *args, **kwargs): RanaModule.__init__(self, *args, **kwargs) self.nodes = [] self.pos = 0 self.numNodes = 0 self.updateTime = 0 self.replayPeriod = 1 # second
def __init__(self, m, d, i): RanaModule.__init__(self, m, d, i) self.defaultTheme = constants.DEFAULT_THEME_ID self.cantLoad = [] self.imageOrderList = [] # for cache trimming self.maxImages = 200 # default 200 self.images = {} self.currentTheme = self.defaultTheme self.themeList = [] # structure -> color_key:color_object self.defaultColors = {} # default color set self.colors = {} # main combined color set defaultThemeConfig = os.path.join( self.modrana.paths.getThemesFolderPath(), self.defaultTheme, 'theme.conf' ) # TODO: make themes GUI toolkit independent if gs.GUIString == "GTK": # load the default set of colors defaultColors = self.loadColorsFromFile(defaultThemeConfig) self.defaultColors = defaultColors self.colors = defaultColors.copy() self.colorInfoSubscribers = {} #color shortcuts self.buttonOutlineColor = (0, 0, 0, 1) self.buttonFillColor = (1, 1, 1, 1)
def __init__(self, m, d, i): RanaModule.__init__(self, m, d, i) self.loggingEnabled = False self.loggingPaused = False self.loggingStartTimestamp = None self.logInterval = 1 #loggin interval in seconds self.saveInterval = 10 #saving interval in seconds self.lastUpdateTimestamp = None self.lastCoords = None self.logName = None #name of the current log self.logFilename = None #name of the current log self.logPath = None #path to the current log self.currentTempLog = [] # primary and secondary AOWay objects for # persistent log storage during logging self.log1 = None self.log2 = None # timer ids self.updateLogTimerId = None self.saveLogTimerId = None # statistics self.maxSpeed = None self.avg1 = 0 self.avg2 = 0 self.avgSpeed = None self.distance = None self.toolsMenuDone = False self.category = 'logs' # trace self.traceColor = 'blue' self.lastTracePoint = None self.traceIndex = 0 self.pxpyIndex = deque()
def __init__(self, m, d, i): RanaModule.__init__(self, m, d, i) self.tt = 0 self.connected = False self.set('speed', None) self.set('metersPerSecSpeed', None) self.set('bearing', None) self.set('elevation', None) self.status = "Unknown" self._enabled = False self.provider = None self.startSignal = Signal() self.stopSignal = Signal() # check if the device handles location by itself if not self.modrana.dmod.handlesLocation(): method = self.modrana.dmod.getLocationType() if method == "qt_mobility": print(" @ location: using Qt Mobility") from . import qt_mobility self.provider = qt_mobility.QtMobility(self) elif method == "gpsd": # GPSD print(" @ location: using GPSD") from . import gps_daemon self.provider = gps_daemon.GPSD(self) # watch if debugging needs to be enabled self.modrana.watch("gpsDebugEnabled", self._debugCB, runNow=True)
def __init__(self, m, d, i): RanaModule.__init__(self, m, d, i) """ # we consider 2km/h as as stationary (to filter out the standard GPS drift while not moving) """ self.notMovingSpeed = 2 self._updateUnitTable()
def __init__(self, *args, **kwargs): RanaModule.__init__(self, *args, **kwargs) self.beforeDraw() self.ignoreNextClicks = 0 self.layers = {2: [], 0: []} self.dragAreas = [] self.dragScreen = None self.timedActionInProgress = None
def __init__(self, *args, **kwargs): RanaModule.__init__(self, *args, **kwargs) self.tempOnlinePOI = None # temporary slot for an uncommitted POI from online search # to which menu to return after the POI is stored # NOTE: False => unset, None => map screen self.menuNameAfterStorageComplete = False # connect to the POI database self._db = self.connect_to_database()
def __init__(self, *args, **kwargs): RanaModule.__init__(self, *args, **kwargs) self.workerThreads = [] self.drawOverlay = False self.workStartTimestamp = None self._connectingCondition = threading.Condition() # TODO: move to location ? self._initGPSCondition = threading.Condition()
def __init__(self, m, d, i): RanaModule.__init__(self, m, d, i) self.espaekProcess = None # this lock is used to make sure there is only one voice speaking at once self.voiceLock = threading.Lock() # default espeak string for manual editing self.defaultStrings = {"espeak": "espeak -v %language% -s 120 -a %volume% -m %qmessage%"} self.defaultProvider = "espeak"
def __init__(self, *args, **kwargs): RanaModule.__init__(self, *args, **kwargs) self.lines = ['hello', 'world'] self.oldLines = ['', ''] self.mode = 0 self.isGraphical = False self.modes = ['pos', 'gps', 'road', 'speed', 'maxSpeed', 'bearing', 'time'] self.unitString = ""
def __init__(self, m, d, i): RanaModule.__init__(self, m, d, i) self.tracklogs = {} # dictionary of all loaded tracklogs, path is the key #self.set('tracklogs', self.tracklogs) # now we make the list easily acessible to other modules self.cache = {} self.tracklogList = [] self.tracklogPathList = [] self.categoryList = []
def __init__(self, m, d, i): RanaModule.__init__(self, m, d, i) self.activePOI = None self.visiblePOI = [] self.listMenusDirty = False self.drawActivePOI = False self.expectPoint = False self.expectLock = threading.Lock()
def __init__(self, *args, **kwargs): RanaModule.__init__(self, *args, **kwargs) self.xyValid = False self.llValid = False self.needsEdgeFind = False # Scale is the number of display pixels per projected unit self.scale = tileSizePixels()
def __init__(self, *args, **kwargs): RanaModule.__init__(self, *args, **kwargs) self.points = [] if 0: # to test m = self.m.get("menu", None) if m: m.clearMenu('sketch', "set:menu:None") self.set("menu", "sketch")
def __init__(self, *args, **kwargs): RanaModule.__init__(self, *args, **kwargs) self.minimalSpeed = 2 # in kmh, we don't update the avg speed if the current speed is like this self.lastT = None self.maxSpeed = 0 self.avg1 = 0 self.avg2 = 0 # update stats once new position info is available self.modrana.watch('locationUpdated', self.updateStatsCB)
def __init__(self, *args, **kwargs): RanaModule.__init__(self, *args, **kwargs) self._layers = {} self._groups = {} self._tree = {} # TODO: actually support runtime layer reconfiguration # and use this signal self.layersChanged = Signal() # parse the config file self._parseConfig()
def __init__(self, *args, **kwargs): RanaModule.__init__(self, *args, **kwargs) self.espaekProcess = None # this lock is used to make sure there is only one voice speaking at once self.voiceLock = threading.Lock() # default espeak string for manual editing self.defaultStrings = { 'espeak': 'espeak -v %language% -s 120 -a %volume% -m %qmessage%' } self.defaultProvider = "espeak"
def __init__(self, *args, **kwargs): RanaModule.__init__(self, *args, **kwargs) self.localSearchResults = None # GLS results from onlineServices self.scroll = 0 self.list = None # processed results: (distance from pos, result, absolute index) self.maxIndex = 0 # based on the number of items in the list self.where = 'position' self.filters = {} # names of marker groups used for search results self._relatedMarkerGroups = ["addressResults", "wikipediaResults"]
def __init__(self, *args, **kwargs): RanaModule.__init__(self, *args, **kwargs) self.items = None self.routeProfileData = None self.nearestPoint = None self.nearestIndex = None self.distanceList = None # sorted distances from current position # colors self.widgetBackgroundColor = (0, 0, 1, 0.45) # transparent blue self.widgetTextColor = (1, 1, 1, 0.95) # slightly transparent white
def __init__(self, *args, **kwargs): RanaModule.__init__(self, *args, **kwargs) self.localSearchResults = None # GLS results from onlineServices self.scroll = 0 self.list = None # processed results: (distance from pos, result, absolute index) self.maxIndex = 0 # based on the number of items in the list self.where = 'position' self.menuWatchId = None self.filters = {} # names of marker groups used for search results self._relatedMarkerGroups = ["addressResults", "wikipediaResults"]
def __init__(self, *args, **kwargs): RanaModule.__init__(self, *args, **kwargs) self.beforeDraw() self.ignoreNextClicks = 0 self._layers = [[], [], []] self.dragAreas = [] self._scrollAreas = [] self.dragScreen = None self.timedActionInProgress = None self._lastSingleActionTimestamp = time.time() self._screenClickedNotify = None self._messages = None
def __init__(self, *args, **kwargs): RanaModule.__init__(self, *args, **kwargs) tileserver_callback_proxy.cb = self self.port = None self.server = None self.serverThread = None self._mapTiles = None if self.modrana.gui.needsLocalhostTileserver(): self.startServer(9009)
def __init__(self, *args, **kwargs): RanaModule.__init__(self, *args, **kwargs) # initial colors self.navigationBoxBackground = (0, 0, 1, 0.3) # very transparent blue self.navigationBoxText = (1, 1, 1, 1) # non-transparent white self.TBTWorker = None self.TBTWorkerEnabled = False self.goToInitialState() self.automaticRerouteCounter = 0 # counts consecutive automatic reroutes self.lastAutomaticRerouteTimestamp = time.time() # reroute even though the route was not yet reached (for special cases) self.overrideRouteReached = False
def __init__(self, *args, **kwargs): RanaModule.__init__(self, *args, **kwargs) self.beforeDraw() self.ignoreNextClicks = 0 self._layers = [[],[],[]] self.dragAreas = [] self._scrollAreas = [] self.dragScreen = None self.timedActionInProgress = None self._lastSingleActionTimestamp = time.time() self._screenClickedNotify = None self._messages = None
def __init__(self, *args, **kwargs): RanaModule.__init__(self, *args, **kwargs) self.versionString = "unknown version" currentVersionString = self.modrana.paths.version_string if currentVersionString is not None: # check version string validity self.versionString = currentVersionString self._dirPoint = None dirPoint = self.get("directionPointLatLon", None) if dirPoint: lat, lon = dirPoint self._dirPoint = Point(lat, lon)
def __init__(self, *args, **kwargs): RanaModule.__init__(self, *args, **kwargs) """according to documentation on: (http://wiki.maemo.org/PyMaemo/Python-osso_examples#Device_State), every display_blanking_pause() call pauses screenblank for 60 seconds, to make sure, we request it every 30 seconds""" self.pauseScreenBlankingEnabled = False #self.msScreenBlankPauseIntervalMs = 30000 self.msScreenBlankPauseIntervalMs = 1000 self.checkMethod = None self.checkConditions = False self.checkConditionsInterval = 5 # how often to check blanking conditions self.lastCheckConditions = time.time()
def __init__(self, *args, **kwargs): RanaModule.__init__(self, *args, **kwargs) self.versionString = "unknown version" currentVersionString = self.modrana.paths.getVersionString() if currentVersionString is not None: # check version string validity self.versionString = currentVersionString self._dirPoint = None dirPoint = self.get("directionPointLatLon", None) if dirPoint: lat, lon = dirPoint self._dirPoint = Point(lat, lon)
def __init__(self, m, d, i): RanaModule.__init__(self, m, d, i) self.images = [{}, {}] # the first dict contains normal image data, the second contains special tiles self.imagesLock = threading.RLock() self.maxImagesInMemory = 150 # to avoid a memory leak self.imagesTrimmingAmount = 30 # how many tiles to remove once the maximum is reached # so that trim does not run always run after adding a tile # TODO: analyse memory usage, # set appropriate value, # platform dependent value, # user configurable self.tileSide = 256 # by default, the tiles are squares, side=256 self.scalingInfo = (1, 15, 256) self.downloadRequestTimeout = 30 # in seconds specialTiles = [ ('tileDownloading', 'themes/default/tile_downloading.png'), ('tileDownloadFailed', 'themes/default/tile_download_failed.png'), ('tileLoading', 'themes/default/tile_loading.png'), ('tileWaitingForDownloadSlot', 'themes/default/tile_waiting_for_download_slot.png'), ('tileNetworkError', 'themes/default/tile_network_error.png') ] if gs.GUIString == "GTK": self.loadSpecialTiles(specialTiles) # load the special tiles to the special image cache self.loadingTile = self.images[1]['tileLoading'] self.downloadingTile = self.images[1]['tileDownloading'] self.waitingTile = self.images[1]['tileWaitingForDownloadSlot'] self.mapViewModule = None self._mapLayersModule = None # cache the map folder path self.mapFolderPath = self.modrana.paths.getMapFolderPath() print(" @ mapTiles: map folder path: %s" % self.mapFolderPath) self._storeTiles = None self.connPools = {} # connection pool dictionary self.cacheImageSurfaces = gs.GUIString == "GTK" self._filterTile = self._nop self._tileDownloaded = Signal() self._dlRequestQueue = six.moves.queue.Queue() self._downloader = None
def __init__(self, m, d, i): RanaModule.__init__(self, m, d, i) self.fullscreen = False """according to documentation on: (http://wiki.maemo.org/PyMaemo/Python-osso_examples#Device_State), every display_blanking_pause() call pauses screenblank for 60 seconds, to make sure, we request it every 30 seconds""" self.pauseScreenBlankingEnabled = False self.msScreenBlankPauseIntervalMs = 30000 self.checkMethod = None self.checkConditions = False self.checkConditionsInterval = 5 # how often to check blanking conditions self.lastCheckConditions = time.time()
def __init__(self, *args, **kwargs): RanaModule.__init__(self, *args, **kwargs) self.lineWidth = 7 #with of the line denoting GPX tracks self.distinctColors = [ 'black', 'blue', 'green', 'pink', 'cyan', 'red', 'gold', 'magenta', 'yellow' ] self.colorIndex = 0
def __init__(self, *args, **kwargs): RanaModule.__init__(self, *args, **kwargs) self.images = [{}, {}] # the first dict contains normal image data, the second contains special tiles self.imagesLock = threading.RLock() # we need to limit the size of the tile cache to avoid a memory leak memoryTileCacheSize = int(self.get("memoryTileCacheSize", constants.DEFAULT_MEMORY_TILE_CACHE_SIZE)) self.log.info("in memory tile cache size: %d", memoryTileCacheSize) self.maxImagesInMemory = memoryTileCacheSize self.imagesTrimmingAmount = constants.DEFAULT_MEMORY_TILE_CACHE_TRIM_SIZE # how many tiles to remove once the maximum is reached # so that trim does not run always run after adding a tile # TODO: analyse memory usage, # set appropriate value, # platform dependent value, # user configurable self.tileSide = 256 # by default, the tiles are squares, side=256 self.scalingInfo = (1, 15, 256) self.downloadRequestTimeout = 30 # in seconds specialTiles = [ ('tileDownloading', 'themes/default/tile_downloading.png'), ('tileDownloadFailed', 'themes/default/tile_download_failed.png'), ('tileLoading', 'themes/default/tile_loading.png'), ('tileWaitingForDownloadSlot', 'themes/default/tile_waiting_for_download_slot.png'), ('tileNetworkError', 'themes/default/tile_network_error.png') ] self.mapViewModule = None self._mapLayersModule = None # cache the map folder path self.mapFolderPath = self.modrana.paths.map_folder_path self.log.info("map folder path: %s" % self.mapFolderPath) self._storeTiles = None self.connPools = {} # connection pool dictionary self.cacheImageSurfaces = False # only GTK GUI used this self._filterTile = self._nop self._tileDownloaded = Signal() self._dlRequestQueue = Queue() self._downloader = None
def __init__(self, *args, **kwargs): RanaModule.__init__(self, *args, **kwargs) # initial colors self.navigationBoxBackground = (0, 0, 1, 0.3) # very transparent blue self.navigationBoxText = (1, 1, 1, 1) # non-transparent white self._tbt_worker_lock = RLock() self._tbt_worker_enabled = False self._go_to_initial_state() self._automatic_reroute_counter = 0 # counts consecutive automatic reroutes self._last_automatic_reroute_timestamp = time.time() # reroute even though the route was not yet reached (for special cases) self._override_route_reached = False # signals self.navigation_started = Signal() self.navigation_stopped = Signal() self.destination_reached = Signal() self.rerouting_triggered = Signal() self.current_step_changed = Signal()
def __init__(self, *args, **kwargs): RanaModule.__init__(self, *args, **kwargs) self.notificationText = "" self.timeout = 5000 self.position = 'middle' self.expirationTimestamp = time.time() self.draw = False self.redrawn = None self.wipOverlayEnabled = Signal() self._showWorkInProgressOverlay = False self.workStartTimestamp = None self._wipOverlayText = "" # this indicates if the notification about # background processing should be shown self._tasks = {} self._tasksLock = threading.RLock() ## for WiP overlay testing #self._tasks = { # "foo" : ("foo", None), # "bar" : ("bar", None), # "baz" : ("baz", None) #} # key is an unique task name (unique for each instance of a task) # and value is a (status, progress) tuple self.tasksChanged = Signal() # connect thread manager signals to task status changes threadMgr.threadStatusChanged.connect(self.setTaskStatus) threadMgr.threadProgressChanged.connect(self.setTaskProgress) threadMgr.threadRemoved.connect(self.removeTask) # also with GTK GUI, assure screen is redrawn properly # when WiP overlay changes if gs.GUIString == "GTK": self.wipOverlayEnabled.connect(self._doRefresh) self.tasksChanged.connect(self._doRefresh) # we handle notification only with the GTK GUI and when the device module does not # support showing them if not self.modrana.dmod.hasNotificationSupport(): self.modrana.notificationTriggered.connect(self._startCustomNotificationCB)
def __init__(self, *args, **kwargs): RanaModule.__init__(self, *args, **kwargs) self._tileDownloadRequests = set() self._tileDownloadRequestsLock = threading.RLock() self._checkPool = BatchSizeCheckPool() self._downloadPool = BatchTileDownloadPool() self.notificateOnce = True self.scroll = 0 self.x = None self.y = None self.z = None self.tiles = [] self.totalSize = 0 self.minZ = 0 self.midZ = 15 self.maxZ = MAX_ZOOMLEVEL
def __init__(self, *args, **kwargs): RanaModule.__init__(self, *args, **kwargs) self._tile_storage_management_lock = RLock() # this variable holds the currently selected primary store type # - this store type will be used to store all downloaded tiles # - this store type will be tried first when looking for tiles # in local storage, before checking other store types if the # tile is not found # - we have a watch on the store type key, so this variable will # be automatically updated if store type changes at runtime self._primary_tile_storage_type = constants.DEFAULT_TILE_STORAGE_TYPE self._stores = FlexibleDefaultDict(factory=self._get_existing_stores_for_layer) self._prevent_media_indexing = self.dmod.device_id == "android" # the tile loading debug log function is no-op by default, but can be # redirected to the normal debug log by setting the "tileLoadingDebug" # key to True self._llog = self._no_op self.modrana.watch('tileLoadingDebug', self._tile_loading_debug_changed_cb, runNow=True) self.modrana.watch('tileStorageType', self._primary_tile_storage_type_changed_cb, runNow=True)
def __init__(self, *args, **kwargs): RanaModule.__init__(self, *args, **kwargs) self._tile_storage_management_lock = RLock() # this variable holds the currently selected primary store type # - this store type will be used to store all downloaded tiles # - this store type will be tried first when looking for tiles # in local storage, before checking other store types if the # tile is not found # - we have a watch on the store type key, so this variable will # be automatically updated if store type changes at runtime self._primary_tile_storage_type = constants.DEFAULT_TILE_STORAGE_TYPE self._stores = FlexibleDefaultDict(factory=self._get_existing_stores_for_layer) self._prevent_media_indexing = self.dmod.getDeviceIDString() == "android" # the tile loading debug log function is no-op by default, but can be # redirected to the normal debug log by setting the "tileLoadingDebug" # key to True self._llog = self._no_op self.modrana.watch("tileLoadingDebug", self._tile_loading_debug_changed_cb, runNow=True) self.modrana.watch("tileStorageType", self._primary_tile_storage_type_changed_cb, runNow=True)
def __init__(self, *args, **kwargs): RanaModule.__init__(self, *args, **kwargs) self.layers = {} self.threadLayers = {} self.currentStorageVersion = 1 self.maxDbFileSizeGibiBytes = 3.7 # maximum database file size (to avoid the FAT32 file size limitation) in GibiBytes self.maxTilesInQueue = 50 self.sqliteTileQueue = Queue.Queue(self.maxTilesInQueue) # if there are more tiles in the buffer than maxTilesInBuffer, # the whole buffer will be processed at once (flushed) to avoid # a potential memory leak # how often we commit to the database (only happens when there is something in the queue) self.commitInterval = int( self.get("sqliteTileDatabaseCommitInterval", constants.DEFAULT_SQLITE_TILE_DATABASE_COMMIT_INTERVAL)) self.log.info("sqlite tile database commit interval: %d s", self.commitInterval) self.lastCommit = time.time() self.dirty = set() # a set of connections, that have uncommitted data # locks # TODO: this lock might not be needed for python2.6+, # as their sqlite version should be thread safe self.lookupConnectionLock = threading.RLock() # the tile loading debug log function is no-op by default, but can be # redirected to the normal debug log by setting the "tileLoadingDebug" # key to True self._loadingLog = self._noOp self.modrana.watch('tileLoadingDebug', self._tileLoadingDebugChangedCB, runNow=True) # device modules are loaded and initialized and configs are parsed before "normal" # modRana modules are initialized, so we can cache the map folder path in init self._mapFolderPath = self.modrana.paths.getMapFolderPath()
def __init__(self, *args, **kwargs): RanaModule.__init__(self, *args, **kwargs) self.loggingEnabled = False self.loggingPaused = False self.loggingStartTimestamp = 0 self.lastUpdateTimestamp = None self.lastCoords = None self.logName = None #name of the current log self.logFilename = None #name of the current log self.logPath = None #path to the current log self.currentLogGPX = None self.currentTempLog = [] # primary and secondary AOWay objects for # persistent log storage during logging self.log1 = None self.log2 = None # timer ids self.updateLogTimerId = None self.saveLogTimerId = None # signals self.tracklogUpdated = Signal() # statistics self.maxSpeed = 0 self.avg1 = 0 self.avg2 = 0 self.avgSpeed = 0 self.distance = 0 self.toolsMenuDone = False self.category = 'logs' # trace self.traceColor = 'blue' self.lastTracePoint = None self.traceIndex = 0 self.pxpyIndex = deque() self.lastX = 0 self.lastY = 0
def __init__(self, *args, **kwargs): RanaModule.__init__(self, *args, **kwargs) self.groups = {} # marker groups
def __init__(self, *args, **kwargs): RanaModule.__init__(self, *args, **kwargs) self.entryBoxVisible = False
def __init__(self, *args, **kwargs): RanaModule.__init__(self, *args, **kwargs) self.menus = None self.question = None self.yesAction = None self.noAction = None
def __init__(self, *args, **kwargs): RanaModule.__init__(self, *args, **kwargs)
def __init__(self, *args, **kwargs): RanaModule.__init__(self, *args, **kwargs) self.scrollDict = {} self.currentNumItems = 0 self.LTModule = None
def __init__(self, *args, **kwargs): RanaModule.__init__(self, *args, **kwargs) self.msLongPress = 400 self.subtypeId = None
def __init__(self, *args, **kwargs): RanaModule.__init__(self, *args, **kwargs) self.lastWaypoint = "(none)" self.lastWaypointAddTime = 0 self.messageLingerTime = 2
def __init__(self, *args, **kwargs): RanaModule.__init__(self, *args, **kwargs) self._themeChanged = Signal() self.modrana.watch('theme', self._themeChangedCB, runNow=True)
def __init__(self, *args, **kwargs): RanaModule.__init__(self, *args, **kwargs) self.internetConnectivityChanged = Signal()
def __init__(self, *args, **kwargs): RanaModule.__init__(self, *args, **kwargs) self.tracks = { } #dictionary of tracklists TODO: support tracklists with same filenames