示例#1
0
    def _loaded(self, task):
        """Load covers after search for elements has finished. If no search was necessary, *task* is None.
        """
        if task is not None:
            if not isinstance(task, search.SearchTask): # subclasses might submit over tasks
                return
            elids = task.criterion.result
            if len(elids):
                filterClause = " AND el.id IN ({})".format(db.csList(elids))
            else:
                self.display().setCovers([], {})
                return
        else:
            filterClause = " AND el.domain={}".format(self.domain.id)
    
        result = db.query("""
            SELECT el.id, st.data
            FROM {p}elements AS el
                JOIN {p}stickers AS st ON el.id = st.element_id
            WHERE st.type = 'COVER' {filter}
            """, filter=filterClause)
        coverPaths = {id: path for id, path in result}
        ids = list(coverPaths.keys())
        levels.real.collect(ids)
        if tags.isInDb("artist") and tags.isInDb("date"):
            sortValues = {}
            artistTag = tags.get("artist")
            dateTag = tags.get("date")
            for id in ids:
                el = levels.real[id]
                sortValues[id] = (el.tags[artistTag][0] if artistTag in el.tags else utils.PointAtInfinity(),
                                  el.tags[dateTag][0] if dateTag in el.tags else utils.PointAtInfinity())
            ids.sort(key=sortValues.get)

        self.display().setCovers(ids, coverPaths)
示例#2
0
 def doAction(self):
     from maestro.gui.tagwidgets import TagValuePropertiesWidget
     if len(self.tagIds) > 1:
         tagNames = [tags.get(tagId).name for tagId, valueId in self.tagIds]
         answer, ok = QtWidgets.QInputDialog.getItem(self.parent(), self.tr("Choose tag mode"),
                                                 self.tr('Tag:'), tagNames)
         if not ok:
             return
         else:
             tagName, valueId = self.tagIds[tagNames.index(answer)]
     else:
         tagName, valueId = self.tagIds[0]
     TagValuePropertiesWidget.showDialog(tags.get(tagName), valueId)
示例#3
0
 def doAction(self):
     from maestro.gui.tagwidgets import TagValuePropertiesWidget
     if len(self.tagIds) > 1:
         tagNames = [tags.get(tagId).name for tagId, valueId in self.tagIds]
         answer, ok = QtWidgets.QInputDialog.getItem(
             self.parent(), self.tr("Choose tag mode"), self.tr('Tag:'),
             tagNames)
         if not ok:
             return
         else:
             tagName, valueId = self.tagIds[tagNames.index(answer)]
     else:
         tagName, valueId = self.tagIds[0]
     TagValuePropertiesWidget.showDialog(tags.get(tagName), valueId)
示例#4
0
 def __init__(self, name, type, state):
     super().__init__(name, type, state)
     if state is None:
         state = {}
     if 'groupTags' in state:
         self.groupTags = [tags.get(t) for t in state['groupTags']]
     else:
         self.groupTags = [tags.get('album')]
     self.albumTag = self.groupTags[0] if len(self.groupTags) > 0 else None
     self.directoryMode = state.get('directoryMode', False)
     self.metaRegex = state.get('metaRegex', self.defaultMetaRegex)
     try:
         self.compilationFlag = flags.get(state['compilationFlag'])
     except (KeyError, ValueError):
         self.compilationFlag = None
示例#5
0
 def runTest(self):
     tagsToRemove = [tags.get(name) for name in ('artist','title','comment')]
     for tag in tagsToRemove:
         del self.file.tags[tag]
     self.file.saveTags()
     self.file.readTags()
     self.assertEqual(self.file.tags,{k:v for k,v in ORIGINAL_TAGS.items() if k not in tagsToRemove})
示例#6
0
 def tagDefinitionAction(self, s, loc, toks):
     macro = toks["tag"]
     ret = toks.copy()
     ret["exists"] = False
     ret["value"] = None
     if "levelDef" in toks:
         level = toks["levelDef"][0]
         if level > len(self.currentParents):
             ret["value"] = ""
             return ret
         pos,parent = self.currentParents[-level]
         if macro == "#":
             ret["value"] =  self.positionFormat.format(pos)
         else:
             elemTag = parent.tags
     else:
         elemTag = self.currentElem.tags
         if macro == "#":
             if len(self.currentParents) > 0:
                 ret["value"] = self.positionFormat.format(self.currentParents[0][0])
     if macro != "#":
         if tags.isInDb(macro.lower()):
             tag = tags.get(macro.lower())
             if tag in elemTag:
                 ret["value"] = ",".join(map(str, elemTag[tag])).translate(self.translation)
     ret["exists"] = (ret["value"] != None)
     if ret["value"] is None:
         ret["value"] = ""
     return ret
