internlm/SWE-Fixer-Train-110K huggingface dataset:
Repository: beetbox/beets

Issue:
Allow plugins to define the same flexible fields if they are of the same type
It should be possible for plugins to define the same flexible fields if they are of the same type.  At the moment lastfmimport and mpdstats define 'play_count' which leads to:

`beets.plugins.PluginConflictException: Plugin mpdstats defines flexible field play_count which has already been defined.`



Discussion:

Resolving patch:
diff --git a/beets/plugins.py b/beets/plugins.py
--- a/beets/plugins.py
+++ b/beets/plugins.py
@@ -262,12 +262,11 @@ def types(model_cls):
     for plugin in find_plugins():
         plugin_types = getattr(plugin, attr_name, {})
         for field in plugin_types:
-            if field in types:
+            if field in types and plugin_types[field] != types[field]:
                 raise PluginConflictException(
                     u'Plugin {0} defines flexible field {1} '
-                    'which has already been defined.'.format(
-                        plugin.name, field
-                    )
+                    'which has already been defined with '
+                    'another type.'.format(plugin.name, field)
                 )
         types.update(plugin_types)
     return types


Test patch:
diff --git a/test/test_plugins.py b/test/test_plugins.py
--- a/test/test_plugins.py
+++ b/test/test_plugins.py
@@ -112,6 +112,45 @@ def register_listener(self, event, func):
         self.event_listener_plugin.register_listener(event, func)
 
 
+class ItemTypeConflictTest(unittest.TestCase, TestHelper):
+
+    def setUp(self):
+        self.setup_plugin_loader()
+        self.setup_beets()
+
+    def tearDown(self):
+        self.teardown_plugin_loader()
+        self.teardown_beets()
+
+    def test_mismatch(self):
+        class EventListenerPlugin(plugins.BeetsPlugin):
+            item_types = {'duplicate': types.INTEGER}
+
+        class AdventListenerPlugin(plugins.BeetsPlugin):
+            item_types = {'duplicate': types.FLOAT}
+
+        self.event_listener_plugin = EventListenerPlugin
+        self.advent_listener_plugin = AdventListenerPlugin
+        self.register_plugin(EventListenerPlugin)
+        self.register_plugin(AdventListenerPlugin)
+        self.assertRaises(plugins.PluginConflictException,
+                          plugins.types, Item
+                          )
+
+    def test_match(self):
+        class EventListenerPlugin(plugins.BeetsPlugin):
+            item_types = {'duplicate': types.INTEGER}
+
+        class AdventListenerPlugin(plugins.BeetsPlugin):
+            item_types = {'duplicate': types.INTEGER}
+
+        self.event_listener_plugin = EventListenerPlugin
+        self.advent_listener_plugin = AdventListenerPlugin
+        self.register_plugin(EventListenerPlugin)
+        self.register_plugin(AdventListenerPlugin)
+        self.assertNotEqual(None, plugins.types(Item))
+
+
 def suite():
     return unittest.TestLoader().loadTestsFromName(__name__)
Repository: beetbox/beets

Issue:
smartplaylist: Respect sort terms in queries
It would be nice to be able sort items in smart playlists, like so:

```
smartplaylist:
  relative_to: ~/music
  playlist_dir: ~/.mpd/playlists
  playlists:
    - name: '2014.m3u'
      query: 'year:2014 added+'
    - name: 'imported-%time{$added,%Y-%m}.m3u'
      query: "added:: path+"
```

I'm unfamiliar with the code but it looks like the smartplaylist plugin [discards the query `sort` field](https://github.com/sampsyo/beets/blob/master/beetsplug/smartplaylist.py#L45) when building playlists. Would it be possible to keep the custom sort?



Discussion:
Indeed; it is unfortunate that the plugin discards the sort—I 100% agree that this deserves fixing.

For a single query it should be relatively easy to preserve the sort , I think we simply need to add it to the call `lib.albums(query):` and `lib.items(query);` a few lines bellow.

But when using a list of query, which is supported by the plugin, which sort specification should we use ? 
For example : 

