mirror of
https://github.com/fergalmoran/picard.git
synced 2026-02-21 15:14:13 +00:00
Add Local Files cover art provider and its options
This commit is contained in:
@@ -164,12 +164,14 @@ class CoverArtProvider(object):
|
||||
self.error(traceback.format_exc())
|
||||
|
||||
|
||||
from picard.coverart.providers.local import CoverArtProviderLocal
|
||||
from picard.coverart.providers.caa import CoverArtProviderCaa
|
||||
from picard.coverart.providers.amazon import CoverArtProviderAmazon
|
||||
from picard.coverart.providers.whitelist import CoverArtProviderWhitelist
|
||||
from picard.coverart.providers.caa_release_group import CoverArtProviderCaaReleaseGroup
|
||||
|
||||
__providers = [
|
||||
CoverArtProviderLocal,
|
||||
CoverArtProviderCaa,
|
||||
CoverArtProviderAmazon,
|
||||
CoverArtProviderWhitelist,
|
||||
|
||||
99
picard/coverart/providers/local.py
Normal file
99
picard/coverart/providers/local.py
Normal file
@@ -0,0 +1,99 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Picard, the next-generation MusicBrainz tagger
|
||||
# Copyright (C) 2015 Laurent Monin
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
import os
|
||||
import re
|
||||
import traceback
|
||||
from PyQt4 import QtCore, QtGui
|
||||
from picard import config, log
|
||||
from picard.coverart.providers import CoverArtProvider, ProviderOptions
|
||||
from picard.coverart.image import CoverArtImageFromFile
|
||||
from picard.coverart.utils import CAA_TYPES
|
||||
from picard.ui.ui_provider_options_local import Ui_LocalOptions
|
||||
|
||||
|
||||
class ProviderOptionsLocal(ProviderOptions):
|
||||
"""
|
||||
Options for Local Files cover art provider
|
||||
"""
|
||||
|
||||
_DEFAULT_LOCAL_COVER_ART_REGEX = '^(?:cover|folder|albumart)(.*)\.(?:jpe?g|png|gif|tiff?)$'
|
||||
|
||||
options = [
|
||||
config.TextOption("setting", "local_cover_regex",
|
||||
_DEFAULT_LOCAL_COVER_ART_REGEX),
|
||||
]
|
||||
|
||||
_options_ui = Ui_LocalOptions
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super(ProviderOptionsLocal, self).__init__(parent)
|
||||
self.init_regex_checker(self.ui.local_cover_regex_edit, self.ui.local_cover_regex_error)
|
||||
self.ui.local_cover_regex_default.clicked.connect(self.set_local_cover_regex_default)
|
||||
|
||||
def set_local_cover_regex_default(self):
|
||||
self.ui.local_cover_regex_edit.setText(self._DEFAULT_LOCAL_COVER_ART_REGEX)
|
||||
|
||||
def load(self):
|
||||
self.ui.local_cover_regex_edit.setText(config.setting["local_cover_regex"])
|
||||
|
||||
def save(self):
|
||||
config.setting["local_cover_regex"] = unicode(self.ui.local_cover_regex_edit.text())
|
||||
|
||||
|
||||
class CoverArtProviderLocal(CoverArtProvider):
|
||||
|
||||
"""Get cover art from local files"""
|
||||
|
||||
NAME = "Local"
|
||||
TITLE = N_(u"Local Files")
|
||||
OPTIONS = ProviderOptionsLocal
|
||||
|
||||
_types_split_re = re.compile('[^a-z0-9]', re.IGNORECASE)
|
||||
_known_types = set([t['name'] for t in CAA_TYPES])
|
||||
|
||||
def enabled(self):
|
||||
enabled = CoverArtProvider.enabled(self)
|
||||
return enabled and not self.coverart.front_image_found
|
||||
|
||||
def queue_images(self):
|
||||
_match_re = re.compile(config.setting['local_cover_regex'], re.IGNORECASE)
|
||||
dirs_done = {}
|
||||
|
||||
for file in self.album.iterfiles():
|
||||
current_dir = os.path.dirname(file.filename)
|
||||
if current_dir in dirs_done:
|
||||
continue
|
||||
dirs_done[current_dir] = True
|
||||
for root, dirs, files in os.walk(current_dir):
|
||||
for filename in files:
|
||||
m = _match_re.search(filename)
|
||||
if not m:
|
||||
continue
|
||||
filepath = os.path.join(current_dir, root, filename)
|
||||
if os.path.exists(filepath):
|
||||
types = self.get_types(m.group(1)) or [ u'front' ]
|
||||
self.queue_put(CoverArtImageFromFile(filepath,
|
||||
types=types,
|
||||
support_types=True))
|
||||
return CoverArtProvider.FINISHED
|
||||
|
||||
def get_types(self, string):
|
||||
found = set([x.lower() for x in self._types_split_re.split(string) if x])
|
||||
return list(found.intersection(self._known_types))
|
||||
@@ -47,6 +47,7 @@ class CoverOptionsPage(OptionsPage):
|
||||
('Amazon', True),
|
||||
('Whitelist', True),
|
||||
('CaaReleaseGroup', False),
|
||||
('Local', False),
|
||||
]),
|
||||
]
|
||||
|
||||
|
||||
67
picard/ui/ui_provider_options_local.py
Normal file
67
picard/ui/ui_provider_options_local.py
Normal file
@@ -0,0 +1,67 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Automatically generated - don't edit.
|
||||
# Use `python setup.py build_ui` to update it.
|
||||
|
||||
from PyQt4 import QtCore, QtGui
|
||||
|
||||
try:
|
||||
_fromUtf8 = QtCore.QString.fromUtf8
|
||||
except AttributeError:
|
||||
def _fromUtf8(s):
|
||||
return s
|
||||
|
||||
try:
|
||||
_encoding = QtGui.QApplication.UnicodeUTF8
|
||||
def _translate(context, text, disambig):
|
||||
return QtGui.QApplication.translate(context, text, disambig, _encoding)
|
||||
except AttributeError:
|
||||
def _translate(context, text, disambig):
|
||||
return QtGui.QApplication.translate(context, text, disambig)
|
||||
|
||||
class Ui_LocalOptions(object):
|
||||
def setupUi(self, LocalOptions):
|
||||
LocalOptions.setObjectName(_fromUtf8("LocalOptions"))
|
||||
LocalOptions.resize(472, 215)
|
||||
self.verticalLayout = QtGui.QVBoxLayout(LocalOptions)
|
||||
self.verticalLayout.setObjectName(_fromUtf8("verticalLayout"))
|
||||
self.local_cover_regex_label = QtGui.QLabel(LocalOptions)
|
||||
self.local_cover_regex_label.setObjectName(_fromUtf8("local_cover_regex_label"))
|
||||
self.verticalLayout.addWidget(self.local_cover_regex_label)
|
||||
self.local_cover_regex_edit = QtGui.QLineEdit(LocalOptions)
|
||||
self.local_cover_regex_edit.setObjectName(_fromUtf8("local_cover_regex_edit"))
|
||||
self.verticalLayout.addWidget(self.local_cover_regex_edit)
|
||||
self.horizontalLayout_2 = QtGui.QHBoxLayout()
|
||||
self.horizontalLayout_2.setObjectName(_fromUtf8("horizontalLayout_2"))
|
||||
self.local_cover_regex_error = QtGui.QLabel(LocalOptions)
|
||||
self.local_cover_regex_error.setText(_fromUtf8(""))
|
||||
self.local_cover_regex_error.setObjectName(_fromUtf8("local_cover_regex_error"))
|
||||
self.horizontalLayout_2.addWidget(self.local_cover_regex_error)
|
||||
self.local_cover_regex_default = QtGui.QPushButton(LocalOptions)
|
||||
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.local_cover_regex_default.sizePolicy().hasHeightForWidth())
|
||||
self.local_cover_regex_default.setSizePolicy(sizePolicy)
|
||||
self.local_cover_regex_default.setObjectName(_fromUtf8("local_cover_regex_default"))
|
||||
self.horizontalLayout_2.addWidget(self.local_cover_regex_default)
|
||||
self.verticalLayout.addLayout(self.horizontalLayout_2)
|
||||
self.note = QtGui.QLabel(LocalOptions)
|
||||
font = QtGui.QFont()
|
||||
font.setItalic(True)
|
||||
self.note.setFont(font)
|
||||
self.note.setWordWrap(True)
|
||||
self.note.setObjectName(_fromUtf8("note"))
|
||||
self.verticalLayout.addWidget(self.note)
|
||||
spacerItem = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding)
|
||||
self.verticalLayout.addItem(spacerItem)
|
||||
|
||||
self.retranslateUi(LocalOptions)
|
||||
QtCore.QMetaObject.connectSlotsByName(LocalOptions)
|
||||
|
||||
def retranslateUi(self, LocalOptions):
|
||||
LocalOptions.setWindowTitle(_("Form"))
|
||||
self.local_cover_regex_label.setText(_("Local cover art files match the following regular expression:"))
|
||||
self.local_cover_regex_default.setText(_("Default"))
|
||||
self.note.setText(_("First group in the regular expression, if any, will be used as type, ie. cover-back-spine.jpg will be set as types Back + Spine. If no type is found, it will default to Front type."))
|
||||
|
||||
83
ui/provider_options_local.ui
Normal file
83
ui/provider_options_local.ui
Normal file
@@ -0,0 +1,83 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>LocalOptions</class>
|
||||
<widget class="QWidget" name="LocalOptions">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>472</width>
|
||||
<height>215</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="local_cover_regex_label">
|
||||
<property name="text">
|
||||
<string>Local cover art files match the following regular expression:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="local_cover_regex_edit"/>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QLabel" name="local_cover_regex_error">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="local_cover_regex_default">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Default</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="note">
|
||||
<property name="font">
|
||||
<font>
|
||||
<italic>true</italic>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>First group in the regular expression, if any, will be used as type, ie. cover-back-spine.jpg will be set as types Back + Spine. If no type is found, it will default to Front type.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
Reference in New Issue
Block a user