示例#7
0
 def fromString(self, value):
     """Read a value from the string *value* and store it in this option. The format of *value* depends
     on the type of the option, see ''export''."""
     if self.type == 'string':
         return value
     elif self.type == 'int':
         try:
             return int(value)
         except ValueError:
             logging.warning(
                 __name__,
                 "Invalid int in delegate configuration in storage file.")
             return None
     elif self.type == 'bool':
         return value == 'True'
     elif self.type == 'tag':
         if tags.isInDb(value):
             return tags.get(value)
     elif self.type == 'datapiece':
         if value == 'none':
             return None
         else:
             try:
                 return DataPiece.fromString(value)
             except ValueError:
                 logging.warning(
                     __name__,
                     "Invalid datapiece in delegate configuration in storage file."
                 )
                 return None
示例#8
0
def value(tagSpec, valueId):
    """Return the value from the tag *tagSpec* with id *valueId* or raise an EmptyResultException if
    that id does not exist. Date tags will be returned as FlexiDate.
    """
    tag = tagsModule.get(tagSpec)

    # Check cache
    if tag in _idToValue:
        value = _idToValue[tag].get(valueId)
        if value is not None:
            return value

    # Look up value
    values = list(getValues(tag, "id={}".format(valueId)))
    if len(values) > 0:
        value = values[0]
    else:
        raise KeyError("There is no value of tag '{}' for id {}".format(
            tag, valueId))

    # Store value in cache
    if tag.type != tagsModule.TYPE_TEXT:
        if tag not in _idToValue:
            _idToValue[tag] = {}
        _idToValue[tag][id] = value
    return value
示例#9
0
 def fromString(self,value):
     """Read a value from the string *value* and store it in this option. The format of *value* depends
     on the type of the option, see ''export''."""
     if self.type == 'string':
         return value
     elif self.type == 'int':
         try:
             return int(value)
         except ValueError:
             logging.warning(__name__, "Invalid int in delegate configuration in storage file.")
             return None
     elif self.type == 'bool':
         return value == 'True'
     elif self.type == 'tag':
         if tags.isInDb(value):
             return tags.get(value)
     elif self.type == 'datapiece':
         if value == 'none':
             return None
         else: 
             try:
                 return DataPiece.fromString(value)
             except ValueError:
                 logging.warning(__name__, "Invalid datapiece in delegate configuration in storage file.")
                 return None
示例#10
0
    def __init__(self, newtags):
        super().__init__()
        self.columns = [self.tr("Import"), self.tr("MusicBrainz Name"), self.tr("Maestro Tag")]
        self.setColumnCount(len(self.columns))
        self.verticalHeader().hide()
        self.setHorizontalHeaderLabels(self.columns)
        self.horizontalHeader().setSectionResizeMode(QtWidgets.QHeaderView.ResizeToContents)
        self.setRowCount(len(newtags))
        self.tagMapping = mbplugin.tagMap.copy()
        from ...gui.tagwidgets import TagTypeBox

        for row, tagname in enumerate(newtags):
            if tagname in self.tagMapping:
                tag = self.tagMapping[tagname]
            else:
                tag = tags.get(tagname)
            checkbox = QtWidgets.QTableWidgetItem()
            ttBox = TagTypeBox(tag, editable=True)
            ttBox.tagChanged.connect(self._handleTagTypeChanged)
            mbname = QtWidgets.QTableWidgetItem(tagname)
            self.setCellWidget(row, 2, ttBox)
            if tag is None:
                checkbox.setCheckState(Qt.Unchecked)
                ttBox.setEnabled(False)
                mbname.setFlags(mbname.flags() ^ Qt.ItemIsEnabled)
            else:
                checkbox.setCheckState(Qt.Checked)
                self.tagMapping[tagname] = tag
                mbname.setFlags(Qt.ItemIsEnabled)
            self.setItem(row, 0, checkbox)
            self.setItem(row, 1, mbname)

        self.cellChanged.connect(self._handleCellChange)
