From 5d44f0306bb8de87f4f0e01422e522ff213d960d Mon Sep 17 00:00:00 2001 From: Carlin Mangar Date: Tue, 20 Oct 2009 17:42:57 +1100 Subject: [PATCH] Allow limited bundling of plugins. After core-upgrade, merge this. Removes obsolete plugins. Merge installer-new AFTER. --- contrib/plugins/addrelease.py | 43 +++- contrib/plugins/coverartplus/__init__.py | 183 ++++++++++++++ contrib/plugins/firstalphachar.py | 18 -- contrib/plugins/initials.py | 12 - contrib/plugins/previewbar/__init__.py | 54 ++++ .../images/16x16/media-playback-start.png | Bin 0 -> 660 bytes .../images/16x16/media-playback-stop.png | Bin 0 -> 429 bytes .../images/32x32/media-playback-start.png | Bin 0 -> 1028 bytes .../images/32x32/media-playback-stop.png | Bin 0 -> 571 bytes contrib/plugins/previewbar/playerbox.py | 124 +++++++++ contrib/plugins/previewbar/resources.py | 235 ++++++++++++++++++ contrib/plugins/previewbar/resources.qrc | 8 + contrib/plugins/title_case_nx.py | 123 +++++++++ contrib/plugins/titlecase.py | 57 ----- setup.py | 42 +++- 15 files changed, 802 insertions(+), 97 deletions(-) create mode 100644 contrib/plugins/coverartplus/__init__.py delete mode 100644 contrib/plugins/firstalphachar.py delete mode 100644 contrib/plugins/initials.py create mode 100644 contrib/plugins/previewbar/__init__.py create mode 100644 contrib/plugins/previewbar/images/16x16/media-playback-start.png create mode 100644 contrib/plugins/previewbar/images/16x16/media-playback-stop.png create mode 100644 contrib/plugins/previewbar/images/32x32/media-playback-start.png create mode 100644 contrib/plugins/previewbar/images/32x32/media-playback-stop.png create mode 100644 contrib/plugins/previewbar/playerbox.py create mode 100644 contrib/plugins/previewbar/resources.py create mode 100644 contrib/plugins/previewbar/resources.qrc create mode 100644 contrib/plugins/title_case_nx.py delete mode 100644 contrib/plugins/titlecase.py diff --git a/contrib/plugins/addrelease.py b/contrib/plugins/addrelease.py index 5ccaacfb4..4dd4729d6 100644 --- a/contrib/plugins/addrelease.py +++ b/contrib/plugins/addrelease.py @@ -3,14 +3,17 @@ PLUGIN_NAME = u"Add Cluster As Release" PLUGIN_AUTHOR = u"Lukáš Lalinský" PLUGIN_DESCRIPTION = "" -PLUGIN_VERSION = "0.1" -PLUGIN_API_VERSIONS = ["0.9.0", "0.10"] +PLUGIN_VERSION = "0.2" +PLUGIN_API_VERSIONS = ["0.9.0", "0.10", "0.11", "0.12"] +# Hacked to popup an ugly dialog (to enable copy+pasting to non-IE browsers) for URLs longer than 2083 +# characters to get around a Windows path limitation. Probably shouldn't be used on other platforms. -from PyQt4 import QtCore +from PyQt4 import QtCore, QtGui, Qt from picard.cluster import Cluster from picard.util import webbrowser2, format_time from picard.ui.itemviews import BaseAction, register_cluster_action +import sys class AddClusterAsRelease(BaseAction): @@ -45,8 +48,40 @@ class AddClusterAsRelease(BaseAction): url += "&tr%d_artistedit=1" % i url += "&tr%d_artistname=%s" % (i, QtCore.QUrl.toPercentEncoding(file.metadata["artist"])) url += "&tracks=%d" % tracks - webbrowser2.open(url) + # Chad Wilson: This is a windows-specific hack, and probably shouldn't be done on other systems. I'm lazy for now. + # Carlin Mangar: I put in a condition for win32 + self.log.info(url) + if (len(url) <= 2048) and sys.platform =="win32": + webbrowser2.open(url) + else: + global w + w = AddClusterViewUrl() + w.addText(url) + w.show() +class AddClusterViewUrl(QtGui.QDialog): + def __init__(self, parent=None): + QtGui.QDialog.__init__(self, parent) + self.setWindowTitle(_("Add Cluster URL - Please copy and paste")) + self.doc = QtGui.QTextDocument(self) + self.textCursor = QtGui.QTextCursor(self.doc) + font = QtGui.QFont() + font.setFixedPitch(True) + font.setPointSize(8) + font.setWeight(QtGui.QFont.Normal) + font.setFamily("") + self.textFormat = QtGui.QTextCharFormat() + self.textFormat.setFont(font) + self.browser = QtGui.QTextBrowser(self) + self.browser.setDocument(self.doc) + vbox = QtGui.QHBoxLayout(self) + vbox.addWidget(self.browser) + + def addText(self, text): + self.textCursor.insertText(text, self.textFormat) + self.textCursor.insertBlock() + +#w = AddClusterViewUrl() register_cluster_action(AddClusterAsRelease()) diff --git a/contrib/plugins/coverartplus/__init__.py b/contrib/plugins/coverartplus/__init__.py new file mode 100644 index 000000000..520d6b132 --- /dev/null +++ b/contrib/plugins/coverartplus/__init__.py @@ -0,0 +1,183 @@ +""" +A small plugin to download cover art for any releseas that have a +CoverArtLink relation. + + +Changelog: + [2009-10-11] Added support for Amazon's new api and possibility for configuration + NXisGOD + + [2008-04-15] Refactored the code to be similar to the server code (hartzell, phw) + + [2008-03-10] Added CDBaby support (phw) + + [2007-09-06] Added Jamendo support (phw) + + [2007-04-24] Moved parsing code into here + Swapped to QUrl + Moved to a list of urls + + [2007-04-23] Moved it to use the bzr picard + Took the hack out + Added Amazon ASIN support + + [2007-04-23] Initial plugin, uses a hack that relies on Python being + installed and musicbrainz2 for the query. + +""" + +PLUGIN_NAME = 'Cover Art Plus' +PLUGIN_AUTHOR = 'Carlin Mangar, Oliver Charles, Philipp Wolfer, Lukas Lalinksy' +PLUGIN_DESCRIPTION = '''Downloads cover artwork for releases that have a +CoverArtLink. Now uses the new Amazon API to get cover art.''' +PLUGIN_VERSION = "0.6" +PLUGIN_API_VERSIONS = ["0.12"] + +from PyQt4.QtCore import QUrl +from picard.metadata import register_album_metadata_processor +from picard.util import partial, mimetype +from picard.webservice import * +from picard.tagger import Tagger +import re +import datetime + + +# +# data transliterated from the perl stuff used to find cover art for the +# musicbrainz server. +# See mb_server/cgi-bin/MusicBrainz/Server/CoverArt.pm +# hartzell --- Tue Apr 15 15:25:58 PDT 2008 +coverArtSites = [ + # CD-Baby + # tested with http://musicbrainz.org/release/1243cc17-b9f7-48bd-a536-b10d2013c938.html + { + 'regexp': 'http://cdbaby.com/cd/(\w)(\w)(\w*)', + 'imguri': 'http://cdbaby.name/$1/$2/$1$2$3.jpg', + }, + # Jamendo + # tested with http://musicbrainz.org/release/2fe63977-bda9-45da-8184-25a4e7af8da7.html + { + 'regexp': 'http:\/\/(?:www.)?jamendo.com\/(?:[a-z]+\/)?album\/([0-9]+)', + 'imguri': 'http://www.jamendo.com/get/album/id/album/artworkurl/redirect/$1/?artwork_size=0', + }, + ] + +_AMAZON_IMAGE_HOST = 'images.amazon.com' +_AMAZON_IMAGE_PATH = '/images/P/%s.01.LZZZZZZZ.jpg' +_AMAZON_IMAGE_PATH_SMALL = '/images/P/%s.01.MZZZZZZZ.jpg' +_AMAZON_IMAGE_PATH2 = '/images/P/%s.02.LZZZZZZZ.jpg' +_AMAZON_IMAGE_PATH2_SMALL = '/images/P/%s.02.MZZZZZZZ.jpg' + +AMAZON_API_LOCATOR = 'free.apisigning.com' +AMAZON_XML="/onca/xml" +ACCESS_KEY='AKIAJU7ZJ3PGRVJG6LSA' +AMAZON_SIGNATURE='' +_re_fixdate=re.compile(":") +_re_detecturl=re.compile(r"(?<=\)https?://(\w*:\w*@)?[-\w.]+(:\d+)?(/([\w/_.]*(\?\S+)?)?)?(?=)") + +def _coverart_downloaded(album, metadata, release, try_list, data, http, error): + try: + if error or len(data) < 1000: + if error: + album.log.error(str(http.errorString())) + coverart(album, metadata, release, try_list) + else: + mime = mimetype.get_from_data(data, "image/jpeg") + metadata.add_image(mime, data) + for track in album._new_tracks: + track.metadata.add_image(mime, data) + finally: + album._requests -= 1 + album._finalize_loading(None) + + +def coverart(album, metadata, release, try_list=None): + """ Gets the CDBaby URL from the metadata, and the attempts to + download the album art. """ + + # try_list will be None for the first call + if try_list is None: + try_list = [] + + try: + for relation_list in release.relation_list: + if relation_list.target_type == 'Url': + for relation in relation_list.relation: + # Search for cover art on special sites + for site in coverArtSites: + # + # this loop transliterated from the perl stuff used to find cover art for the + # musicbrainz server. + # See mb_server/cgi-bin/MusicBrainz/Server/CoverArt.pm + # hartzell --- Tue Apr 15 15:25:58 PDT 2008 + match = re.match(site['regexp'], relation.target) + if match != None: + imgURI = site['imguri'] + for i in range(1, len(match.groups())+1 ): + if match.group(i) != None: + imgURI = imgURI.replace('$' + str(i), match.group(i)) + _try_list_append_image_url(try_list, QUrl.fromEncoded(str(imgURI))) + + # Use the URL of a cover art link directly + if relation.type == 'CoverArtLink': + _try_list_append_image_url(try_list, QUrl.fromEncoded(str(relation.target))) + except AttributeError: + pass + + if metadata['asin']: + try_list.append({'host': _AMAZON_IMAGE_HOST, 'port': 80, + 'path': _AMAZON_IMAGE_PATH % metadata['asin'] + }) + try_list.append({'host': _AMAZON_IMAGE_HOST, 'port': 80, + 'path': _AMAZON_IMAGE_PATH_SMALL % metadata['asin'] + }) + try_list.append({'host': _AMAZON_IMAGE_HOST, 'port': 80, + 'path': _AMAZON_IMAGE_PATH2 % metadata['asin'] + }) + try_list.append({'host': _AMAZON_IMAGE_HOST, 'port': 80, + 'path': _AMAZON_IMAGE_PATH2_SMALL % metadata['asin'] + }) + + path = '%s?Service=AWSECommerceService&AWSAccessKeyId=%s&ItemId=%s&Operation=ItemLookup&ResponseGroup=Images&Timestamp=%s&Version=%s' \ + % ( AMAZON_XML, ACCESS_KEY, metadata['asin'], _re_fixdate.sub("%3A",datetime.datetime.now().isoformat()[:23]+"Z"),datetime.date.today().isoformat()) + album._requests += 1 + album.tagger.xmlws.get(AMAZON_API_LOCATOR, 80, path, + partial(_url_downloaded, album, metadata, release, try_list)) + + if len(try_list) > 0: + # We still have some items to try! + album._requests += 1 + album.tagger.xmlws.download( + try_list[0]['host'], try_list[0]['port'], try_list[0]['path'], + partial(_coverart_downloaded, album, metadata, release, try_list[1:]), + position=1) + + +def _parse_image_url(parsed_url): + path = parsed_url.path() + if parsed_url.hasQuery(): + path += '?' + location.encodedQuery() + return { + 'host': str(parsed_url.host()), + 'port': parsed_url.port(80), + 'path': str(path) + } + +def _try_list_append_image_url(try_list, parsed_url): + try_list.append(_parse_image_url(parsed_url)) + +def _url_downloaded(album, metadata, release, try_list, data, http, error): + album._requests -= 1 + if data: + try: + url = data.ItemLookupResponse[0].Items[0].Item[0].LargeImage[0].URL[0].text + try_list.insert(0, _parse_image_url(QUrl.fromEncoded(str(url)))) + except AttributeError: + try: + url = data.ItemLookupResponse[0].Items[0].Item[0].MediumImage[0].URL[0].text + try_list.insert(0, _parse_image_url(QUrl.fromEncoded(str(url)))) + except AttributeError: + pass + coverart(album, metadata, release, try_list) + +register_album_metadata_processor(coverart) diff --git a/contrib/plugins/firstalphachar.py b/contrib/plugins/firstalphachar.py deleted file mode 100644 index cf3740e9f..000000000 --- a/contrib/plugins/firstalphachar.py +++ /dev/null @@ -1,18 +0,0 @@ -PLUGIN_NAME = 'First alphabetic character function' -PLUGIN_AUTHOR = 'Philipp Wolfer' -PLUGIN_DESCRIPTION = 'Provides the tagger script function $firstalphachar(text, nonalpha=#).' -PLUGIN_VERSION = "0.1" -PLUGIN_API_VERSIONS = ["0.9.0", "0.10", "0.11", "0.12"] - -from picard.script import register_script_function - -def firstalphachar(parser, text, nonalpha="#"): - if len(text) == 0: - return nonalpha - firstchar = text[0] - if firstchar.isalpha(): - return firstchar.upper() - else: - return nonalpha - -register_script_function(firstalphachar) diff --git a/contrib/plugins/initials.py b/contrib/plugins/initials.py deleted file mode 100644 index 09d7b91d5..000000000 --- a/contrib/plugins/initials.py +++ /dev/null @@ -1,12 +0,0 @@ -PLUGIN_NAME = 'Initials' -PLUGIN_AUTHOR = 'Lukas Lalinsky' -PLUGIN_DESCRIPTION = 'Provides tagger script function $initials(text).' -PLUGIN_VERSION = "0.1" -PLUGIN_API_VERSIONS = ["0.9.0", "0.10"] - -from picard.script import register_script_function - -def initials(parser, text): - return "".join(a[:1] for a in text.split(" ") if a[:1].isalpha()) - -register_script_function(initials) diff --git a/contrib/plugins/previewbar/__init__.py b/contrib/plugins/previewbar/__init__.py new file mode 100644 index 000000000..8cbfb2558 --- /dev/null +++ b/contrib/plugins/previewbar/__init__.py @@ -0,0 +1,54 @@ +# -*- coding: utf-8 -*- +# +# Built in Player for Picard +# Copyright (C) 2007 Gary van der Merwe +# Copyright (C) 2009 Carlin Mangar +# +# 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. + + +PLUGIN_NAME = u"Preview Bar" +PLUGIN_AUTHOR = u"Carlin Mangar, Gary van der Merwe" +PLUGIN_DESCRIPTION = "Adds a cool music preview toolbar to Picard. Note however that you need Picard 0.12 and above to use this and you are limited\ + by the codecs you have installed. On linux this plugin depends on Gstreamer natively, \ + but there are different backends you can use.;)" +PLUGIN_VERSION = "0.3" +PLUGIN_API_VERSIONS = ["0.12.0"] + + +from PyQt4 import QtCore +from picard.ui.mainwindow import register_ui_init +from picard.plugins.previewbar.playerbox import PlayerBox +import picard.plugins.previewbar.resources +try: + from PyQt4.phonon import Phonon +except ImportError, e: + Phonon = None + phonon_import_error = e + +def create_player_box(mainwindow): + player_box = PlayerBox(mainwindow) + mainwindow.addToolBar(player_box) + player_box.connect(mainwindow, QtCore.SIGNAL("update_selection"), + player_box.updateSelection) + player_box.connect(mainwindow.tagger, QtCore.SIGNAL("file_save"), + player_box.file_save) + player_box.connect(mainwindow.tagger, QtCore.SIGNAL("file_saving_finished"), + player_box.AutoPlay) + player_box.connect(mainwindow.tagger, QtCore.SIGNAL("file_state_changed"), + player_box.file_changed) + +register_ui_init(create_player_box) + diff --git a/contrib/plugins/previewbar/images/16x16/media-playback-start.png b/contrib/plugins/previewbar/images/16x16/media-playback-start.png new file mode 100644 index 0000000000000000000000000000000000000000..a7de0feb09ff9e98d1eeaca81e9fbf6793ef2706 GIT binary patch literal 660 zcmV;F0&D$=P)H0h#)QuLQNI1SZtsXO8U^GGfgrxxh}+}VkxnAb?)YabMHAocX%9NxLrB| zzyY8MfO-Y6yO;d<*y~_0mS+_>8utCg%c)OS>fRtAV|%-`d2TEk2V8nL~zb!m)|pEA$SF2->jn-2hWj=^AH zPL5B%P2Stz^{Pr7#{fi4VAUxi)#JB!S3FMcd3k;2Es0696z@F%)>@ou3v24+*vND076Ixy33;9q2pAv`@ZPsg6f3A(Qi1k* zFkavM@*Aa-5I$9)h)6g*I{0=DB#I*EIzT(hNs`o~9IE3`*}+soD!;iA7_JPj`4{UQ XDQtDP+C_)X00000NkvXXu0mjf5}&Iv literal 0 HcmV?d00001 diff --git a/contrib/plugins/previewbar/images/32x32/media-playback-start.png b/contrib/plugins/previewbar/images/32x32/media-playback-start.png new file mode 100644 index 0000000000000000000000000000000000000000..66f32d89b59aed6480c4b3682ad57055828498ac GIT binary patch literal 1028 zcmV+f1pE7mP)pW=oQ8_HEoW$@{l6 z<6$?75H{PG#)J97oaVjxecpF|^PLCmX;1&L_!jfc02%;z<+1Akk)wS*9~ru4E-jfB z00)5BO@L4`*?OV9z2l|k=wq$R`9EgY*VhFA8-UssfCG;wPftyK##>qvPb@CZpNKR! zVPSr8P6#1Ua^&Fy3=SScL#Unx1_pG)(7U7(#{&Mk^!)t73VBjWoV|MW3s|-VqKc1$GmiVKs~G>_yf>H5e1G3sdz(p?c3pRAW@ctnM_8o= zqtR%Ik{CGW;EaQF4#r9jD5W5!fLHWjJ2qBU3y`Xa(b0GG(Xp|^!MeKd0`+yTB@&7F z$jC^|0|SJ^VE}+q5|(Yjb}ZPo1;=&Zc@BgqLP!ZH1x5soYw-DMz!}HF{DQPB3!GRw z91de`ZEe#i*D3+TVlmwQR0%HuU+zXs@SnC$9UHj6ze*NogxG{X@)Tvj0 z5JKd-y1G^>tzEqXh7JWlDhZMV2?@p+q>#9E^QOG~$wj-qzTv~OXUX34k)D{M6vXOrXzdr9xh(`*i{OjzkKqQ@y^c9EPyN#J@DmJ5dZ)T!+=r}nx;bv zg)3Jsd+GG=w-2VCesgee=njA!5mjaPwg7Zp2j?1o`te5b+nI07c)aD@`{yTa04S7; zS8ez901O@PzBgw3AMsy!Lg+ifKY}4*-0kpQZjveZH{;O0fl>=ZBQDG+vZ>VCp yE2R#gl$M2Z@g4mi+)_#@T`A?;)uMa)-|0_!Dtwg}>0a3Y0000u4^P)G>juCK3$14!cX>NBo> z0Ot=LZsQLD#K#soJ3A9V@PNya_iSs>P5fU2%;$55ZU_EEzMj8{zfVU~Fq_RJ97)7c zjPD|AzjHU#wpM1d*+KH707X&g=Gzh^;y5PK{>jzGcE_d-Em{K5z8=MHiydh0f>bf2VkY$;h8Sdh?Z3&@8!3hdm5a@2SQ9L4! zJ4i{G8CjMMtAWL0p{p;KL~%q!R|g~!u}0nYt4o5k>38O$16V8;!*-ymDw$1*B1n=k zlCQrI*qG_gbkj#*Hl?bnVE|=Wx|tCXlO`$dzGLM306Pu9%$Q6j!vM@oW=0f29Cv3> z5{}bdBU-opRBvjas;Xf%&@_$A3`vY9lWop__k{Ja6u2BSqiLF9JCNtO%%;40^YYl# zUt~5V&+~%-NB;*T6~MT!>2kT;8?RQY+q$lA`o^Dh(n0: + objects = objects[0] + + if isinstance(objects, Track): + if len(objects.linked_files) == 1: + new_selection = objects.linked_files[0] + + if isinstance(objects, File): + new_selection = objects + + if new_selection is not None and not new_selection==self.selection: + self.selection = new_selection + self.AutoPlay() + + def file_save(self): + if self.selection: + self.media_object.clear() + + def file_changed(self): + if self.selection and self.selection.state==File.REMOVED: + self.media_object.clear() + + def AutoPlay(self): + if self.auto_play_action.isChecked(): + if isinstance(self.selection, File) and self.selection.state!=File.PENDING: + source = Phonon.MediaSource(self.selection.filename) + self.media_object.setCurrentSource(source) + self.media_object.play() + + def onAutoPlayClicked(self): + if self.auto_play_action.isChecked() : + self.AutoPlay() + else: + self.media_object.stop() + self.updateAutoPlayIcon() + + def updateAutoPlayIcon(self): + if self.auto_play_action.isChecked(): + self.auto_play_action.setIcon(icontheme.lookup('media-playback-stop', + icontheme.ICON_SIZE_ALL)) + else: + self.auto_play_action.setIcon(icontheme.lookup('media-playback-start', + icontheme.ICON_SIZE_ALL)) diff --git a/contrib/plugins/previewbar/resources.py b/contrib/plugins/previewbar/resources.py new file mode 100644 index 000000000..f439eec13 --- /dev/null +++ b/contrib/plugins/previewbar/resources.py @@ -0,0 +1,235 @@ +# -*- coding: utf-8 -*- + +# Resource object code +# +# Created: Fri 2. Oct 21:15:21 2009 +# by: The Resource Compiler for PyQt (Qt v4.5.2) +# +# WARNING! All changes made in this file will be lost! + +from PyQt4 import QtCore + +qt_resource_data = "\ +\x00\x00\x02\x94\ +\x89\ +\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\ +\x00\x00\x10\x00\x00\x00\x10\x08\x06\x00\x00\x00\x1f\xf3\xff\x61\ +\x00\x00\x00\x06\x62\x4b\x47\x44\x00\xff\x00\xff\x00\xff\xa0\xbd\ +\xa7\x93\x00\x00\x00\x09\x70\x48\x59\x73\x00\x00\x0b\x13\x00\x00\ +\x0b\x13\x01\x00\x9a\x9c\x18\x00\x00\x00\x07\x74\x49\x4d\x45\x07\ +\xd5\x0c\x06\x11\x24\x21\xce\xd9\xad\x5e\x00\x00\x02\x21\x49\x44\ +\x41\x54\x38\xcb\x9d\x93\x4b\x6b\x13\x01\x14\x85\xcf\x3c\x32\xc9\ +\x24\x4d\x26\x31\x99\x69\x62\x13\x13\x5a\x49\x30\x23\xba\x4a\xd1\ +\xd4\x48\x52\x6c\x8a\x05\xc1\x67\x74\x27\x58\x10\xc1\x42\xb6\xdd\ +\xf9\x07\x5c\xf4\x17\x48\x97\x82\x2f\xba\x72\xa3\x88\x20\x2e\x0c\ +\x42\x4d\x15\xb1\x58\x6c\xa0\x11\x4a\xfa\xd0\xa4\x33\x4d\x32\x33\ +\xb9\x2e\xc4\xa6\x62\x29\xb1\x77\x75\xee\xe6\x83\x73\xef\x39\x40\ +\x77\x78\x1c\x60\xb8\x5d\x3a\x02\xc0\x01\xa0\x09\x80\x7a\x05\xb0\ +\xbb\x97\xfc\xf8\xd8\xeb\x60\x30\x98\x06\xe0\xeb\x15\xc0\xfc\x11\ +\x8a\x2c\x1f\x19\x3e\x95\xfa\xc6\x30\x4c\xc7\xb2\xcc\x2f\xe5\x0f\ +\x9f\x6e\xb6\x5a\xad\xcf\xb5\x5a\x4d\xef\xc9\x42\x34\x16\x93\xbc\ +\x3e\xa9\xf8\xec\xe9\x1c\xef\x91\x3c\xfe\x6a\x75\x65\xb2\xbf\x5f\ +\x19\xe9\x30\xf4\x66\x20\x34\x50\xaf\xd5\x6a\xb4\x2f\x20\xa9\xaa\ +\x92\x28\x3a\x8a\xd7\x0b\x37\xd8\x48\x64\x80\x9d\x38\x3f\xc1\xf5\ +\xb9\xdd\xe1\x8d\xf5\xf5\xdb\xa2\x53\x4c\x3a\x45\xd7\xbb\x64\xf2\ +\x58\x63\x79\xb9\xb2\x37\x60\x38\x95\x92\x38\x8e\x29\x5e\xbd\x72\ +\x8d\x05\x01\xae\x3e\x37\xd4\xa4\xca\xa5\x4f\xa7\x05\x97\x53\x4c\ +\xfc\xa8\xff\x9c\x34\x2d\x6b\x75\x68\x70\xa8\xb2\xb4\xb4\xd4\xfc\ +\x07\x90\xcb\x66\xa5\xb6\xd9\x2e\x5e\xba\x78\x99\xdd\xd2\xeb\x30\ +\x8c\x36\x0c\xa3\x0d\xbb\xc3\x8e\x78\x22\xc1\xe5\xf3\xe3\x0e\x22\ +\xba\x40\x30\x53\x89\x78\xfc\x7d\xe6\x4c\xa6\x51\x2a\x95\xcc\x9d\ +\xdf\x07\x64\x05\x0d\xad\x0e\x00\xd0\x74\x0d\x20\x02\x01\xb0\xf1\ +\x36\x78\x3d\x3e\xe8\xa4\x83\xc8\x62\xfc\x87\xfc\x86\xd7\x13\x90\ +\x78\x8e\x75\x03\x68\xee\x00\x14\x45\x46\xf5\xfb\x6f\x7f\xba\xbe\ +\x05\x9b\xcd\x8e\xc3\xc1\x30\x2c\xd3\xc4\xec\xec\x03\x6b\xf1\xeb\ +\xe2\x66\x2c\x16\xbd\xa3\x04\x42\x6f\x01\x5a\xbb\x3b\x35\x65\xfc\ +\x95\x3e\x59\x96\xc9\x26\x08\x00\x08\xd1\xf0\x20\x78\x9e\xc7\xe3\ +\x27\x8f\xac\x85\x8f\x0b\x46\x3c\x71\xf4\x5e\x66\x24\xfb\xb0\xd3\ +\xe9\xac\x16\x0a\x85\x16\xf6\x8a\xaf\x2c\x2b\x10\x04\x1b\x75\x88\ +\xf0\xf2\xd5\x0b\x2a\x97\xe7\x2d\xb7\xc7\xf3\x3c\x7b\x76\x74\x5a\ +\x10\xec\x95\x5c\x2e\xab\xed\xf5\xc6\x2e\x40\x09\x40\x14\xed\x34\ +\x33\x73\xdf\xd2\x74\x6d\x65\x34\x3b\x7a\x2b\x20\x87\xe6\x8f\xab\ +\xea\xc6\x7e\x41\xea\xde\x20\x20\x63\x7b\xbb\xb5\x79\x6e\x2c\x35\ +\x7d\x42\x3d\x39\x07\x30\x9b\x8a\xa2\x50\xcf\x51\x26\xa2\x30\x00\ +\x03\xc0\x1a\xc3\x30\xd6\x7f\xd7\x92\x88\xd8\x83\xd4\xf9\x17\x30\ +\x46\xc1\x1f\x41\xe0\x4e\x62\x00\x00\x00\x00\x49\x45\x4e\x44\xae\ +\x42\x60\x82\ +\x00\x00\x01\xad\ +\x89\ +\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\ +\x00\x00\x10\x00\x00\x00\x10\x08\x06\x00\x00\x00\x1f\xf3\xff\x61\ +\x00\x00\x00\x06\x62\x4b\x47\x44\x00\xff\x00\xff\x00\xff\xa0\xbd\ +\xa7\x93\x00\x00\x00\x09\x70\x48\x59\x73\x00\x00\x0b\x13\x00\x00\ +\x0b\x13\x01\x00\x9a\x9c\x18\x00\x00\x00\x07\x74\x49\x4d\x45\x07\ +\xd5\x0c\x06\x11\x28\x2e\xf2\xd3\xff\xc3\x00\x00\x01\x3a\x49\x44\ +\x41\x54\x38\xcb\xcd\x92\x5f\x4a\x03\x31\x10\x87\xbf\xec\xa4\xaf\ +\x16\x0a\x66\x3c\x80\x58\xf0\x14\x22\x1e\x42\xc4\x4b\x08\xe2\x89\ +\x44\xbc\x82\x88\xd7\x10\x54\x04\x45\x29\x8a\x3e\xac\x2c\xb4\xbb\ +\xdd\xdd\xc4\x87\xfd\xab\xad\x8a\x4f\x1a\x08\xcc\x64\x32\x5f\xe6\ +\x37\x19\xf8\xeb\x65\x7a\xf6\xc6\x2f\x73\x6f\x80\x60\x1b\x6f\x34\ +\x1a\xb1\xbd\xb3\x75\x69\x8c\x91\x9f\x32\xcf\xcf\x2e\xc6\x71\x1c\ +\x9b\x0f\x00\x75\x8e\xc1\x60\x60\x4e\x8e\x4f\xbf\x4d\xde\xdb\xdf\ +\xf5\xaa\x4a\x1c\xc7\x00\x44\x4d\x60\xd5\x29\x22\xd5\xe3\xb7\x77\ +\x57\x3c\x4e\xee\x79\x79\x7d\xe6\x2d\x89\x49\xb3\x14\xef\x3d\x00\ +\xd6\x5a\x9c\x6a\x0b\x6c\x01\xaa\x1d\x40\xc4\xd6\x5b\x90\x48\x30\ +\xc0\x3c\xcf\xea\x98\xa0\xce\x2d\x02\x9c\xba\x16\x10\x45\x02\x06\ +\x7c\x08\x14\x65\x41\x9a\xa5\xcc\x66\xd3\x0a\x60\x05\xb7\x0c\xb0\ +\xd6\xab\x20\x04\x4f\x59\x96\x14\xc5\x9c\x2c\x4b\x99\xa5\x53\xa6\ +\x69\x05\xb0\x22\x68\x4f\x82\xed\x7a\xe0\x98\x3c\x3d\x00\x50\x96\ +\x25\xde\x7b\xca\xa2\xe2\xfb\x1a\xd8\xc8\x73\xea\x16\x01\xea\x3a\ +\x09\x79\x9e\x13\x08\x18\x20\x10\xf0\xde\xb7\x4d\x14\x2b\xa8\x5b\ +\x52\x81\xf6\x7a\x30\x5e\xdf\xfc\xf2\x1b\xa5\x93\x10\x3e\x55\xa0\ +\x88\x48\x38\x3c\x3a\xf8\x76\x0e\x24\x8a\x22\xe7\x3a\x40\x3b\xca\ +\x49\x92\xd4\xa3\x1c\xaa\xe3\x50\xd9\xc1\x54\x42\x2a\xbf\xb9\x11\ +\x18\xae\x0c\xaf\xf9\x17\xeb\x1d\x29\x6c\x75\xb8\xda\x45\x87\xce\ +\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82\ +\x00\x00\x04\x04\ +\x89\ +\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\ +\x00\x00\x20\x00\x00\x00\x20\x08\x06\x00\x00\x00\x73\x7a\x7a\xf4\ +\x00\x00\x00\x04\x73\x42\x49\x54\x08\x08\x08\x08\x7c\x08\x64\x88\ +\x00\x00\x03\xbb\x49\x44\x41\x54\x58\x85\xed\x96\x4f\x68\x5c\x45\ +\x1c\xc7\xbf\xbf\x99\xf7\xde\x26\x98\xdd\x4d\xba\x59\xb3\x66\x77\ +\x9b\xcd\xd6\x1c\x34\xc1\x43\xd8\x62\xac\xc6\x9e\x02\x6d\x12\xe3\ +\x25\x35\xe9\xa1\x10\x8a\x20\x05\x8b\x07\x11\x5b\xa9\x24\xa2\x87\ +\x6a\x34\xb9\x15\xa4\x2d\xf6\x14\x91\x1c\x2c\x5a\x10\xa9\x60\x8a\ +\x28\x0a\x5e\x5a\x28\x42\xa8\xca\x66\x4b\x92\x6e\xf6\x6d\xdc\x34\ +\xc9\xfb\xb7\x33\xe3\x61\x37\x8a\x10\x36\xdb\x98\xc6\x83\xf9\xc2\ +\x9c\xe6\xbd\xf9\x7d\xde\x77\x7e\xf3\x9d\x07\xec\x69\x4f\xff\xb1\ +\xf8\x16\xf3\xcd\x00\x1a\x00\x78\xe5\xb1\xeb\x00\x91\xa3\x7d\x3d\ +\x1f\x19\xba\x66\x2e\x2d\x99\x16\x00\x07\x80\xd8\x4d\x80\x50\x32\ +\xd9\x7a\xa1\xbd\xbd\xe3\xa5\xe6\xe8\x63\xad\xcb\xf9\x3f\x66\xd7\ +\xd7\xd7\x05\x00\x1b\x80\xda\x15\x80\x03\x8f\x27\x4f\x4f\x4d\x7d\ +\xc6\x5b\x5a\x12\x4f\x2c\x2e\xce\x9f\x88\x34\x37\x61\x61\x7e\x71\ +\x4e\x08\x21\x51\x72\xe4\xe1\x03\x0c\x0e\x1e\x43\x43\xa8\x9e\x06\ +\x06\x06\x74\xc3\xd0\xbb\xa4\x12\xc7\x02\xfe\xba\xf4\xfc\xfc\xc2\ +\x0a\x80\x22\x00\xf7\xa1\x02\x0c\x0d\x0d\xc3\x75\x1d\x28\x25\xd1\ +\xde\xd1\xc1\x8f\x1c\x39\xea\x5f\xca\xe5\xfa\x43\xfb\xea\x9f\x53\ +\x4a\xcc\x9a\xe6\xb2\x8b\x6d\xf6\x47\xd5\x00\x9e\x57\xfa\x48\x29\ +\x25\x38\x67\xe8\xee\x3e\xcc\x53\xa9\x83\xb1\x4c\x26\x33\xdc\x1c\ +\x6b\x7e\x34\xb7\x94\xbb\x63\xdb\x36\xca\x20\x72\x47\x00\x02\x81\ +\x40\x28\x16\x8f\xfe\x03\x60\x43\x52\x0a\xf8\x03\x7e\xf4\xf5\xf5\ +\xf3\xfd\xf1\xf8\x53\x39\x33\x7b\x22\xd2\xd4\x64\xe5\xf3\xcb\x77\ +\x7d\x3e\x1f\x1c\xc7\xb1\xff\x35\x40\x32\x99\x0c\x05\x83\xfe\xd3\ +\x43\xc3\xc7\x51\x14\x45\x30\x22\x10\xb1\xbf\x07\x08\x52\x0a\xc4\ +\xa2\x31\xea\x7f\x61\xc0\x00\x54\x37\x41\xbc\x58\x17\x0c\xfe\x5a\ +\x5b\x53\xbb\xde\xd8\xd8\x28\x4c\xd3\xac\xd8\x1f\x54\x69\xb2\xa7\ +\xa7\xa7\x8d\x98\x9c\xbd\x7a\xf5\x0b\x58\xb6\x05\xa2\x8a\x8f\x83\ +\x33\x8e\xfb\xab\xab\x18\xff\xe0\xbc\x37\x97\xce\x7c\x7f\xdf\x5a\ +\x7b\x9b\x49\x96\x76\x5d\x77\x69\x66\x66\x66\x53\x47\x58\xa5\x05\ +\xa3\xd1\x68\x89\x92\x18\x38\xe7\xe0\x8c\x83\x73\x0e\xc6\x4a\x0e\ +\x28\xa5\x20\xa5\x80\x57\xf4\x60\x3b\x36\x56\x56\x0b\x90\xaa\x88\ +\xd1\xd1\x77\xf4\xd1\xb1\xb1\xc3\xc1\xba\xba\xef\x02\xf5\x75\xaf\ +\x25\x12\x89\xf8\xc8\xc8\x48\xcd\x03\x03\x84\xc3\x61\x00\x80\x52\ +\x12\x96\x6d\xc1\x76\x2c\xd8\xb6\x05\xc7\x75\xe0\x79\x0e\x84\x28\ +\x42\x48\x09\x28\x05\x46\x04\x8d\x6b\xf0\xf9\x6a\xc0\x19\xc7\xc2\ +\xfc\x82\xb4\x2c\x0b\x9c\x58\x3a\x1c\x0e\x63\x6d\x6d\x6d\xd3\x28\ +\xd7\x2a\x01\xc4\x62\x31\xdc\xfe\xe5\x16\x88\x18\x34\xae\x81\xb1\ +\x8d\x1e\x20\x10\xa8\xb4\x81\x0a\x50\xe5\x50\xd4\x35\x03\x99\xcc\ +\x1c\x26\x26\xc7\x5d\xc7\x71\x3f\x7d\xf6\xd0\x33\x13\x7e\xff\xbe\ +\x85\x7c\x3e\x6f\x4e\x4f\x4f\x6f\x7a\x32\x2a\x02\x44\xa3\x51\x18\ +\xba\x01\x22\xfa\x6b\x0b\x18\x63\x20\xc6\xc0\x88\xb0\xd1\x42\x9c\ +\x73\x14\x0a\x05\x4c\x4e\x4e\x78\x77\xe7\x32\x3f\x27\x12\xfb\xcf\ +\xb6\xb5\x3d\xf9\x5b\x30\x18\xcc\xf6\xf6\xf6\x56\x4c\xcb\x2d\x1d\ +\xd0\x75\x1d\x04\x80\x11\x03\x31\x02\x63\x0c\xac\xdc\x0b\x9c\x73\ +\x58\xeb\x16\xae\x5d\xfb\xd2\xbb\x7e\xfd\xeb\x6c\xb8\x31\x7c\xe6\ +\xd4\xa9\x57\x7f\x10\x42\xe4\xba\xba\xba\x56\x2a\xad\x5d\xbd\x03\ +\x86\x0e\x05\x40\x2a\x09\x92\x04\x09\x09\xc6\x18\xa4\x90\xb8\x75\ +\xf3\xa6\xbc\xfc\xc9\x45\xbb\xbe\xbe\xe1\xc3\xb3\x67\xce\x4d\xd5\ +\xd6\xd6\xe6\x23\x91\x88\x49\x44\x55\x07\x51\x55\x0e\x28\xa5\x20\ +\x44\xb1\xf4\x82\xa6\x23\x7b\xef\x1e\x2e\x5e\xfa\xd8\x55\x0a\x9f\ +\xbf\x7c\xf2\x95\xf1\xce\xce\xce\x2c\x80\x2c\x11\x3d\xf0\xe5\x54\ +\x11\x00\x00\x0c\xc3\x80\x52\x12\x9a\xa6\x43\x0a\x85\x2b\x57\x2e\ +\x7b\xe9\xf4\xef\xb7\x0f\xa6\x9e\x7e\x73\x70\x70\xe8\x0e\x80\x1c\ +\x11\x55\x65\xf7\xb6\x00\x74\x5d\x07\xe7\x1a\x7e\xfa\xf1\x46\xf1\ +\xdb\x99\x6f\xcc\x78\xbc\xe5\xdc\xfb\xe7\x27\x6e\x00\x28\x94\x8b\ +\x57\x6d\xf7\xf6\x00\x0c\x1d\xef\xbe\x37\x66\xfb\x1f\xf1\x5f\x78\ +\xe3\xf5\xb7\x2e\x85\x42\xa1\x55\x6c\xd3\xee\x6d\x01\xb4\xb6\xb6\ +\x8e\x1d\xea\x7a\xfe\xab\x54\x2a\x95\x03\x60\x12\x51\x61\x27\x0a\ +\x6f\xa8\x62\xb8\x2b\xa5\x0e\xa0\x94\x96\x85\x72\xf1\x1d\xfd\x1f\ +\xdc\x52\x4a\x29\x5d\x29\xe5\xdb\xd5\xa2\x7b\xfa\xdf\xe9\x4f\x7a\ +\x2a\x7c\x95\x17\xe9\x5e\xd9\x00\x00\x00\x00\x49\x45\x4e\x44\xae\ +\x42\x60\x82\ +\x00\x00\x02\x3b\ +\x89\ +\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\ +\x00\x00\x20\x00\x00\x00\x20\x08\x06\x00\x00\x00\x73\x7a\x7a\xf4\ +\x00\x00\x00\x04\x73\x42\x49\x54\x08\x08\x08\x08\x7c\x08\x64\x88\ +\x00\x00\x01\xf2\x49\x44\x41\x54\x58\x85\xed\x96\xed\x8a\xd3\x40\ +\x14\x86\x9f\xa4\x49\xdb\x93\x04\xb2\xa1\x0d\xb1\x8b\x7f\xbd\x22\ +\xbf\xf0\xe6\x44\x14\x05\x41\x6f\xc8\x0b\x58\x64\x17\x84\xed\xe2\ +\x07\xdd\xcc\x79\xfd\x91\xb6\xdb\xa2\xdb\x46\x03\xfe\xb1\x2f\x0c\ +\x99\x21\x73\xe6\x7d\x32\xe7\xcc\x10\x38\xe9\xa4\x93\xfe\x77\x45\ +\x3d\xe6\x9c\x03\xf9\x00\x8f\xaf\xc0\xc5\x7d\x2f\x93\x1e\x0b\x64\ +\x4f\x9e\x3f\xfe\x94\x24\xc9\xea\x4f\x9d\xdb\xb6\x1d\x7f\x78\xff\ +\xf1\xd1\xa1\x39\x47\x01\xca\xb2\x14\xc0\xdb\xd7\xef\xc6\xee\x8e\ +\xbb\xf7\x32\x4f\xd3\x94\x67\x2f\x9e\x52\x96\xa5\xae\xaf\xaf\x87\ +\x03\x48\xe2\xf2\xea\x33\xae\x7e\x00\xe7\x0f\x1e\x6e\xe3\x0f\x01\ +\xc4\xc7\x16\x3a\x3b\x3b\x13\x40\xf0\x80\xcb\x91\xf7\x6c\x6b\xd0\ +\x4d\xfc\x5f\x03\xcc\xe7\x73\x87\x6e\x07\xfe\x44\xbe\x9e\xbf\x89\ +\xbf\x4f\x47\x53\x30\x9b\xcd\x24\x1c\x49\xc4\x51\x8c\xef\x22\x6b\ +\xbf\x73\x37\xd4\xb6\x56\x66\xb3\xd9\x41\xf2\xa3\x00\x45\x51\xe8\ +\xe6\xdb\x12\x24\xe2\x38\x26\xd2\xfe\xc9\xd5\xc6\x76\xc7\xa6\x0d\ +\x2d\x5a\x03\x14\x45\x31\x0c\xa0\xae\x6b\xfd\xb8\xf8\x0e\xc0\x68\ +\x34\xda\xa6\x42\x12\x21\xb4\x04\x77\x42\x68\x69\x43\xc0\x43\x4b\ +\x1b\x9c\x08\xc1\xbc\x21\x4d\x53\xea\xba\x1e\x06\x90\x65\x99\x9b\ +\x19\xee\xe2\xb6\x6d\x09\xa1\x45\xc1\x09\x0a\x5b\x10\xe8\x6e\xb4\ +\x51\x3c\x22\x8e\x3b\x48\x49\x98\x19\x59\x96\x0d\xab\x81\xc5\x62\ +\xa1\xab\x2f\x97\x44\x71\x44\x44\x57\x07\x24\x11\xb1\x46\xdd\xf6\ +\xab\x4b\x82\xb4\xe9\x77\xe6\xa2\x03\x58\x2c\x16\xc3\x76\xa0\xaa\ +\x2a\x99\x4d\x89\x22\x48\x92\x31\x92\xaf\xbf\x10\xd8\x98\xe9\xce\ +\x74\xd3\x47\x60\x36\xa5\xaa\xaa\x61\x00\x65\x59\xba\x99\x11\x11\ +\x93\x26\x29\xee\xbe\x63\xe4\xfb\x00\x3b\x0d\xc0\xcc\x98\x4c\x26\ +\xc3\x00\xcc\x4c\x66\x46\x14\x41\x1c\x77\x67\x50\x12\x8e\xd3\x5d\ +\x23\x5a\xb7\xfd\x54\x6f\x6a\xa0\xaa\xaa\x61\x35\xd0\x34\x8d\xcc\ +\x0c\x49\x8c\x27\x93\x6d\xce\x7f\xf7\x84\xf5\xb1\x14\xb8\x1c\x33\ +\xa3\x69\x9a\x61\x3b\x90\xe7\xb9\xcc\xa6\xbc\x7a\xf3\xf2\xd8\xd4\ +\x5f\x64\x36\x25\xcf\xf3\x83\x00\x47\xff\x07\x24\x15\xc0\xb8\xaf\ +\xe9\x72\xb9\xdc\x1b\xaf\x56\xab\xdb\xba\xae\x6f\xfa\xc6\x9f\x74\ +\xd2\x49\xff\x5c\x3f\x01\x96\xf9\x3b\x3a\x60\x1d\x6f\x05\x00\x00\ +\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82\ +" + +qt_resource_name = "\ +\x00\x06\ +\x07\x03\x7d\xc3\ +\x00\x69\ +\x00\x6d\x00\x61\x00\x67\x00\x65\x00\x73\ +\x00\x05\ +\x00\x36\x9b\x62\ +\x00\x33\ +\x00\x32\x00\x78\x00\x33\x00\x32\ +\x00\x05\ +\x00\x34\xdb\x46\ +\x00\x31\ +\x00\x36\x00\x78\x00\x31\x00\x36\ +\x00\x18\ +\x0f\xa4\x86\x47\ +\x00\x6d\ +\x00\x65\x00\x64\x00\x69\x00\x61\x00\x2d\x00\x70\x00\x6c\x00\x61\x00\x79\x00\x62\x00\x61\x00\x63\x00\x6b\x00\x2d\x00\x73\x00\x74\ +\x00\x61\x00\x72\x00\x74\x00\x2e\x00\x70\x00\x6e\x00\x67\ +\x00\x17\ +\x09\x10\x6a\x47\ +\x00\x6d\ +\x00\x65\x00\x64\x00\x69\x00\x61\x00\x2d\x00\x70\x00\x6c\x00\x61\x00\x79\x00\x62\x00\x61\x00\x63\x00\x6b\x00\x2d\x00\x73\x00\x74\ +\x00\x6f\x00\x70\x00\x2e\x00\x70\x00\x6e\x00\x67\ +" + +qt_resource_struct = "\ +\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x01\ +\x00\x00\x00\x00\x00\x02\x00\x00\x00\x02\x00\x00\x00\x02\ +\x00\x00\x00\x22\x00\x02\x00\x00\x00\x02\x00\x00\x00\x06\ +\x00\x00\x00\x12\x00\x02\x00\x00\x00\x02\x00\x00\x00\x04\ +\x00\x00\x00\x68\x00\x00\x00\x00\x00\x01\x00\x00\x08\x51\ +\x00\x00\x00\x32\x00\x00\x00\x00\x00\x01\x00\x00\x04\x49\ +\x00\x00\x00\x68\x00\x00\x00\x00\x00\x01\x00\x00\x02\x98\ +\x00\x00\x00\x32\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\ +" + +def qInitResources(): + QtCore.qRegisterResourceData(0x01, qt_resource_struct, qt_resource_name, qt_resource_data) + +def qCleanupResources(): + QtCore.qUnregisterResourceData(0x01, qt_resource_struct, qt_resource_name, qt_resource_data) + +qInitResources() diff --git a/contrib/plugins/previewbar/resources.qrc b/contrib/plugins/previewbar/resources.qrc new file mode 100644 index 000000000..654bfb0af --- /dev/null +++ b/contrib/plugins/previewbar/resources.qrc @@ -0,0 +1,8 @@ + + + images/32x32/media-playback-start.png + images/32x32/media-playback-stop.png + images/16x16/media-playback-start.png + images/16x16/media-playback-stop.png + + \ No newline at end of file diff --git a/contrib/plugins/title_case_nx.py b/contrib/plugins/title_case_nx.py new file mode 100644 index 000000000..69d650b09 --- /dev/null +++ b/contrib/plugins/title_case_nx.py @@ -0,0 +1,123 @@ +# -*- coding: utf-8 -*- +# +# Picard, the next-generation MusicBrainz tagger +# Copyright (C) 2009 Carlin Mangar +# +# 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. +# +# THIS FILE MAKES USE OF: +# titlecase.py v0.2 +# Original Perl version by: John Gruber http://daringfireball.net/ 10 May 2008 +# Python version by Stuart Colville http://muffinresearch.co.uk +# License: http://www.opensource.org/licenses/mit-license.php +# +# The MIT License +# +# Copyright (c) 2008 John Gruber, Stuart Colville + +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# +# Source Code: https://launchpad.net/titlecase.py/trunk/0.2 + +PLUGIN_NAME = "Advanced Title Case for Picard" +PLUGIN_AUTHOR = "Carlin Mangar, John Gruber, Stuart Colville" +PLUGIN_VERSION = "0.1" +PLUGIN_API_VERSIONS = ["0.9", "0.10", "0.11", "0.12"] +PLUGIN_DESCRIPTION = "This plugin changes all words in title, album and artist to Title Case according \ + to the New York Times Manual of Style. Read Source code" + +import sys +import re +import unicodedata +from picard.metadata import ( + register_track_metadata_processor, + register_album_metadata_processor, + ) + +SMALL = 'a|an|and|as|at|but|by|en|for|if|in|of|on|or|the|to|v\.?|via|vs\.?' +PUNCT = "[!\"#$%&'‘()*+,-./:;?@[\\\\\\]_`{|}~]" + +SMALL_WORDS = re.compile(r'^(%s)$' % SMALL, re.I) +INLINE_PERIOD = re.compile(r'[a-zA-Z][.][a-zA-Z]') +UC_ELSEWHERE = re.compile(r'%s*?[a-zA-Z]+[A-Z]+?' % PUNCT) +CAPFIRST = re.compile(r"^%s*?([A-Za-z])" % PUNCT) +SMALL_FIRST = re.compile(r'^(%s*)(%s)\b' % (PUNCT, SMALL), re.I) +SMALL_LAST = re.compile(r'\b(%s)%s?$' % (SMALL, PUNCT), re.I) +SUBPHRASE = re.compile(r'([:.;?!][ ])(%s)' % SMALL) + +def titlecase(text): + + """ + Titlecases input text + + This filter changes all words to Title Caps, and attempts to be clever + about *un*capitalizing SMALL words like a/an/the in the input. + + The list of "SMALL words" which are not capped comes from + the New York Times Manual of Style, plus 'vs' and 'v'. + + """ + + words = re.split('\s', text) + line = [] + for word in words: + if INLINE_PERIOD.search(word) or UC_ELSEWHERE.match(word): + line.append(word) + continue + if SMALL_WORDS.match(word): + line.append(word.lower()) + continue + line.append(CAPFIRST.sub(lambda m: m.group(0).upper(), word)) + + line = " ".join(line) + + line = SMALL_FIRST.sub(lambda m: '%s%s' % ( + m.group(1), + m.group(2).capitalize() + ), line) + + line = SMALL_LAST.sub(lambda m: m.group(0).capitalize(), line) + + line = SUBPHRASE.sub(lambda m: '%s%s' % ( + m.group(1), + m.group(2).capitalize() + ), line) + + return line + + +def nx_title_case(tagger, metadata, release, track=None): + for name, value in metadata.rawitems(): + if name in ["title", "album", "artist"]: + metadata[name] = [titlecase(x) for x in value] + +register_track_metadata_processor(nx_title_case) +register_album_metadata_processor(nx_title_case) diff --git a/contrib/plugins/titlecase.py b/contrib/plugins/titlecase.py deleted file mode 100644 index 7d5da394c..000000000 --- a/contrib/plugins/titlecase.py +++ /dev/null @@ -1,57 +0,0 @@ -# Copyright 2007 Javier Kohen -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License version 2 as -# published by the Free Software Foundation - -import unicodedata - -def iswbound(char): - """Returns whether the given character is a word boundary.""" - category = unicodedata.category(char) - # If it's a space separator or punctuation - return 'Zs' == category or 'Sk' == category or 'P' == category[0] - -def utitle(string): - """Title-case a string using a less destructive method than str.title.""" - new_string = string[0].capitalize() - cap = False - for i in xrange(1, len(string)): - s = string[i] - # Special case apostrophe in the middle of a word. - if u"'" == s and string[i-1].isalpha(): cap = False - elif iswbound(s): cap = True - elif cap and s.isalpha(): - cap = False - s = s.capitalize() - else: cap = False - new_string += s - return new_string - -def title(string, locale="utf-8"): - """Title-case a string using a less destructive method than str.title.""" - if not string: return u"" - # if the string is all uppercase, lowercase it - Erich/Javier - # Lots of Japanese songs use entirely upper-case English titles, - # so I don't like this change... - JoeW - #if string == string.upper(): string = string.lower() - if not isinstance(string, unicode): - string = string.decode(locale) - return utitle(string) - - -PLUGIN_NAME = "Title Case" -PLUGIN_API_VERSIONS = ["0.9", "0.10", "0.11"] -PLUGIN_DESCRIPTION = "Capitalize First Character In Every Word Of A Title" -from picard.metadata import ( - register_track_metadata_processor, - register_album_metadata_processor, - ) - -def title_case(tagger, metadata, release, track=None): - for name, value in metadata.rawitems(): - if name in ["title", "album", "artist"]: - metadata[name] = [title(x) for x in value] - -register_track_metadata_processor(title_case) -register_album_metadata_processor(title_case) diff --git a/setup.py b/setup.py index c1a76f41a..57d8b7a37 100755 --- a/setup.py +++ b/setup.py @@ -11,8 +11,8 @@ from picard import __version__ from picard.const import UI_LANGUAGES -if sys.version_info < (2, 5): - print "*** You need Python 2.5 or higher to use Picard." +if sys.version_info < (2, 6): + print "*** You need Python 2.6 or higher to use Picard." args = {} @@ -341,6 +341,24 @@ class picard_clean_ui(Command): except OSError: log.warn("'%s' does not exist -- can't clean it", pyfile) +class picard_clean_pyd(Command): + description = "clean up compiled c files" + user_options = [] + + def initialize_options(self): + pass + + def finalize_options(self): + pass + + def run(self): + from PyQt4 import uic + for pydfile in glob.glob("picard/*/*.pyd"): + try: + os.unlink(pydfile) + log.info("removing %s", pydfile) + except OSError: + log.warn("'%s' does not exist -- can't clean it", pyfile) def cflags_to_include_dirs(cflags): cflags = cflags.split() @@ -460,6 +478,7 @@ args2 = { 'build_locales': picard_build_locales, 'build_ui': picard_build_ui, 'clean_ui': picard_clean_ui, + 'clean_pyd': picard_clean_pyd, 'config': picard_config, 'install': picard_install, 'install_locales': picard_install_locales, @@ -486,8 +505,8 @@ try: generate_file('scripts/picard.py2exe.in', 'scripts/picard', {}) self.distribution.data_files.append( ("", ["discid.dll", "libfftw3-3.dll", "libofa.dll", - ])) - # "msvcp71.dll"])) + # ])) + "msvcp90.dll"])) # Compile with VS2008 only or you will also need MSVC 7 runtimes as well. for locale in self.distribution.locales: self.distribution.data_files.append( ("locale/" + locale[1] + "/LC_MESSAGES", @@ -495,14 +514,24 @@ try: self.distribution.data_files.append( ("imageformats", [find_file_in_path("PyQt4/plugins/imageformats/qgif4.dll"), find_file_in_path("PyQt4/plugins/imageformats/qjpeg4.dll"), - find_file_in_path("PyQt4/plugins/imageformats/qtiff4.dll")])) + find_file_in_path("PyQt4/plugins/imageformats/qtiff4.dll")])) + self.distribution.data_files.append( + ("plugins", ["contrib/plugins/addrelease.py", + "contrib/plugins/discnumber.py", + "contrib/plugins/title_case_nx.py", + "contrib/plugins/featartist.py", + "contrib/plugins/originalreleasedate.py"])) + self.distribution.data_files.append( + ("phonon_backend", [find_file_in_path("PyQt4/plugins/phonon_backend/phonon_ds94.dll")])) py2exe.run(self) print "*** creating the NSIS setup script ***" pathname = "installer\picard-setup.nsi" generate_file(pathname + ".in", pathname, {'name': 'MusicBrainz Picard', - 'version': __version__}) + 'version': __version__, + 'description': 'The next generation MusicBrainz tagger.', + 'url': 'http://wiki.musicbrainz.org/PicardTagger',}) print "*** compiling the NSIS setup script ***" from ctypes import windll operation = 'compile' @@ -521,6 +550,7 @@ try: 'includes': ['sip'] + [e.name for e in ext_modules], 'excludes': ['ssl', 'socket', 'bz2'], 'optimize': 2, + 'dll_excludes' : ['AVIFIL32.dll','MSACM32.dll','MSVFW32.dll'] }, } except ImportError: