diff --git a/.hgtags b/.hgtags index e268fb86c..e69bb6762 100644 --- a/.hgtags +++ b/.hgtags @@ -13,3 +13,4 @@ a256ec5b0b2de500305fd6656db0a195df273acc 1.0b9 b6c10981014a5b3a963460fca3b31cc62bf7ed2c 1.0b13 d3dbc6df2b96f8ba5704305a893e3e63b7f9cd77 1.0b14 618201431990382474829cf96ea58e3669159f9a 1.0b15 +c84744f4519be7416dc1653142f1763f406d6896 1.0rc1 diff --git a/beets/__init__.py b/beets/__init__.py index 9b4d40b92..fed17e308 100644 --- a/beets/__init__.py +++ b/beets/__init__.py @@ -12,7 +12,7 @@ # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. -__version__ = '1.0rc1' +__version__ = '1.0rc2-dev' __author__ = 'Adrian Sampson ' import beets.library diff --git a/beets/mediafile.py b/beets/mediafile.py index 4f5be5ff4..82f6b9c06 100644 --- a/beets/mediafile.py +++ b/beets/mediafile.py @@ -460,7 +460,7 @@ class MediaField(object): else: if self.out_type == bool: # store bools as 1,0 instead of True,False - out = unicode(int(out)) + out = unicode(int(bool(out))) elif isinstance(out, str): out = out.decode('utf8', 'ignore') else: diff --git a/beets/ui/__init__.py b/beets/ui/__init__.py index c8eab799d..61469300b 100644 --- a/beets/ui/__init__.py +++ b/beets/ui/__init__.py @@ -694,3 +694,6 @@ def main(args=None): pass else: raise + except KeyboardInterrupt: + # Silently ignore ^C. + pass diff --git a/beets/util/__init__.py b/beets/util/__init__.py index 12a338439..5914de9ed 100644 --- a/beets/util/__init__.py +++ b/beets/util/__init__.py @@ -112,7 +112,7 @@ def normpath(path): """Provide the canonical form of the path suitable for storing in the database. """ - path = syspath(path) + path = syspath(path, prefix=False) path = os.path.normpath(os.path.abspath(os.path.expanduser(path))) return bytestring_path(path) @@ -310,10 +310,12 @@ def displayable_path(path): except (UnicodeError, LookupError): return path.decode('utf8', 'ignore') -def syspath(path, pathmod=None): +def syspath(path, prefix=True, pathmod=None): """Convert a path for use by the operating system. In particular, paths on Windows must receive a magic prefix and must be converted - to unicode before they are sent to the OS. + to Unicode before they are sent to the OS. To disable the magic + prefix on Windows, set `prefix` to False---but only do this if you + *really* know what you're doing. """ pathmod = pathmod or os.path windows = pathmod.__name__ == 'ntpath' @@ -335,7 +337,7 @@ def syspath(path, pathmod=None): path = path.decode(encoding, 'replace') # Add the magic prefix if it isn't already there - if not path.startswith(WINDOWS_MAGIC_PREFIX): + if prefix and not path.startswith(WINDOWS_MAGIC_PREFIX): path = WINDOWS_MAGIC_PREFIX + path return path diff --git a/beetsplug/fetchart.py b/beetsplug/fetchart.py index 2eb2b5103..33bebe414 100644 --- a/beetsplug/fetchart.py +++ b/beetsplug/fetchart.py @@ -150,13 +150,17 @@ def _source_urls(album): necessary. """ if album.mb_albumid: - yield caa_art(album.mb_albumid) + url = caa_art(album.mb_albumid) + if url: + yield url # Amazon and AlbumArt.org. if album.asin: for url in art_for_asin(album.asin): yield url - yield aao_art(album.asin) + url = aao_art(album.asin) + if url: + yield url def art_for_album(album, path, maxwidth=None, local_only=False): """Given an Album object, returns a path to downloaded art for the diff --git a/beetsplug/zero.py b/beetsplug/zero.py index 0dc5e228e..9aebe9f9d 100644 --- a/beetsplug/zero.py +++ b/beetsplug/zero.py @@ -49,7 +49,7 @@ class ZeroPlugin(BeetsPlugin): for f in self.config['fields'].get(list): if f not in ITEM_KEYS: - self._log.error('[zero] invalid field: {0}'.format(f)) + self._log.error(u'[zero] invalid field: {0}'.format(f)) else: self.fields.append(f) try: @@ -60,7 +60,7 @@ class ZeroPlugin(BeetsPlugin): def import_task_choice_event(self, task): """Listen for import_task_choice event.""" if task.choice_flag == action.ASIS and not self.warned: - self._log.warn('[zero] cannot zero in \"as-is\" mode') + self._log.warn(u'[zero] cannot zero in \"as-is\" mode') self.warned = True # TODO request write in as-is mode @@ -77,23 +77,24 @@ class ZeroPlugin(BeetsPlugin): def write_event(self, item): """Listen for write event.""" if not self.fields: - self._log.warn('[zero] no fields, nothing to do') + self._log.warn(u'[zero] no fields, nothing to do') return for fn in self.fields: try: fval = getattr(item, fn) except AttributeError: - self._log.error('[zero] no such field: {0}'.format(fn)) + self._log.error(u'[zero] no such field: {0}'.format(fn)) else: if not self.match_patterns(fval, self.patterns[fn]): - self._log.debug('[zero] \"{0}\" ({1}) not match: {2}' + self._log.debug(u'[zero] \"{0}\" ({1}) not match: {2}' .format(fval, fn, ' '.join(self.patterns[fn]))) continue - self._log.debug('[zero] \"{0}\" ({1}) match: {2}' + self._log.debug(u'[zero] \"{0}\" ({1}) match: {2}' .format(fval, fn, ' '.join(self.patterns[fn]))) setattr(item, fn, type(fval)()) - self._log.debug('[zero] {0}={1}'.format(fn, getattr(item, fn))) + self._log.debug(u'[zero] {0}={1}' + .format(fn, getattr(item, fn))) @ZeroPlugin.listen('import_task_choice') diff --git a/docs/changelog.rst b/docs/changelog.rst index 57974231b..9737406b8 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -1,21 +1,42 @@ Changelog ========= -1.0rc1 (in development) +1.0rc2 (in development) ----------------------- -* New plugin: :doc:`/plugins/convert` transcodes music and embeds album art +* :doc:`/plugins/fetchart`: Fix a regression that caused crashes when art was + not available from some sources. +* Fix a regression on Windows that caused all relative paths to be "not found". + +1.0rc1 (December 17, 2012) +-------------------------- + +The first release candidate for beets 1.0 includes a deluge of new features +contributed by beets users. The vast majority of the credit for this release +goes to the growing and vibrant beets community. A million thanks to everybody +who contributed to this release. + +There are new plugins for transcoding music, fuzzy searches, tempo collection, +and fiddling with metadata. The ReplayGain plugin has been rebuilt from +scratch. Album art images can now be resized automatically. Many other smaller +refinements make things "just work" as smoothly as possible. + +With this release candidate, beets 1.0 is feature-complete. We'll be fixing +bugs on the road to 1.0 but no new features will be added. Concurrently, work +begins today on features for version 1.1. + +* New plugin: :doc:`/plugins/convert` **transcodes** music and embeds album art while copying to a separate directory. Thanks to Jakob Schnitzer and Andrew G. Dunn. -* New plugin: :doc:`/plugins/fuzzy_search` lets you find albums and tracks using - fuzzy string matching so you don't have to type (or even remember) their exact - names. Thanks to Philippe Mongeau. -* New plugin: :doc:`/plugins/echonest_tempo` fetches tempo (BPM) information +* New plugin: :doc:`/plugins/fuzzy_search` lets you find albums and tracks + using **fuzzy string matching** so you don't have to type (or even remember) + their exact names. Thanks to Philippe Mongeau. +* New plugin: :doc:`/plugins/echonest_tempo` fetches **tempo** (BPM) information from `The Echo Nest`_. Thanks to David Brenner. * New plugin: :doc:`/plugins/the` adds a template function that helps format text for nicely-sorted directory listings. Thanks to Blemjhoo Tezoulbr. -* New plugin: :doc:`/plugins/zero` filters out undesirable fields before they - are written to your tags. Thanks again to Blemjhoo Tezoulbr. +* New plugin: :doc:`/plugins/zero` **filters out undesirable fields** before + they are written to your tags. Thanks again to Blemjhoo Tezoulbr. * New plugin: :doc:`/plugins/ihate` automatically skips (or warns you about) importing albums that match certain criteria. Thanks once again to Blemjhoo Tezoulbr. @@ -23,7 +44,7 @@ Changelog the `mp3gain`_ or `aacgain`_ command-line tools instead of the failure-prone Gstreamer ReplayGain implementation. Thanks to Fabrice Laporte. * :doc:`/plugins/fetchart` and :doc:`/plugins/embedart`: Both plugins can now - resize album art to avoid excessively large images. Use the ``maxwidth`` + **resize album art** to avoid excessively large images. Use the ``maxwidth`` config option with either plugin. Thanks to Fabrice Laporte. * :doc:`/plugins/scrub`: Scrubbing now removes *all* types of tags from a file rather than just one. For example, if your FLAC file has both ordinary FLAC diff --git a/docs/conf.py b/docs/conf.py index 09790f717..19e4a7336 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -12,8 +12,8 @@ master_doc = 'index' project = u'beets' copyright = u'2012, Adrian Sampson' -version = '1.0rc1' -release = '1.0rc1' +version = '1.0' +release = '1.0rc2-dev' pygments_style = 'sphinx' diff --git a/docs/guides/main.rst b/docs/guides/main.rst index d049ca44a..ec4986ec4 100644 --- a/docs/guides/main.rst +++ b/docs/guides/main.rst @@ -14,8 +14,8 @@ You will need Python. (Beets is written for `Python 2.7`_, but it works with .. _Python 2.7: http://www.python.org/download/releases/2.7.2/ -* **Mac OS X** v10.7 (Lion) includes Python 2.7 out of the box; Snow Leopard - ships with Python 2.6. +* **Mac OS X** v10.7 (Lion) and 10.8 (Mountain Lion) include Python 2.7 out of + the box; Snow Leopard ships with Python 2.6. * On **Debian or Ubuntu**, depending on the version, beets is available as an official package (`Debian details`_, `Ubuntu details`_), so try typing: @@ -39,12 +39,11 @@ You will need Python. (Beets is written for `Python 2.7`_, but it works with If you have `pip`_, just say ``pip install beets`` (you might need ``sudo`` in front of that). On Arch, you'll need to use ``pip2`` instead of ``pip``. -To install without pip, head over to the `Downloads`_ area, download the most -recent source distribution, and run ``python setup.py install`` in the directory -therein. +To install without pip, download beets from `its PyPI page`_ and run ``python +setup.py install`` in the directory therein. +.. _its PyPI page: http://pypi.python.org/pypi/beets#downloads .. _pip: http://pip.openplans.org/ -.. _Downloads: https://github.com/sampsyo/beets/downloads The best way to upgrade beets to a new version is by running ``pip install -U beets``. You may want to follow `@b33ts`_ on Twitter to hear about progress on diff --git a/docs/plugins/index.rst b/docs/plugins/index.rst index 1132de456..1fd497a81 100644 --- a/docs/plugins/index.rst +++ b/docs/plugins/index.rst @@ -81,7 +81,8 @@ Path Formats * :doc:`inline`: Use Python snippets to customize path format strings. * :doc:`rewrite`: Substitute values in path formats. -* :doc:`the`: Moves patterns in path formats (suitable for moving articles). +* :doc:`the`: Move patterns in path formats (i.e., move "a" and "the" to the + end). Interoperability '''''''''''''''' @@ -97,10 +98,11 @@ Miscellaneous * :doc:`rdm`: Randomly choose albums and tracks from your library. * :doc:`fuzzy_search`: Search albums and tracks with fuzzy string matching. * :doc:`mbcollection`: Maintain your MusicBrainz collection list. -* :doc:`ihate`: Skip by defined patterns things you hate during import process. +* :doc:`ihate`: Automatically skip albums and tracks during the import process. * :doc:`bpd`: A music player for your beets library that emulates `MPD`_ and is compatible with `MPD clients`_. -* :doc:`convert`: Converts parts of your collection to an external directory +* :doc:`convert`: Transcode music and embed album art while exporting to + a different directory. * :doc:`info`: Print music files' tags to the console. .. _MPD: http://mpd.wikia.com/ diff --git a/setup.py b/setup.py index 6023c9537..ca499b060 100755 --- a/setup.py +++ b/setup.py @@ -42,7 +42,7 @@ if 'sdist' in sys.argv: shutil.copytree(os.path.join(docdir, '_build', 'man'), mandir) setup(name='beets', - version='1.0rc1', + version='1.0rc2-dev', description='music tagger and library organizer', author='Adrian Sampson', author_email='adrian@radbox.org', diff --git a/test/test_db.py b/test/test_db.py index 4d451c3f1..43e9ef5db 100644 --- a/test/test_db.py +++ b/test/test_db.py @@ -555,13 +555,13 @@ class DisambiguationTest(unittest.TestCase, PathFormattingMixin): class PathConversionTest(unittest.TestCase): def test_syspath_windows_format(self): path = ntpath.join('a', 'b', 'c') - outpath = util.syspath(path, ntpath) + outpath = util.syspath(path, pathmod=ntpath) self.assertTrue(isinstance(outpath, unicode)) self.assertTrue(outpath.startswith(u'\\\\?\\')) def test_syspath_posix_unchanged(self): path = posixpath.join('a', 'b', 'c') - outpath = util.syspath(path, posixpath) + outpath = util.syspath(path, pathmod=posixpath) self.assertEqual(path, outpath) def _windows_bytestring_path(self, path):