示例#11
0
 def tagDefinitionAction(self, s, loc, toks):
     macro = toks["tag"]
     ret = toks.copy()
     ret["exists"] = False
     ret["value"] = None
     if "levelDef" in toks:
         level = toks["levelDef"][0]
         if level > len(self.currentParents):
             ret["value"] = ""
             return ret
         pos, parent = self.currentParents[-level]
         if macro == "#":
             ret["value"] = self.positionFormat.format(pos)
         else:
             elemTag = parent.tags
     else:
         elemTag = self.currentElem.tags
         if macro == "#":
             if len(self.currentParents) > 0:
                 ret["value"] = self.positionFormat.format(
                     self.currentParents[0][0])
     if macro != "#":
         if tags.isInDb(macro.lower()):
             tag = tags.get(macro.lower())
             if tag in elemTag:
                 ret["value"] = ",".join(map(str, elemTag[tag])).translate(
                     self.translation)
     ret["exists"] = (ret["value"] != None)
     if ret["value"] is None:
         ret["value"] = ""
     return ret
示例#12
0
 def __init__(self, tagList=None, state=None):
     if tagList is None:
         assert state is not None
         tagList = [tags.get(name) for name in state]
     if any(tag.type != tags.TYPE_VARCHAR for tag in tagList):
         logging.warning(__name__, "Only tags of type varchar are permitted in the browser's layers.")
         tagList = {tag for tag in tagList if tag.type == tags.TYPE_VARCHAR}
     self.tagList = tagList
示例#13
0
 def sortFunction(wrapper):
     """Intelligent sort: sort albums by their date, everything else by name."""
     element = wrapper.element
     date = 0
     if element.isContainer() and element.type == elements.ContainerType.Album:
         dateTag = tags.get("date")
         if dateTag.type == tags.TYPE_DATE and dateTag in element.tags: 
             date = -element.tags[dateTag][0].toSql() # minus leads to descending sort
     return (date, element.getTitle(neverShowIds=True))
示例#14
0
    def updateCharts(self):
        """Create or update the charts."""
        innerWidget = QtWidgets.QWidget()
        self.innerLayout = QtWidgets.QGridLayout(innerWidget)
        if tags.get("genre").isInDb() and tags.get(
                "genre").type == tags.TYPE_VARCHAR:
            sizes, labels = self._filter(self.getGenres())
            self._addPie(self.tr("Genres"), 0, 0, sizes, labels, 4, 3)
            sizes, labels = self._filter(self.getFormats())
            self._addPie(self.tr("Formats"), 0, 1, sizes, labels, 3.2, 3)
            sizes, labels = self._filter(self.getContainerTypes())
            self._addPie(self.tr("Container types"), 1, 1, sizes, labels, 3.2,
                         3)

            heights, labels = zip(*self.getDates())
            self._addBars(self.tr("Dates"), 1, 0, heights, labels, 4, 4)

        self.scrollArea.setWidget(innerWidget)
示例#15
0
 def defaultTagList():
     """Return the default list of tags in a TagLayer."""
     tagList = [
         tags.get(name) for name in ('artist', 'composer', 'performer')
     ]
     return [
         tag for tag in tagList
         if tag.isInDb() and tag.type == tags.TYPE_VARCHAR
     ]
示例#16
0
def getIdsAndValues(tagSpec, whereClause='1', *args, **kwargs):
    tag = tagsModule.get(tagSpec)
    result = db.query(
        "SELECT id, value FROM {} WHERE tag_id = ? AND {}".format(
            tag.type.table, whereClause), tag.id, *args, **kwargs)
    if tag.type != tagsModule.TYPE_DATE:
        return (tuple(row) for row in result)
    else:
        return ((id, utils.FlexiDate.fromSql(date)) for id, date in result)
示例#17
0
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
示例#18
0
def getValues(tagSpec, whereClause='1', *args, **kwargs):
    tag = tagsModule.get(tagSpec)
    result = db.query(
        "SELECT value FROM {} WHERE tag_id = ? AND {}".format(
            tag.type.table, whereClause), tag.id, *args, **kwargs)
    if tag.type != tagsModule.TYPE_DATE:
        return result.getSingleColumn()
    else:
        return (utils.FlexiDate.fromSql(date)
                for date in result.getSingleColumn())
示例#19
0
    def __init__(self, discId, trackCount, level):
        super().__init__(mainwindow.mainWindow)
        self.setModal(True)
        self.level = level
        self.discid = discId
        topLayout = QtWidgets.QHBoxLayout()
        topLayout.addWidget(QtWidgets.QLabel(self.tr('Album title:')))
        self.titleEdit = tagwidgets.TagValueEditor(tags.TITLE)
        self.titleEdit.setValue('unknown album')
        topLayout.addWidget(self.titleEdit)
        midLayout = QtWidgets.QHBoxLayout()
        midLayout.addWidget(QtWidgets.QLabel(self.tr('Artist:')))
        self.artistEdit = tagwidgets.TagValueEditor(tags.get('artist'))
        self.artistEdit.setValue('unknown artist')
        midLayout.addWidget(self.artistEdit)
        midLayout.addStretch()
        midLayout.addWidget(QtWidgets.QLabel(self.tr('Date:')))
        self.dateEdit = tagwidgets.TagValueEditor(tags.get('date'))
        self.dateEdit.setValue(utils.FlexiDate(1900))
        midLayout.addWidget(self.dateEdit)
        layout = QtWidgets.QVBoxLayout()
        description = QtWidgets.QLabel(self.tr('The MusicBrainz database does not contain a release '
            'for this disc. Please fill the tags manually.'))
        description.setWordWrap(True)
        layout.addWidget(description)
        layout.addLayout(topLayout)
        layout.addLayout(midLayout)

        tableLayout = QtWidgets.QGridLayout()
        edits = []
        for i in range(1, trackCount+1):
            tableLayout.addWidget(QtWidgets.QLabel(self.tr('Track {:2d}:').format(i)), i-1, 0)
            edits.append(tagwidgets.TagValueEditor(tags.TITLE))
            edits[-1].setValue('unknown title')
            tableLayout.addWidget(edits[-1], i-1, 1)
        layout.addLayout(tableLayout)
        box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
        box.accepted.connect(self.finish)
        box.rejected.connect(self.reject)
        layout.addWidget(box)
        self.setLayout(layout)
        self.edits = edits
示例#20
0
 def __init__(self, tagList=None, state=None):
     if tagList is None:
         assert state is not None
         tagList = [tags.get(name) for name in state]
     if any(tag.type != tags.TYPE_VARCHAR for tag in tagList):
         logging.warning(
             __name__,
             "Only tags of type varchar are permitted in the browser's layers."
         )
         tagList = {tag for tag in tagList if tag.type == tags.TYPE_VARCHAR}
     self.tagList = tagList
示例#21
0
 def fromString(string):
     """Construct a datapiece from a string. The string must either be one of the special datapiece
     identifiers (e.g. 'length') or something like 't:artist' to construct a datapiece containing a tag.
     """
     if string.startswith('t:'):
         return DataPiece(tags.get(string[2:], True))
     else: 
         for dataPiece in availableDataPieces():
             if dataPiece.tag is None and dataPiece.data == string:
                 return dataPiece
     raise ValueError("'{}' is not a valid datapiece export.".format(string))
示例#22
0
 def sortFunction(wrapper):
     """Intelligent sort: sort albums by their date, everything else by name."""
     element = wrapper.element
     date = 0
     if element.isContainer(
     ) and element.type == elements.ContainerType.Album:
         dateTag = tags.get("date")
         if dateTag.type == tags.TYPE_DATE and dateTag in element.tags:
             date = -element.tags[dateTag][0].toSql(
             )  # minus leads to descending sort
     return (date, element.getTitle(neverShowIds=True))
示例#23
0
 def fromString(string):
     """Construct a datapiece from a string. The string must either be one of the special datapiece
     identifiers (e.g. 'length') or something like 't:artist' to construct a datapiece containing a tag.
     """
     if string.startswith('t:'):
         return DataPiece(tags.get(string[2:], True))
     else:
         for dataPiece in availableDataPieces():
             if dataPiece.tag is None and dataPiece.data == string:
                 return dataPiece
     raise ValueError(
         "'{}' is not a valid datapiece export.".format(string))
示例#24
0
def init():
    BrowserDelegate.profileType = profiles.createProfileType(
        name='browser',
        title=translate('Delegates', 'Browser'),
        leftData=['t:composer', 't:artist', 't:performer'],
        rightData=['t:date', 't:conductor'],
        overwrite={'fitInTitleRowData': profiles.DataPiece(tags.get('date'))
                                            if tags.isInDb('date') else None},
        addOptions=[
            profiles.DelegateOption("showSortValues",
                translate("Delegates", "Display sort values instead of real values"),"bool",False)
        ]
    )
示例#25
0
def sortValue(tagSpec, valueId, valueIfNone=False):
    """Returns the sort value for the given tag value, or None if it is not set.
    
    If *valueIfNone=True*, the value itself is returned if no sort value is set."""
    tag = tagsModule.get(tagSpec)
    value, sortValue = db.query(
        "SELECT value, sort_value FROM {} WHERE tag_id = ? AND id = ?".format(
            tag.type.table), tag.id, valueId).getSingleRow()
    if sortValue is not None:
        return sortValue
    elif valueIfNone:
        return value
    else:
        return None
示例#26
0
 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()
示例#27
0
 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
示例#28
0
    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()
示例#29
0
 def check(self,values,redo=True):
     result = db.query("SELECT tagtype,title,icon,private,sort FROM {}tagids WHERE tagname='testtag'"
                       .format(db.prefix))
     if values is not None:
         dbValues = [v if not db.isNull(v) else None for v in result.getSingleRow()]
         dbValues[3] = bool(dbValues[3]) # private
         dbValues = tuple(dbValues)
                         
         self.assertEqual(dbValues,values)
         tag = tags.get("testtag")
         self.assertEqual(tag.type.name,values[0])
         self.assertEqual(tag.rawTitle,values[1])
         self.assertEqual(tag.iconPath,values[2])
         self.assertEqual(tag.private,values[3])
         self.assertEqual(tags.tagList.index(tag),values[4])
     else:
         self.assertRaises(db.sql.EmptyResultException,result.getSingleRow)
示例#30
0
 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
示例#31
0
 def getGenres(self):
     """Return sizes and labels for each wedge in the genre chart. The percentage of a wedge
     is its size divided by the sum of all sizes times 100."""
     tag = tags.get("genre")
     if not tag.isInDb() or tag.type != tags.TYPE_VARCHAR:
         return []
     result = db.query(
         """
         SELECT COUNT(*) AS count, v.value
         FROM {p}tags AS t
             JOIN {p}elements AS el ON t.element_id = el.id
             JOIN {p}values_varchar AS v ON t.tag_id=v.tag_id AND t.value_id = v.id
         WHERE el.file = 1 AND t.tag_id=?
         GROUP BY value_id
         ORDER BY count DESC
         """, tag.id)
     return list(result)
示例#32
0
def id(tagSpec, value, insert=False):
    """Return the id of the given value in the tag-table of tag *tagSpec*. If the value does not exist,
    raise an EmptyResultException, unless the optional parameter *insert* is set to True. In that case
    insert the value into the table and return its id.
    """
    tag = tagsModule.get(tagSpec)

    # Check cache
    if tag in _valueToId:
        id = _valueToId[tag].get(value)
        if id is not None:
            return id

    # Look up id
    if tag.type in (tagsModule.TYPE_VARCHAR,
                    tagsModule.TYPE_TEXT) and type == 'mysql':
        whereClause = "value COLLATE utf8_bin = ?"
    else:
        whereClause = "value = ?"
    args = [tag.sqlFormat(value)]

    ids = list(getIdsAndValues(tag, whereClause, *args))
    if len(ids) > 0:
        id = ids[0][0]
    elif insert:
        if tag.type == tagsModule.TYPE_VARCHAR:
            columns = 'tag_id, value, search_value'
            args = [tag.id, tag.sqlFormat(value), _makeSearchValue(value)]
        else:
            columns = 'tag_id, value'
            args = [tag.id, tag.sqlFormat(value)]
        result = db.query(
            "INSERT INTO {} ({}) VALUES ({})".format(
                tag.type.table, columns, ','.join(['?'] * len(args))), *args)
        id = result.insertId()
    else:
        raise KeyError("No value id for tag '{}' and value '{}'".format(
            tag, value))

    # Store id in cache
    if tag.type != tagsModule.TYPE_TEXT:
        if tag not in _valueToId:
            _valueToId[tag] = {}
        _valueToId[tag][value] = id
    return id
示例#33
0
    def check(self, values, redo=True):
        result = db.query(
            "SELECT tagtype,title,icon,private,sort FROM {}tagids WHERE tagname='testtag'"
            .format(db.prefix))
        if values is not None:
            dbValues = [
                v if not db.isNull(v) else None for v in result.getSingleRow()
            ]
            dbValues[3] = bool(dbValues[3])  # private
            dbValues = tuple(dbValues)

            self.assertEqual(dbValues, values)
            tag = tags.get("testtag")
            self.assertEqual(tag.type.name, values[0])
            self.assertEqual(tag.rawTitle, values[1])
            self.assertEqual(tag.iconPath, values[2])
            self.assertEqual(tag.private, values[3])
            self.assertEqual(tags.tagList.index(tag), values[4])
        else:
            self.assertRaises(db.sql.EmptyResultException, result.getSingleRow)
示例#34
0
    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()
示例#35
0
 def getInfo(self, path):
     """Query MPD to get tags & length of the file at *path* (relative to this MPD instance).
     
     Since MPD connection is delegated to a subthread, this method might be slow.
     """
     with self.getClient() as client:
         info = client.listallinfo(path)[0]
         storage = tags.Storage()
         length = None
         for key, values in info.items():
             if key in ("file", "last-modified", "track"):
                 #  mpd delivers these but they aren't keys
                 continue
             if key == "time":
                 length = int(values)
                 continue
             tag = tags.get(key)
             if not isinstance(values, list):
                 values = [ values ]
             storage[tag] = [ tag.convertValue(value, crop=True) for value in values ]
         return storage, length
示例#36
0
import unittest, shutil, os

from maestro import application, utils, filebackends, database as db
from maestro.core import tags
    
PATH_BASE = os.path.join(os.getcwd(),os.path.dirname(__file__))
PATH_EMPTY = os.path.join(PATH_BASE,'realfiles/empty')
PATH_FULL = os.path.join(PATH_BASE,'realfiles/full')
PATH_INVALID = os.path.join(PATH_BASE,'realfiles/invalid')
PATH_TEST = os.path.join(PATH_BASE,'realfiles/test')

ORIGINAL_TAGS = {
tags.get("artist"): ["Martin","Michael"],
tags.get("title"): ['The "äöü#~♀" Song'],
tags.get("album"): ["Dullness"],
tags.get("date"): [utils.FlexiDate(2010),utils.FlexiDate(2000,12,24)],
tags.get("genre"): ["Dull","Gangsta"],
tags.get("comment"): ["äöü#~♀","..."]
}

TAGS_TO_WRITE = {
tags.get("artist"): ["You","Know","Who"],
tags.get("date"): [utils.FlexiDate(1900,12,24)],
tags.get("comment"): ["Stupid ümläütß"],
tags.get("conductor"): ["Absolutely","Nobody"]
}
ORIGINAL_POSITION = 1


def getFile(path):
    file = filebackends.getFile('file://'+path)
示例#37
0
 def toolTipText(self):
     from maestro.core import tags
     return '{} ({})'.format(' or '.join(self.getValues()),
                             '/'.join(tags.get(id).title for (id,_) in self.tagIds))
示例#38
0
 def runTest(self):
     self.file = getFile(self.test)
     tag = tags.get('artist')
     self.assertEqual(list(self.file.tags.keys()),[tag])
     self.assertTrue(len(self.file.tags[tag]) == 1)
     self.assertTrue(tag.isValid(self.file.tags[tag][0]))
示例#39
0
 def runTest(self):
     self.file.tags[tags.get('artist')] = ['Someone','Everyone']
     self.file.saveTags()
     self.file.readTags()
     self.assertEqual(self.file.tags,{tags.get('artist'): ['Someone','Everyone']})
示例#40
0
 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)
示例#41
0
    def loadFromDb(self, idList, level=None):
        """Load elements specified by *idList* from the database into *level* which defaults to the
        real level."""
        if level is None:
            level = self

        if len(idList) == 0:  # queries will fail otherwise
            return []

        csIdList = db.csList(idList)

        # bare elements
        result = db.query("""
                SELECT el.domain, el.id, el.file, el.type, f.url, f.length
                FROM {0}elements AS el LEFT JOIN {0}files AS f ON el.id = f.element_id
                WHERE el.id IN ({1})
                """.format(db.prefix, csIdList))
        for domainId, id, file, elementType, url, length in result:
            _dbIds.add(id)
            if file:
                level.elements[id] = elements.File(
                    domains.domainById(domainId),
                    level,
                    id,
                    url=URL(url),
                    length=length,
                    type=elements.ContainerType(elementType))
            else:
                level.elements[id] = elements.Container(
                    domains.domainById(domainId),
                    level,
                    id,
                    type=elements.ContainerType(elementType))

        # contents
        result = db.query("""
                SELECT el.id, c.position, c.element_id
                FROM {0}elements AS el JOIN {0}contents AS c ON el.id = c.container_id
                WHERE el.id IN ({1})
                ORDER BY position
                """.format(db.prefix, csIdList))
        for id, pos, contentId in result:
            level.elements[id].contents.insert(pos, contentId)

        # parents
        result = db.query("""
                SELECT el.id, c.container_id
                FROM {0}elements AS el JOIN {0}contents AS c ON el.id = c.element_id
                WHERE el.id IN ({1})
                """.format(db.prefix, csIdList))
        for id, contentId in result:
            level.elements[id].parents.append(contentId)

        # tags
        result = db.query("""
                SELECT el.id, t.tag_id, t.value_id
                FROM {0}elements AS el JOIN {0}tags AS t ON el.id = t.element_id
                WHERE el.id IN ({1})
                """.format(db.prefix, csIdList))
        for id, tagId, valueId in result:
            tag = tags.get(tagId)
            level.elements[id].tags.add(tag, db.tags.value(tag, valueId))

        # flags
        result = db.query("""
                SELECT el.id, f.flag_id
                FROM {0}elements AS el JOIN {0}flags AS f ON el.id = f.element_id
                WHERE el.id IN ({1})
                """.format(db.prefix, csIdList))
        for id, flagId in result:
            level.elements[id].flags.append(flags.get(flagId))

        # stickers
        result = db.query("""
                SELECT element_id, type, data
                FROM {}stickers
                WHERE element_id IN ({})
                ORDER BY element_id, type, sort
                """.format(db.prefix, csIdList))
        # This is a bit complicated because the stickers should be stored in tuples, not lists
        # Changing the lists would break undo/redo
        #TODO: is this really necessary?
        current = None
        buffer = []
        for (id, type, sticker) in result:
            if current is None:
                current = (id, type)
            elif current != (id, type):
                level.elements[current[0]].stickers[current[1]] = tuple(buffer)
                current = (id, type)
                buffer = []
            element = level.elements[id]
            if element.stickers is None:
                element.stickers = {}
            buffer.append(sticker)
        if current is not None:
            level.elements[current[0]].stickers[current[1]] = tuple(buffer)

        try:
            return [self.elements[id] for id in idList]
        except KeyError:  # probably some ids were not contained in the database
            raise levels.ElementGetError(
                self, [id for id in idList if id not in self])
示例#42
0
 def defaultTagList():
     """Return the default list of tags in a TagLayer."""
     tagList = [tags.get(name) for name in ('artist', 'composer', 'performer')]
     return [tag for tag in tagList if tag.isInDb() and tag.type == tags.TYPE_VARCHAR]
示例#43
0
 def loadFromDb(self, idList, level=None):
     """Load elements specified by *idList* from the database into *level* which defaults to the
     real level."""
     if level is None:
         level = self
         
     if len(idList) == 0: # queries will fail otherwise
         return []
     
     csIdList = db.csList(idList)
     
     # bare elements
     result = db.query("""
             SELECT el.domain, el.id, el.file, el.type, f.url, f.length
             FROM {0}elements AS el LEFT JOIN {0}files AS f ON el.id = f.element_id
             WHERE el.id IN ({1})
             """.format(db.prefix, csIdList))
     for domainId, id, file, elementType, url, length in result:
         _dbIds.add(id)
         if file:
             level.elements[id] = elements.File(domains.domainById(domainId), level, id,
                                                url=URL(url), length=length,
                                                type=elements.ContainerType(elementType))
         else:
             level.elements[id] = elements.Container(domains.domainById(domainId), level, id,
                                                     type=elements.ContainerType(elementType))
             
     # contents
     result = db.query("""
             SELECT el.id, c.position, c.element_id
             FROM {0}elements AS el JOIN {0}contents AS c ON el.id = c.container_id
             WHERE el.id IN ({1})
             ORDER BY position
             """.format(db.prefix, csIdList))
     for id, pos, contentId in result:
         level.elements[id].contents.insert(pos, contentId)
         
     # parents
     result = db.query("""
             SELECT el.id, c.container_id
             FROM {0}elements AS el JOIN {0}contents AS c ON el.id = c.element_id
             WHERE el.id IN ({1})
             """.format(db.prefix, csIdList))
     for id, contentId in result:
         level.elements[id].parents.append(contentId)
         
     # tags
     result = db.query("""
             SELECT el.id, t.tag_id, t.value_id
             FROM {0}elements AS el JOIN {0}tags AS t ON el.id = t.element_id
             WHERE el.id IN ({1})
             """.format(db.prefix, csIdList))
     for id, tagId, valueId in result:
         tag = tags.get(tagId)
         level.elements[id].tags.add(tag, db.tags.value(tag, valueId))
         
     # flags
     result = db.query("""
             SELECT el.id, f.flag_id
             FROM {0}elements AS el JOIN {0}flags AS f ON el.id = f.element_id
             WHERE el.id IN ({1})
             """.format(db.prefix, csIdList))
     for id, flagId in result:
         level.elements[id].flags.append(flags.get(flagId))
         
     # stickers
     result = db.query("""
             SELECT element_id, type, data
             FROM {}stickers
             WHERE element_id IN ({})
             ORDER BY element_id, type, sort
             """.format(db.prefix, csIdList))
     # This is a bit complicated because the stickers should be stored in tuples, not lists
     # Changing the lists would break undo/redo
     #TODO: is this really necessary?
     current = None
     buffer = []
     for (id, type, sticker) in result:
         if current is None:
             current = (id, type)
         elif current != (id, type):
             level.elements[current[0]].stickers[current[1]] = tuple(buffer)
             current = (id, type)
             buffer = []
         element = level.elements[id]
         if element.stickers is None:
             element.stickers = {}
         buffer.append(sticker)
     if current is not None:
         level.elements[current[0]].stickers[current[1]] = tuple(buffer)
     
     try:
         return [self.elements[id] for id in idList]
     except KeyError: # probably some ids were not contained in the database
         raise levels.ElementGetError(self, [id for id in idList if id not in self])
示例#44
0
 def _guessHelper(self, files):
     files = list(files)
     domain = files[0].domain
     byKey = OrderedDict()
     existingParents = []
     pureDirMode = self.directoryMode and len(self.groupTags) == 0
     for element in files:
         self.orders[element] = self.currentOrder
         self.currentOrder += 1
         if len(element.parents) > 0:
             # there are already parents -> use the first one
             if element.parents[0] not in existingParents:
                 existingParents.append(element.parents[0])
         else:
             if pureDirMode:
                 key = os.path.dirname(element.url.path)
             else:
                 key = tuple( (tuple(element.tags[tag]) if tag in element.tags else None)
                                                        for tag in self.groupTags)
             if key not in byKey:
                 byKey[key] = []
             byKey[key].append(element)
     existing = self.level.collect(existingParents)
     for elem in existing:
         self.orders[elem] = self.currentOrder
         self.currentOrder += 1
     self.albums.extend(existing)
     self.toplevels.update(existing)
     for key, elements in byKey.items():
         flags = set()
         if self.compilationFlag is not None:
             for elem in elements:
                 if hasattr(elem, "specialTags") and "compilation" in elem.specialTags \
                                 and elem.specialTags["compilation"][0] not in ("0", ""):
                     flags.add(self.compilationFlag)
         if pureDirMode or (self.albumTag in elements[0].tags):
             def position(elem):
                 if hasattr(elem, "specialTags") and "tracknumber" in elem.specialTags:
                     return utils.parsePosition(elem.specialTags["tracknumber"][0])
                 return None
             elementsWithoutPos = { e for e in elements if position(e) is None }
             elementsWithPos = sorted(set(elements) - elementsWithoutPos, key = lambda e: position(e))
             children = {}
             for element in elementsWithPos:
                 if position(element) in children:
                     from maestro.gui.dialogs import warning
                     warning(self.tr("Error guessing albums"),
                             self.tr("position {} appears twice in {}").format(position(element), key))
                     self.level.removeElements([element])
                 else:
                     children[position(element)] = element.id
             firstFreePosition = position(elementsWithPos[-1])+1 if len(elementsWithPos) > 0 else 1
             for i, element in enumerate(elementsWithoutPos, start=firstFreePosition):
                 children[i] = element.id
             albumTags = tags.findCommonTags(elements)
             albumTags[tags.TITLE] = [key] if pureDirMode else elements[0].tags[self.albumTag]
             cType = ContainerType.Work if tags.get('composer') in albumTags else ContainerType.Album
             container = self.level.createContainer(domain=domain, tags=albumTags,
                                                    flags=list(flags), type=cType,
                                                    contents=ContentList.fromPairs(children.items()))
             self.orders[container] = self.orders[elements[0]]
             self.albums.append(container)
             self.toplevels.add(container)
         else:
             self.toplevels.update(elements)
示例#45
0
 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)
示例#46
0
def isHidden(tagSpec, valueId):
    """Returns True iff the given tag value is set hidden."""
    tag = tagsModule.get(tagSpec)
    return db.query(
        "SELECT hide FROM {} WHERE tag_id = ? AND id = ?".format(
            tag.type.table), tag.id, valueId).getSingle()