```
name: 'BeatlesUniverse.m3u'
query: ['artist:beatles added+', 'genre:"beatles cover year+"']
```

Intuitively, I would assume that would produce a list made from joining the results of two sorted queries (`query1.extend(query2)`).


Resolving patch:
diff --git a/beetsplug/smartplaylist.py b/beetsplug/smartplaylist.py
--- a/beetsplug/smartplaylist.py
+++ b/beetsplug/smartplaylist.py
@@ -18,7 +18,6 @@
 
 from beets.plugins import BeetsPlugin
 from beets import config, ui, library
-from beets import dbcore
 from beets.util import normpath, syspath
 import os
 
@@ -36,23 +35,21 @@ def _items_for_query(lib, playlist, album=False):
     if key not in playlist:
         return []
 
-    # Parse quer(ies). If it's a list, join the queries with OR.
+    # Parse quer(ies). If it's a list, perform the queries and manually
+    # concatenate the results
     query_strings = playlist[key]
     if not isinstance(query_strings, (list, tuple)):
         query_strings = [query_strings]
     model = library.Album if album else library.Item
-    query = dbcore.OrQuery(
-        [library.parse_query_string(q, model)[0] for q in query_strings]
-    )
-
-    # Execute query, depending on type.
-    if album:
-        result = []
-        for album in lib.albums(query):
-            result.extend(album.items())
-        return result
-    else:
-        return lib.items(query)
+    results = []
+    for q in query_strings:
+        querystr, sort = library.parse_query_string(q, model)
+        if album:
+            new = lib.albums(querystr, sort)
+        else:
+            new = lib.items(querystr, sort)
+        results.extend(new)
+    return results
 
 
 def update_playlists(lib):


Test patch:
Repository: beetbox/beets

Issue:
ftintitle: does not gracefully handle duplicate artist name
Using ftintitle on one of my tracks, it seemed to get tripped up and not be able to fix it. I've tracked it down to being a problem with the fact that the Album Artist's name is in the Artist field twice.

```
Artist: The Roots feat. Talib Kweli / The Roots
Album Artist: The Roots
```

When trying to find the album artist in the artist field, it does a string split using the album artist as a separator. This returns a list with the following values `['', 'feat. Talib Kweli / ', '']`.

The code that tries to find the `feat_part` is then only expecting a two element list, but is instead given a three. It then checks if the `-1th` element, `2` in this case, is blank. If it's not, it extracts the featured artist. 

If it is blank, it goes on to assume the featured artist must be on the left-hand side of the split and checks element `0`.

Both elements `0` and `2` are blank, so no featured part is found.

I've thought of two solutions, but am not sure which one would make more sense
- Attempt to remove duplicate album artists from the artist string before splitting
- Add another/change the current case to iterate over the split parts to find the first non-blank item

Either way, these methods would presumably still leave the trailing slash on the `feat. Talib Kweli /` and add the extraneous trailing slash to the track title. This, I'm not quite sure how to handle if at all.

Thoughts?



Discussion:
Thanks for investigating; this does look like a problem. Perhaps we should just split on the first occurrence? I don't know why the Roots are in there twice, but I suppose the most reasonable thing would be to move the entire string "Talib Kweli / The Roots" to the title.


Resolving patch:
diff --git a/beetsplug/ftintitle.py b/beetsplug/ftintitle.py
--- a/beetsplug/ftintitle.py
+++ b/beetsplug/ftintitle.py
@@ -83,7 +83,7 @@ def ft_in_title(item, drop_feat):
 
         # Look for the album artist in the artist field. If it's not
         # present, give up.
-        albumartist_split = artist.split(albumartist)
+        albumartist_split = artist.split(albumartist, 1)
         if len(albumartist_split) <= 1:
             ui.print_('album artist not present in artist')
 


Test patch:
Repository: beetbox/beets

Issue:
Improve extractart to extract cover art of all albums for a query
The current `extractart` command of the `embedart` plugin is only able to extract the cover art of a single file. If the query the user specifies results in more than one item, only the art of the first one is extracted.

