def getStorage(elid): """Return a tags.Storage object filled with the tags of the element with the given id.""" result = db.query( "SELECT tag_id, value_id FROM {p}tags WHERE element_id = ?", elid) storage = tagsModule.Storage() for tagId, valueId in result: tag = tagsModule.get(tagId) storage.add(tag, value(tag, valueId)) return storage
def setUp(self): super().setUp() self.f1 = self.level.collect(TestUrl('test://band 1 - song')) self.f2 = self.level.collect(TestUrl('test://band 2 - a song')) self.f3 = self.level.collect(TestUrl('test://band 3 - another song')) self.f4 = self.level.collect(TestUrl('test://band 4 - no song')) self.fs = [self.f1, self.f2, self.f3, self.f4] containerTags = tags.Storage({tags.TITLE: ['Weird album']}) if self.real: # On real level createContainer does not work until we added the contents to the db self.level.addToDb(self.fs) self.c = self.level.createContainer(tags=containerTags, contents=[])
def setUp(self): super().setUp() self.subLevel = levels.Level('TEST', self.level) self.f1 = self.subLevel.collect(TestUrl('test://band 1 - song')) self.f2 = self.subLevel.collect(TestUrl('test://band 2 - a song')) self.f3 = self.subLevel.collect( TestUrl('test://band 3 - another song')) self.f4 = self.subLevel.collect(TestUrl('test://band 4 - no song')) self.fs = [self.f1, self.f2, self.f3, self.f4] self.containerTags = tags.Storage({tags.TITLE: ['Weird album']}) self.contentList = elements.ContentList.fromPairs([(10, self.f1), (12, self.f2)]) self.c = self.subLevel.createContainer(tags=self.containerTags, contents=self.contentList)
def finish(self): elems = [] for i, edit in enumerate(self.edits, start=1): url = urls.URL("audiocd://{0}.{1}{2}/{0}/{1}.flac".format( self.discid, i, os.path.abspath(config.options.audiocd.rippath))) elem = self.level.collect(url) elTags = tags.Storage() elTags[tags.TITLE] = [edit.getValue()] elTags[tags.ALBUM] = [self.titleEdit.getValue()] elTags[tags.get('artist')] = [self.artistEdit.getValue()] elTags[tags.get('date')] = [self.dateEdit.getValue()] diff = tags.TagStorageDifference(None, elTags) self.level.changeTags({elem: diff}) elems.append(elem) contTags = tags.Storage() contTags[tags.TITLE] = [self.titleEdit.getValue()] contTags[tags.ALBUM] = [self.titleEdit.getValue()] contTags[tags.get('date')] = [self.dateEdit.getValue()] contTags[tags.get('artist')] = [self.artistEdit.getValue()] cont = self.level.createContainer(contents=elems, type=ContainerType.Album, domain=domains.default(), tags=contTags) self.container = cont self.accept()
def readTags(self): """Load the tags from disk using pytaglib. Special tags (tracknumber, compilation, discnumber) are stored in the "specialTags" attribute. """ self.tags = tags.Storage() self.specialTags = collections.OrderedDict() try: self._taglibFile = taglib.File(self.url.path) except OSError: if self.url.extension in config.options.main.audio_extensions: logging.warning( __name__, 'TagLib failed to open "{}". Tags will be stored in database only' .format(self.url.path)) return self.length = self._taglibFile.length autoProcessingDone = False for key, values in self._taglibFile.tags.items(): key = key.lower() if key in self.specialTagNames: self.specialTags[key] = values elif key in config.options.tags.auto_delete: autoProcessingDone = True continue elif key in autoReplaceTags: autoProcessingDone = True key = autoReplaceTags[key] elif tags.isValidTagName(key): tag = tags.get(key) validValues = [] for string in values: try: validValues.append(tag.convertValue(string, crop=True)) except tags.TagValueError: logging.error( __name__, "Invalid value for tag '{}' found: {}".format( tag.name, string)) if len(validValues) > 0: self.tags.add(tag, *validValues) else: logging.error( __name__, "Invalid tag name '{}' found : {}".format(key, self.url)) if autoProcessingDone: self.saveTags()
def asMaestroTags(self, mapping=None): """Convert the MBTagStorage to an maestro.tags.Storage object. *mapping* may be a dict mapping strings to Maestro tag types. """ ret = tags.Storage() for key, values in self.items(): if mapping and key in mapping: if mapping[key] is None: continue else: tag = mapping[key] else: tag = tags.get(key) ret[tag] = [tag.convertValue(str(v)) for v in values] # converts AliasEntities to strings return ret
def runTest(self): if not self.real: self.assertEqual(self.level.elements, {}) # this is important on undo self.f1 = self.level.collect(TestUrl('test://band 1 - song')) # due to the fixed url->id mapping, these id is the same on real and editor self.assertEqual(self.f1.id, 1) self.assertIn(self.f1.id, self.level) self.f2 = self.level.collect(TestUrl('test://band 2 - a song')) self.f3 = self.level.collect(TestUrl('test://band 3 - another song')) self.f4 = self.level.collect(TestUrl('test://band 4 - no song')) containerTags = tags.Storage({tags.TITLE: ['Weird album']}) if self.real: # On real level createContainer does not work until we added the contents to the db self.assertEqual( 0, db.query("SELECT COUNT(*) FROM {}elements".format( db.prefix)).getSingle()) from maestro.core import reallevel self.assertEqual(reallevel._dbIds, set()) self.level.addToDb([self.f1, self.f2, self.f3, self.f4]) self.assertEqual( 4, db.query("SELECT COUNT(*) FROM {}elements".format( db.prefix)).getSingle()) self.assertEqual(reallevel._dbIds, set([1, 2, 3, 4])) # note that this id will be different when this test is run for editor and real level predictedId = db._nextId self.assertNotIn(predictedId, self.level) self.assertEqual(self.f1.parents, []) self.c = self.level.createContainer( tags=containerTags, contents=[self.f1, self.f2, self.f3]) self.assertEqual(self.c.id, predictedId) self.assertIn(predictedId, self.level) self.assertEqual( self.c.contents, elements.ContentList.fromList([self.f1.id, self.f2.id, self.f3.id])) self.assertEqual(self.f1.parents, [self.c.id]) self.checkUndo() self.checkRedo()
def performMerge(self): """The actual merge operation.""" self.level.stack.beginMacro(self.tr("Merge elements"), transaction=self.level is levels.real) containerTitle = self.titleEdit.text().strip() domain = self.domainBox.currentDomain() containerType = self.parentTypeBox.currentType() # Container tags & flags if self.commonTagsBox.isChecked(): containerTags = tags.findCommonTags(self.elements) containerFlags = list( set.intersection(*(set(el.flags) for el in self.elements))) else: containerTags = tags.Storage() containerFlags = [] if len(containerTitle) > 0: containerTags[tags.TITLE] = [containerTitle] if containerType == ContainerType.Album and tags.ALBUM not in containerTags: containerTags[tags.ALBUM] = [containerTitle] # Before creating anything, change tags of children (might raise filesystem errors) removePrefixes = hasattr( self, 'removePrefixBox') and self.removePrefixBox.isChecked() removeNumbers = hasattr( self, 'removeNumbersBox') and self.removeNumbersBox.isChecked() tagChanges = {} prefix = self.removeEdit.text() if removePrefixes else '' for element in self.elements: additions = removals = replacements = None if (removePrefixes or removeNumbers) and tags.TITLE in element.tags: removals, replacements = [], [] for value in element.tags[tags.TITLE]: if removePrefixes and value.startswith(prefix): newValue = value[len(prefix):] else: newValue = value if removeNumbers: number = utils.strings.numberFromPrefix(newValue)[1] if len(number) > 0: newValue = newValue[len(number):] if len(newValue) == 0: removals.append((tags.TITLE, value)) elif value != newValue: replacements.append((tags.TITLE, value, newValue)) if containerType == ContainerType.Album and tags.ALBUM not in element.tags: additions = [(tags.ALBUM, containerTitle)] tagChanges[element] = tags.TagDifference(additions=additions, removals=removals, replacements=replacements) if len(tagChanges) > 0: try: self.level.changeTags(tagChanges) except urls.TagWriteError as e: e.displayMessage() self.level.stack.abortMacro() self.reject() return if hasattr(self, 'changeTypeBox') and self.changeTypeBox.isChecked(): newType = self.childrenTypeBox.currentType() self.level.setTypes({ elem: newType for elem in self.elements if elem.isContainer and elem.type != newType }) contents = elements.ContentList.fromPairs( enumerate(self.elements, start=1)) container = self.level.createContainer(domain=domain, tags=containerTags, flags=containerFlags, contents=contents, type=containerType) if isinstance(self.parentNode, nodes.Wrapper): parent = self.parentNode.element insertPosition = self.wrappers[0].position insertIndex = parent.contents.positions.index(insertPosition) if self.positionCheckBox.isChecked(): self.level.removeContentsAuto( parent, [wrapper.position for wrapper in self.wrappers]) self.level.insertContentsAuto(parent, insertIndex, [container]) else: self.level.removeContents( parent, [wrapper.position for wrapper in self.wrappers]) self.level.insertContents(parent, [(insertPosition, container)]) else: from ..models import leveltreemodel if isinstance(self.model, leveltreemodel.LevelTreeModel): rows = [ self.parentNode.contents.index(wrapper) for wrapper in self.wrappers ] insertIndex = rows[0] for i in range(len(rows)): if rows[i] >= insertIndex: rows[i] += 1 # Insert first, otherwise EditorTreeModel might remove elements from the level. self.model.insertElements(self.parentNode, insertIndex, [container]) self.model.removeElements(self.parentNode, rows) # else: Nothing to do: Merge has been performed in the level and the model does not allow a merge self.level.stack.endMacro() if containerType != self.DefaultType: config.storage.gui.merge_dialog_container_type = containerType else: config.storage.gui.merge_dialog_container_type = None self.accept()
def readTags(self): self.tags = tags.Storage() artist, title = self.url.parsedUrl.path[1:].split( ' - ') # skip leading / self.tags.add(tags.TITLE, title) self.tags.add(tags.get('artist'), artist)
def readTags(self): self.tags, self.length = tags.Storage(), 0