Ejemplo n.º 1
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
Ejemplo n.º 2
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
Ejemplo n.º 3
0
 def checkMPDChanges(self, changed):
     """Check for changes in the MPD subsystems listed in "changed" (as returned from idle).
     
     All changes will be handled accordingly. If """
     self.mpdStatus = self.client.status()
     if 'error' in self.mpdStatus:
         from ...gui.dialogs import warning
         warning('MPD error',
                 self.tr('MPD reported an error:\n{}').format(self.mpdStatus['error']))
         self.client.clearerror()
     if 'mixer' in changed:
         self.updateMixer()
         changed.remove('mixer')
     if 'playlist' in changed:
         self.updatePlaylist()
         changed.remove('playlist')
     if 'player' in changed:
         self.updatePlayer()
         changed.remove('player')
     if 'update' in changed:
         changed.remove('update')
     if 'output' in changed:
         self.updateOutputs()
         changed.remove('output')
     if len(changed) > 0:
         logging.warning(__name__, 'unhandled MPD changes: {}'.format(changed))
Ejemplo n.º 4
0
 def setIndex(self, index):
     """Undo/redo commands until there are *index* commands left that can be undone."""
     if self._inUndoRedo or self.isComposing():
         raise UndoStackError(
             "Cannot change index during undo/redo or while a macro is built."
             "")
     if index != self._index:
         if not 0 <= index <= len(self._commands):
             raise ValueError(
                 "Invalid index {} (there are {} commands on the stack).".
                 format(index, len(self._commands)))
         self._inUndoRedo = True
         try:
             if index < self._index:
                 for command in reversed(self._commands[index:self._index]):
                     command.undo()
             else:
                 for command in self._commands[self._index:index]:
                     command.redo()
         except Exception as e:
             logging.exception(__name__, "Exception during undo/redo.")
             self._clear()
             logging.warning(__name__, "Undostack cleared")
             return
         self._index = index
         self._emitQueuedEvents()
         self._inUndoRedo = False
         self._emitSignals()
Ejemplo n.º 5
0
 def setIndex(self, index):
     """Undo/redo commands until there are *index* commands left that can be undone."""
     if self._inUndoRedo or self.isComposing():
         raise UndoStackError("Cannot change index during undo/redo or while a macro is built.""")
     if index != self._index:
         if not 0 <= index <= len(self._commands):
             raise ValueError("Invalid index {} (there are {} commands on the stack)."
                              .format(index, len(self._commands)))
         self._inUndoRedo = True
         try:
             if index < self._index:
                 for command in reversed(self._commands[index:self._index]):
                     command.undo()
             else:
                 for command in self._commands[self._index:index]:
                     command.redo()
         except Exception as e:
             logging.exception(__name__, "Exception during undo/redo.")
             self._clear()
             logging.warning(__name__, "Undostack cleared")
             return
         self._index = index    
         self._emitQueuedEvents()
         self._inUndoRedo = False
         self._emitSignals()
Ejemplo n.º 6
0
    def __init__(self, state=None, **args):
        super().__init__(**args)
        layout = QtWidgets.QHBoxLayout(self)
        scene = DesktopScene(self)

        if state is not None:
            if 'items' in state:
                try:
                    levels.real.collect([
                        t[0] for t in state['items'] if isinstance(t[0], int)
                    ])
                    items = []
                    for t in state['items']:
                        if t[0] == 'stack':
                            item = StackItem.fromState(scene, t)
                        else:
                            item = CoverItem.fromState(scene, t)
                        scene.addItem(item)
                except Exception as e:
                    logging.warning(__name__,
                                    "Could not restore cover desk: " + str(e))
            if 'domain' in state:
                scene.domain = domains.domainById(state['domain'])

        self.view = QtWidgets.QGraphicsView(scene)
        self.view.setAcceptDrops(True)
        self.view.setAlignment(Qt.AlignLeft | Qt.AlignTop)
        self.view.setDragMode(QtWidgets.QGraphicsView.ScrollHandDrag)
        #self.view.scene().selectionChanged.connect(self.selectionChanged)
        layout.addWidget(self.view)
        self.view.ensureVisible(0, 0, 1, 1, 0, 0)
Ejemplo n.º 7
0
 def __init__(self, state=None, **args):
     super().__init__(**args)
     layout = QtWidgets.QHBoxLayout(self)
     scene = DesktopScene(self)
     
     if state is not None:
         if 'items' in state:
             try:
                 levels.real.collect([t[0] for t in state['items'] if isinstance(t[0], int)])
                 items = []
                 for t in state['items']:
                     if t[0] == 'stack':
                         item = StackItem.fromState(scene, t)
                     else: item = CoverItem.fromState(scene, t)
                     scene.addItem(item)
             except Exception as e:
                 logging.warning(__name__, "Could not restore cover desk: "+str(e))
         if 'domain' in state:
             scene.domain = domains.domainById(state['domain'])
             
     self.view = QtWidgets.QGraphicsView(scene)
     self.view.setAcceptDrops(True)
     self.view.setAlignment(Qt.AlignLeft | Qt.AlignTop)
     self.view.setDragMode(QtWidgets.QGraphicsView.ScrollHandDrag)
     #self.view.scene().selectionChanged.connect(self.selectionChanged)
     layout.addWidget(self.view)
     self.view.ensureVisible(0, 0, 1, 1, 0, 0)
Ejemplo n.º 8
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
Ejemplo n.º 9
0
 def removeWidgetClass(widgetClassId):
     widgetClass = WidgetClass.getWidgetClass(widgetClassId)
     if widgetClass is None:
         logging.warning(__name__, "Attempt to remove nonexistent widget class: {}".format(widgetClassId))
     else:
         WidgetClass.__registeredClasses.remove(widgetClass)
     if application.mainWindow is not None:
         application.mainWindow._widgetClassRemoved(widgetClass)
Ejemplo n.º 10
0
 def addWidgetClass(widgetClass=None, **kwargs):
     if widgetClass is None:
         widgetClass = WidgetClass(**kwargs)
     if widgetClass in WidgetClass.widgetClasses():
         logging.warning(__name__, "Attempt to add widget class twice: {}".format(widgetClass))
     else:
         WidgetClass.__registeredClasses.append(widgetClass)
     if application.mainWindow is not None:
         application.mainWindow._widgetClassAdded(widgetClass)
     return widgetClass
Ejemplo n.º 11
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
Ejemplo n.º 12
0
 def removeWidgetClass(widgetClassId):
     widgetClass = WidgetClass.getWidgetClass(widgetClassId)
     if widgetClass is None:
         logging.warning(
             __name__,
             "Attempt to remove nonexistent widget class: {}".format(
                 widgetClassId))
     else:
         WidgetClass.__registeredClasses.remove(widgetClass)
     if application.mainWindow is not None:
         application.mainWindow._widgetClassRemoved(widgetClass)
Ejemplo n.º 13
0
 def addWidgetClass(widgetClass=None, **kwargs):
     if widgetClass is None:
         widgetClass = WidgetClass(**kwargs)
     if widgetClass in WidgetClass.widgetClasses():
         logging.warning(
             __name__,
             "Attempt to add widget class twice: {}".format(widgetClass))
     else:
         WidgetClass.__registeredClasses.append(widgetClass)
     if application.mainWindow is not None:
         application.mainWindow._widgetClassAdded(widgetClass)
     return widgetClass
Ejemplo n.º 14
0
 def fallbackHash(self, path):
     """Compute the audio hash of a single file using ffmpeg to dump the audio.
     
     This method uses the "ffmpeg" binary ot extract the first 15 seconds in raw PCM format and
     then creates the MD5 hash of that data.
     """
     try:
         ans = subprocess.check_output(['ffmpeg', '-i', path, '-v', 'quiet',
                                        '-f', 's16le', '-t', '15', '-'])
         return 'hash:{}'.format(hashlib.md5(ans).hexdigest())
     except OSError:
         logging.warning(__name__, 'ffmpeg not installed - could not compute fallback audio hash')
     except subprocess.CalledProcessError:
         logging.warning(__name__, 'ffmpeg run failed')
Ejemplo n.º 15
0
 def dropEvent(self, event):
     mimeData = event.mimeData()
     if not Qt.CopyAction & event.possibleActions():
         return
     event.setDropAction(Qt.CopyAction)
     if mimeData.hasFormat(config.options.gui.mime):
         elements = [w.element for w in mimeData.toplevelWrappers()]
         level = mimeData.level
     else:
         logging.warning(__name__, "Invalid drop event (supports only {})"
                                   .format(", ".join(mimeData.formats())))
         return
     
     self.addElements(elements, event.scenePos())
     event.acceptProposedAction()
Ejemplo n.º 16
0
    def dropEvent(self, event):
        mimeData = event.mimeData()
        if not Qt.CopyAction & event.possibleActions():
            return
        event.setDropAction(Qt.CopyAction)
        if mimeData.hasFormat(config.options.gui.mime):
            elements = [w.element for w in mimeData.toplevelWrappers()]
            level = mimeData.level
        else:
            logging.warning(
                __name__, "Invalid drop event (supports only {})".format(
                    ", ".join(mimeData.formats())))
            return

        self.addElements(elements, event.scenePos())
        event.acceptProposedAction()
Ejemplo n.º 17
0
 def addPath(self, element):
     if element.isFile():
         if not element.inParentLevel():
             logging.warning(__name__, '{} not in parent level'.format(element))
             return
         oldPath = element.inParentLevel().url.path
         newPath = element.url.path
         if oldPath != newPath:
                 self.addCenter(delegates.TextItem(self.tr("From: {}").format(oldPath),
                                                   self.newPathStyleOld))
                 self.newRow()
                 self.addCenter(delegates.TextItem(self.tr("To: {}").format(newPath),
                                               self.newPathStyleNew))
         else:
             self.addCenter(delegates.TextItem(self.tr("Unchanged: {}").format(oldPath),
                                               self.unchangedStyle))
Ejemplo n.º 18
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()
Ejemplo n.º 19
0
 def redo(self):
     """Redo the next command/macro."""
     if self._inUndoRedo or self.isComposing():
         raise UndoStackError("Cannot redo a command during undo/redo or while a macro is built.""")
     if self._index == len(self._commands):
         raise UndoStackError("There is no command to redo.")
     self._inUndoRedo = True
     commandOrMacro = self._commands[self._index]
     try:
         commandOrMacro.redo()
     except Exception:
         logging.exception(__name__, "Exception during redo.")
         self._clear()
         logging.warning(__name__, "Undostack cleared")
     self._index += 1
     self._emitQueuedEvents()
     self._inUndoRedo = False
     self._emitSignals()
Ejemplo n.º 20
0
 def fallbackHash(self, path):
     """Compute the audio hash of a single file using ffmpeg to dump the audio.
     
     This method uses the "ffmpeg" binary ot extract the first 15 seconds in raw PCM format and
     then creates the MD5 hash of that data.
     """
     try:
         ans = subprocess.check_output([
             'ffmpeg', '-i', path, '-v', 'quiet', '-f', 's16le', '-t', '15',
             '-'
         ])
         return 'hash:{}'.format(hashlib.md5(ans).hexdigest())
     except OSError:
         logging.warning(
             __name__,
             'ffmpeg not installed - could not compute fallback audio hash')
     except subprocess.CalledProcessError:
         logging.warning(__name__, 'ffmpeg run failed')
Ejemplo n.º 21
0
 def redo(self):
     """Redo the next command/macro."""
     if self._inUndoRedo or self.isComposing():
         raise UndoStackError(
             "Cannot redo a command during undo/redo or while a macro is built."
             "")
     if self._index == len(self._commands):
         raise UndoStackError("There is no command to redo.")
     self._inUndoRedo = True
     commandOrMacro = self._commands[self._index]
     try:
         commandOrMacro.redo()
     except Exception:
         logging.exception(__name__, "Exception during redo.")
         self._clear()
         logging.warning(__name__, "Undostack cleared")
     self._index += 1
     self._emitQueuedEvents()
     self._inUndoRedo = False
     self._emitSignals()
Ejemplo n.º 22
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()
Ejemplo n.º 23
0
    def handleInitialScan(self):
        """Called when the initial filesystem walk is finished. Removes newfiles that have not been
        found anymore, adds newly found files, stores a list of missing committed files, and updates
        folder states if necessary.
        """
        # add newly found files to newfiles table (also creating folders entries)
        newfiles = []
        hashRequests = []
        for path, stamp in self.fsFiles.items():
            if path in self.files:
                file = self.files[path]
            else:
                url = urls.URL.fileURL(path)
                file = self.addFile(urls.URL.fileURL(path), store=False)
                newfiles.append(file)
            if file.hash is None or (file.id is None and file.verified < stamp):
                # for files with outdated verified that are in DB, we need to check if tags have changed
                # which is done later in the scan process
                hashRequests.append(HashRequest(priority=int(file.id is None), path=path))

        self.storeNewFiles(newfiles)
        # remove entries in newfiles that don't exist anymore
        self.removeFiles([file for path, file in self.files.items()
                           if file.id is None and path not in self.fsFiles])
        # store missing DB files for later usage
        self.missingDB = [file for path, file in self.files.items() if file.id and path not in self.fsFiles]
        if len(self.missingDB):
            logging.warning(__name__, '{} files in DB missing on filesystem'.format(len(self.missingDB)))
        # compute missing hashes, if necessary
        if len(hashRequests):
            logging.info(__name__, 'Hash value of {} files missing'.format(len(hashRequests)))
            self.scanState = ScanState.computingHashes
            self.hashThread.lastJobDone.clear()
            for elem in hashRequests:
                self.hashThread.jobQueue.put(elem)
            self.scanTimer.start(5000)  # check hash results every 5 seconds
        else:
            self.scanCheckModified()
Ejemplo n.º 24
0
 def addPath(self, element):
     if element.isFile():
         if not element.inParentLevel():
             logging.warning(__name__,
                             '{} not in parent level'.format(element))
             return
         oldPath = element.inParentLevel().url.path
         newPath = element.url.path
         if oldPath != newPath:
             self.addCenter(
                 delegates.TextItem(
                     self.tr("From: {}").format(oldPath),
                     self.newPathStyleOld))
             self.newRow()
             self.addCenter(
                 delegates.TextItem(
                     self.tr("To: {}").format(newPath),
                     self.newPathStyleNew))
         else:
             self.addCenter(
                 delegates.TextItem(
                     self.tr("Unchanged: {}").format(oldPath),
                     self.unchangedStyle))
Ejemplo n.º 25
0
 def dropEvent(self, event):
     mimeData = event.mimeData()
     
     if mimeData.hasFormat(config.options.gui.mime):
         allElements = (w.element for w in mimeData.wrappers())
         level = mimeData.level
     elif mimeData.hasUrls():
         allElements = levels.real.collect(url for url in event.mimeData().urls()
                        if url.isValid() and url.scheme() == 'file' and os.path.exists(url.toLocalFile()))
         level = levels.real
     else:
         logging.warning(__name__, "Invalid drop event (supports only {})"
                                   .format(", ".join(mimeData.formats())))
         return
     
     elements = []
     ids = set()
     for element in allElements:
         if element.id not in ids:
             ids.add(element.id)
             elements.append(element)
     
     self.setElements(level, elements)
     event.acceptProposedAction()
Ejemplo n.º 26
0
 def updatePlaylist(self):
     """Update the playlist if it has changed on the server.
     
     Currently, two special cases are detected: Insertion of consecutive songs,
     and removal of consecutive songs.
     
     In any other case, a complete playlist change is issued.
     """
     newVersion = int(self.mpdStatus["playlist"])
     if newVersion == self.playlistVersion:
         return
     logging.debug(__name__, "detected new plVersion: {}-->{}".format(self.playlistVersion, newVersion))
     
     if self.playlistVersion is None:
         # this happens only on initialization.
         self.mpdPlaylist = [x["file"] for x in self.client.playlistinfo()]
         self.playlistVersion = newVersion
         self.playlist.initFromUrls(self.makeUrls(self.mpdPlaylist))
         return
     plChanges = self.client.plchanges(self.playlistVersion)
     changedFiles = [ a["file"] for a in plChanges ]
     self.playlistVersion = newVersion
     newLength = int(self.mpdStatus["playlistlength"])
     # first special case: find out if only consecutive songs were removed 
     if newLength < len(self.mpdPlaylist):
         numRemoved = len(self.mpdPlaylist) - newLength
         oldSongsThere = self.mpdPlaylist[-len(plChanges):] if len(plChanges) > 0 else []
         if changedFiles == oldSongsThere:
             firstRemoved = newLength - len(plChanges)
             del self.mpdPlaylist[firstRemoved:firstRemoved+numRemoved]
             self.playlist.removeByOffset(firstRemoved, numRemoved, updateBackend='onundoredo')
             return
     # second special case: find out if a number of consecutive songs were inserted
     elif newLength > len(self.mpdPlaylist):
         numInserted = newLength - len(self.mpdPlaylist)
         numShifted = len(plChanges) - numInserted
         if numShifted == 0:
             newSongsThere = []
             oldSongsThere = []
         else:
             newSongsThere = plChanges
             oldSongsThere = self.mpdPlaylist[-numShifted:]
         if newSongsThere == oldSongsThere:
             firstInserted = len(self.mpdPlaylist) - numShifted
             paths = changedFiles[:numInserted]
             self.mpdPlaylist[firstInserted:firstInserted] = paths
             urls = self.makeUrls(paths)
             pos = int(plChanges[0]["pos"])
             self.playlist.insertUrlsAtOffset(pos, urls, updateBackend='onundoredo')
             return
     if len(plChanges) == 0:
         logging.warning(__name__, 'no changes???')
         return
     # other cases: update self.mpdPlaylist and perform a general playlist change
     reallyChange = False
     for pos, file in sorted((int(a["pos"]),a["file"]) for a in plChanges):
         if pos < len(self.mpdPlaylist):
             if self.mpdPlaylist[pos] != file:
                 reallyChange = True
             self.mpdPlaylist[pos] = file
         else:
             reallyChange = True
             self.mpdPlaylist.append(file)
     if reallyChange: # this might not happen e.g. when a stream is updated
         self.playlist.resetFromUrls(self.makeUrls(self.mpdPlaylist),
                                     updateBackend='onundoredo')   
Ejemplo n.º 27
0
 def __call__(self, path):
     if not maestro.utils.files.isMusicFile(path):
         return 'nomusic'
     try:
         data = subprocess.check_output(['fpcalc', path], stderr=subprocess.DEVNULL)
     except OSError:  # fpcalc not found, not executable etc.
         global _logOSError
         if _logOSError:
             _logOSError = False  # This error will always occur  - don't print it again.
         logging.warning(__name__, 'Error computing AcoustID fingerprint: fpcalc unavailable?')
         return self.fallbackHash(path)
     except subprocess.CalledProcessError:
         # fpcalc returned non-zero exit status
         logging.warning(__name__,
                         f'Error computing AcoustID fingerprint of {path}: fpcalc returned non-zero exit status')
         return self.fallbackHash(path)
     data = data.decode(sys.getfilesystemencoding())
     try:
         duration, fingerprint = (line.split("=", 1)[1] for line in data.splitlines() )
     except Exception as e:
         logging.warning(__name__, f'Error computing AcoustID fingerprint of {path}: {e}')
         return self.fallbackHash(path)
     import urllib.request, urllib.error, json
     try:
         req = urllib.request.urlopen(self.requestURL.format(self.apikey, duration, fingerprint))
     except (urllib.error.HTTPError, urllib.error.URLError) as e:
         logging.warning(__name__,
             'Error opening {}'.format(self.requestURL.format(self.apikey, duration, fingerprint)))
         return self.fallbackHash(path)
     ans = req.read().decode('utf-8')
     req.close()
     ans = json.loads(ans)
     if ans['status'] != 'ok':
         logging.warning(__name__, 'Error retrieving AcoustID fingerprint for "{}"'.format(path))
         return self.fallbackHash(path)
     results = ans['results']
     if len(results) == 0:
         logging.warning(__name__, 'No AcoustID fingerprint found for "{}"'.format(path))
         return self.fallbackHash(path)
     bestResult = max(results, key=lambda x: x['score'])
     if "recordings" in bestResult and len(bestResult["recordings"]) > 0:
         ans = "mbid:{}".format(bestResult["recordings"][0]["id"])
     else:
         ans = "acoustid:{}".format(bestResult["id"])
     return ans
Ejemplo n.º 28
0
 def __call__(self, path):
     if not maestro.utils.files.isMusicFile(path):
         return 'nomusic'
     try:
         data = subprocess.check_output(['fpcalc', path],
                                        stderr=subprocess.DEVNULL)
     except OSError:  # fpcalc not found, not executable etc.
         global _logOSError
         if _logOSError:
             _logOSError = False  # This error will always occur  - don't print it again.
         logging.warning(
             __name__,
             'Error computing AcoustID fingerprint: fpcalc unavailable?')
         return self.fallbackHash(path)
     except subprocess.CalledProcessError:
         # fpcalc returned non-zero exit status
         logging.warning(
             __name__,
             f'Error computing AcoustID fingerprint of {path}: fpcalc returned non-zero exit status'
         )
         return self.fallbackHash(path)
     data = data.decode(sys.getfilesystemencoding())
     try:
         duration, fingerprint = (line.split("=", 1)[1]
                                  for line in data.splitlines())
     except Exception as e:
         logging.warning(
             __name__,
             f'Error computing AcoustID fingerprint of {path}: {e}')
         return self.fallbackHash(path)
     import urllib.request, urllib.error, json
     try:
         req = urllib.request.urlopen(
             self.requestURL.format(self.apikey, duration, fingerprint))
     except (urllib.error.HTTPError, urllib.error.URLError) as e:
         logging.warning(
             __name__, 'Error opening {}'.format(
                 self.requestURL.format(self.apikey, duration,
                                        fingerprint)))
         return self.fallbackHash(path)
     ans = req.read().decode('utf-8')
     req.close()
     ans = json.loads(ans)
     if ans['status'] != 'ok':
         logging.warning(
             __name__,
             'Error retrieving AcoustID fingerprint for "{}"'.format(path))
         return self.fallbackHash(path)
     results = ans['results']
     if len(results) == 0:
         logging.warning(
             __name__,
             'No AcoustID fingerprint found for "{}"'.format(path))
         return self.fallbackHash(path)
     bestResult = max(results, key=lambda x: x['score'])
     if "recordings" in bestResult and len(bestResult["recordings"]) > 0:
         ans = "mbid:{}".format(bestResult["recordings"][0]["id"])
     else:
         ans = "acoustid:{}".format(bestResult["id"])
     return ans
Ejemplo n.º 29
0
 def logWarning(msg, xml):
     logging.warning(
         __name__,
         msg + '\n' + etree.tostring(xml, pretty_print=True, encoding=str))
Ejemplo n.º 30
0
 def logWarning(msg, xml):
     logging.warning(__name__, msg + '\n' + etree.tostring(xml, pretty_print=True, encoding=str))