I would like to improve the command such the user queries for albums (like `ls -a` command) and one cover art is extracted per album and placed inside the album folder. The command should try all files of an album until an art is found. The command could be executed like `beet extractart -a <query>`.



Discussion:

Resolving patch:
diff --git a/beetsplug/embedart.py b/beetsplug/embedart.py
--- a/beetsplug/embedart.py
+++ b/beetsplug/embedart.py
@@ -89,8 +89,9 @@ def embed_func(lib, opts, args):
 
         def extract_func(lib, opts, args):
             outpath = normpath(opts.outpath or 'cover')
-            item = lib.items(decargs(args)).get()
-            self.extract(outpath, item)
+            for item in lib.items(decargs(args)):
+                if self.extract(outpath, item):
+                    return
         extract_cmd.func = extract_func
 
         # Clear command.


Test patch:
Repository: beetbox/beets

Issue:
Better error message when MusicBrainz is unreachable
A user [recently was confused by a terrible error message](https://botbot.me/freenode/beets/2014-12-28/?msg=28424335&page=1) when their DNS was misconfigured:

```
Error: "caused by: <urlopen error [Errno -2] Name or service not known>" in
release search with query blah blah blah...
```

It would be great to have this instead print "MusicBrainz not reachable" (maybe with more info in the verbose log).



Discussion:

Resolving patch:
diff --git a/beets/autotag/mb.py b/beets/autotag/mb.py
--- a/beets/autotag/mb.py
+++ b/beets/autotag/mb.py
@@ -38,6 +38,8 @@ class MusicBrainzAPIError(util.HumanReadableException):
     """
     def __init__(self, reason, verb, query, tb=None):
         self.query = query
+        if isinstance(reason, musicbrainzngs.WebServiceError):
+            reason = 'MusicBrainz not reachable'
         super(MusicBrainzAPIError, self).__init__(reason, verb, tb)
 
     def get_message(self):


Test patch:
Repository: beetbox/beets

Issue:
embedart plugin disregards "write: no" and "-W" config opts
Any import action with `embedart` enabled causes a full write of tags and art, even when config file specifies `write: no`, or commandline includes `-W`.

CAUSE: `art.py` does not check config option `import/write` before calling `try_write`.

SUGGESTED FIX: check config option first! :) PR will be attached presently.

embedart plugin disregards "write: no" and "-W" config opts
Any import action with `embedart` enabled causes a full write of tags and art, even when config file specifies `write: no`, or commandline includes `-W`.

CAUSE: `art.py` does not check config option `import/write` before calling `try_write`.

SUGGESTED FIX: check config option first! :) PR will be attached presently.

embedart plugin disregards "write: no" and "-W" config opts
Any import action with `embedart` enabled causes a full write of tags and art, even when config file specifies `write: no`, or commandline includes `-W`.

CAUSE: `art.py` does not check config option `import/write` before calling `try_write`.

SUGGESTED FIX: check config option first! :) PR will be attached presently.



Discussion:
It might be preferable to add the config check into `library.py` function `try_write` itself.

There are two other locations that call `try_write`: `importer.py/manipulate_files` and `library.py/try_sync`. These two check config settings properly.

PR #1428 adds the config test to `art.py/embed_item`, for a third occurrence of similar code.

Thanks for the report, and for the fix! This is indeed a problem.

It might be preferable to add the config check into `library.py` function `try_write` itself.

There are two other locations that call `try_write`: `importer.py/manipulate_files` and `library.py/try_sync`. These two check config settings properly.

PR #1428 adds the config test to `art.py/embed_item`, for a third occurrence of similar code.

Thanks for the report, and for the fix! This is indeed a problem.

It might be preferable to add the config check into `library.py` function `try_write` itself.

There are two other locations that call `try_write`: `importer.py/manipulate_files` and `library.py/try_sync`. These two check config settings properly.

PR #1428 adds the config test to `art.py/embed_item`, for a third occurrence of similar code.

Thanks for the report, and for the fix! This is indeed a problem.


Resolving patch:
diff --git a/beetsplug/embedart.py b/beetsplug/embedart.py
--- a/beetsplug/embedart.py
+++ b/beetsplug/embedart.py
@@ -126,7 +126,7 @@ def clear_func(lib, opts, args):
     def process_album(self, album):
         """Automatically embed art after art has been set
         """
-        if self.config['auto']:
+        if self.config['auto'] and config['import']['write']:
             max_width = self.config['maxwidth'].get(int)
             art.embed_album(self._log, album, max_width, True,
                             self.config['compare_threshold'].get(int),


Test patch:
Repository: beetbox/beets

Issue:
Sort by Path
Because path is stored as a blob, COLLATE NOCASE doesn't work, lowercase entries come after uppercase ones.
ORDER BY LOWER(path) does work though.



Discussion:
Sounds good. A patch to make this work would be helpful.


Resolving patch:
diff --git a/beets/dbcore/query.py b/beets/dbcore/query.py
--- a/beets/dbcore/query.py
+++ b/beets/dbcore/query.py
@@ -756,8 +756,11 @@ class FixedFieldSort(FieldSort):
     """
     def order_clause(self):
         order = "ASC" if self.ascending else "DESC"
-        collate = 'COLLATE NOCASE' if self.case_insensitive else ''
-        return "{0} {1} {2}".format(self.field, collate, order)
+        if self.case_insensitive:
+            field = 'LOWER({})'.format(self.field)
+        else:
+            field = self.field
+        return "{0} {1}".format(field, order)
 
 
 class SlowFieldSort(FieldSort):


Test patch:
diff --git a/test/test_sort.py b/test/test_sort.py
--- a/test/test_sort.py
+++ b/test/test_sort.py
@@ -66,6 +66,7 @@ def setUp(self):
         items[0].flex2 = "Flex2-A"
         items[0].album_id = albums[0].id
         items[0].artist_sort = None
+        items[0].path = "/path0.mp3"
         items[1].title = 'Baz qux'
         items[1].artist = 'Two'
         items[1].album = 'Baz'
@@ -75,6 +76,7 @@ def setUp(self):
         items[1].flex2 = "Flex2-A"
         items[1].album_id = albums[0].id
         items[1].artist_sort = None
+        items[1].path = "/patH1.mp3"
         items[2].title = 'Beets 4 eva'
         items[2].artist = 'Three'
         items[2].album = 'Foo'
@@ -84,6 +86,7 @@ def setUp(self):
         items[2].flex2 = "Flex1-B"
         items[2].album_id = albums[1].id
         items[2].artist_sort = None
+        items[2].path = "/paTH2.mp3"
         items[3].title = 'Beets 4 eva'
         items[3].artist = 'Three'
         items[3].album = 'Foo2'
@@ -93,6 +96,7 @@ def setUp(self):
         items[3].flex2 = "Flex1-C"
         items[3].album_id = albums[2].id
         items[3].artist_sort = None
+        items[3].path = "/PATH3.mp3"
         for item in items:
             self.lib.add(item)
 
@@ -141,6 +145,15 @@ def test_sort_two_field_asc(self):
         for r1, r2 in zip(results, results2):
             self.assertEqual(r1.id, r2.id)
 
+    def test_sort_path_field(self):
+        q = ''
+        sort = dbcore.query.FixedFieldSort('path', True)
+        results = self.lib.items(q, sort)
+        self.assertEqual(results[0]['path'], '/path0.mp3')
+        self.assertEqual(results[1]['path'], '/patH1.mp3')
+        self.assertEqual(results[2]['path'], '/paTH2.mp3')
+        self.assertEqual(results[3]['path'], '/PATH3.mp3')
+
 
 class SortFlexFieldTest(DummyDataTestCase):
     def test_sort_asc(self):
Repository: beetbox/beets

Issue:
python-mpd is old and crusty, beets should start using python-mpd2
Assuming that at some point in time `beets` needs to run on Python 3 (which it does eventually, because Python 2 is being phased out), there will be an issue concerning `python-mpd`; `python-mpd` is not compatible with Python 3, nor is it really even maintained upstream anymore. The [last update was in December of 2010](https://pypi.python.org/pypi/python-mpd/), and it's website is down as well.

[`python-mpd2`](https://github.com/Mic92/python-mpd2), however, is maintained and sees fairly active development. It is a fork of `python-mpd`, and has [a document explaining porting](https://github.com/Mic92/python-mpd2/blob/1c7e8f246465110ccb2d64df829c6dbdcdc74c9e/doc/topics/porting.rst) from `python-mpd` on the repository. Aside from the stickers API, which I'm not even sure `beets` uses, it looks fairly easy to replace.

I think that it would be better to use python-mpd2 for these reasons. Any thoughts?



Discussion:
Seems like a great idea! And porting should be minimal effort. :sparkles: Would you be interested in flipping the switch and checking that stuff still works?

Certainly. I'll submit a pull req once I'm done.


Resolving patch:
diff --git a/setup.py b/setup.py
--- a/setup.py
+++ b/setup.py
@@ -105,7 +105,7 @@ def build_manpages():
         'responses',
         'pyxdg',
         'pathlib',
-        'python-mpd',
+        'python-mpd2',
     ],
 
     # Plugin (optional) dependencies:
@@ -115,7 +115,7 @@ def build_manpages():
         'discogs': ['discogs-client>=2.1.0'],
         'echonest': ['pyechonest'],
         'lastgenre': ['pylast'],
-        'mpdstats': ['python-mpd'],
+        'mpdstats': ['python-mpd2'],
         'web': ['flask', 'flask-cors'],
         'import': ['rarfile'],
         'thumbnails': ['pathlib', 'pyxdg'],


Test patch:
Repository: beetbox/beets

Issue:
importfeeds: name of m3u_multi playlist get messed up when both m3u* options are on
activate both m3u output formats   

```
 importfeeds:
        formats: m3u m3u_multi
```

Result : m3u_multi filename is not `<date> <track/album name>` as expected



Discussion:

Resolving patch:
diff --git a/beetsplug/importfeeds.py b/beetsplug/importfeeds.py
--- a/beetsplug/importfeeds.py
+++ b/beetsplug/importfeeds.py
@@ -118,10 +118,9 @@ def _record_items(self, lib, basename, items):
                 paths.append(relpath)
 
         if 'm3u' in formats:
-            basename = bytestring_path(
-                self.config['m3u_name'].get(unicode)
-            )
-            m3u_path = os.path.join(feedsdir, basename)
+            m3u_basename = bytestring_path(
+                self.config['m3u_name'].get(unicode))
+            m3u_path = os.path.join(feedsdir, m3u_basename)
             _write_m3u(m3u_path, paths)
 
         if 'm3u_multi' in formats:


Test patch:
Repository: beetbox/beets

Issue:
__str__ crash due to timeout in fetchart plugin
This looks like more of an issue with the urllib3 package than beets, but beets could do with a workaround to avoid crashing when this exception occurs while fetching album artwork:

```
  File "/usr/local/lib/python2.7/dist-packages/beets-1.3.14-py2.7.egg/beetsplug/fetchart.py", line 385, in fetch_art
    path = self.art_for_album(task.album, task.paths, local)
  File "/usr/local/lib/python2.7/dist-packages/beets-1.3.14-py2.7.egg/beetsplug/fetchart.py", line 488, in art_for_album
    candidate = self._fetch_image(url)
  File "/usr/local/lib/python2.7/dist-packages/beets-1.3.14-py2.7.egg/beetsplug/fetchart.py", line 425, in _fetch_image
    with closing(requests_session.get(url, stream=True)) as resp:
  File "/home/ben/.local/lib/python2.7/site-packages/requests/sessions.py", line 477, in get
    return self.request('GET', url, **kwargs)
  File "/home/ben/.local/lib/python2.7/site-packages/requests/sessions.py", line 465, in request
    resp = self.send(prep, **send_kwargs)
  File "/home/ben/.local/lib/python2.7/site-packages/requests/sessions.py", line 573, in send
    r = adapter.send(request, **kwargs)
  File "/home/ben/.local/lib/python2.7/site-packages/requests/adapters.py", line 370, in send
    timeout=timeout
  File "/home/ben/.local/lib/python2.7/site-packages/requests/packages/urllib3/connectionpool.py", line 544, in urlopen
    body=body, headers=headers)
  File "/home/ben/.local/lib/python2.7/site-packages/requests/packages/urllib3/connectionpool.py", line 344, in _make_request
    self._raise_timeout(err=e, url=url, timeout_value=conn.timeout)
  File "/home/ben/.local/lib/python2.7/site-packages/requests/packages/urllib3/connectionpool.py", line 314, in _raise_timeout
    if 'timed out' in str(err) or 'did not complete (read)' in str(err):  # Python 2.6
TypeError: __str__ returned non-string (type Error)
```



Discussion:

Resolving patch:
diff --git a/beetsplug/fetchart.py b/beetsplug/fetchart.py
--- a/beetsplug/fetchart.py
+++ b/beetsplug/fetchart.py
@@ -436,7 +436,7 @@ def _fetch_image(self, url):
                 self._log.debug(u'downloaded art to: {0}',
                                 util.displayable_path(fh.name))
                 return fh.name
-        except (IOError, requests.RequestException):
+        except (IOError, requests.RequestException, TypeError):
             self._log.debug(u'error fetching art')
 
     def _is_valid_image_candidate(self, candidate):


Test patch:
Repository: beetbox/beets

Issue:
Add aliases for standard terminal colors in color config
Terminals usually call `teal` and `turquoise` the `darkcyan` and `cyan`, `purple` and `fuchsia` are `darkmagenta` and `magenta`, and `brown` is `darkyellow`. It would be nice to have these names also available.



Discussion:
Sounds very reasonable.


Resolving patch:
diff --git a/beets/ui/__init__.py b/beets/ui/__init__.py
--- a/beets/ui/__init__.py
+++ b/beets/ui/__init__.py
@@ -376,10 +376,31 @@ def human_seconds_short(interval):
 # http://dev.pocoo.org/hg/pygments-main/file/b2deea5b5030/pygments/console.py
 # (pygments is by Tim Hatch, Armin Ronacher, et al.)
 COLOR_ESCAPE = "\x1b["
-DARK_COLORS = ["black", "darkred", "darkgreen", "brown", "darkblue",
-               "purple", "teal", "lightgray"]
-LIGHT_COLORS = ["darkgray", "red", "green", "yellow", "blue",
-                "fuchsia", "turquoise", "white"]
+DARK_COLORS = {
+    "black": 0,
+    "darkred": 1,
+    "darkgreen": 2,
+    "brown": 3,
+    "darkyellow": 3,
+    "darkblue": 4,
+    "purple": 5,
+    "darkmagenta": 5,
+    "teal": 6,
+    "darkcyan": 6,
+    "lightgray": 7
+}
+LIGHT_COLORS = {
+    "darkgray": 0,
+    "red": 1,
+    "green": 2,
+    "yellow": 3,
+    "blue": 4,
+    "fuchsia": 5,
+    "magenta": 5,
+    "turquoise": 6,
+    "cyan": 6,
+    "white": 7
+}
 RESET_COLOR = COLOR_ESCAPE + "39;49;00m"
 
 # These abstract COLOR_NAMES are lazily mapped on to the actual color in COLORS
@@ -395,9 +416,9 @@ def _colorize(color, text):
     in DARK_COLORS or LIGHT_COLORS.
     """
     if color in DARK_COLORS:
-        escape = COLOR_ESCAPE + "%im" % (DARK_COLORS.index(color) + 30)
+        escape = COLOR_ESCAPE + "%im" % (DARK_COLORS[color] + 30)
     elif color in LIGHT_COLORS:
-        escape = COLOR_ESCAPE + "%i;01m" % (LIGHT_COLORS.index(color) + 30)
+        escape = COLOR_ESCAPE + "%i;01m" % (LIGHT_COLORS[color] + 30)
     else:
         raise ValueError('no such color %s', color)
     return escape + text + RESET_COLOR


Test patch: