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

Issue:
Fetch MusicBrainz track disambiguation field
I download a lot of singletons, and I use the track disambiguation notes frequently. I saw that Beets has a way to note the **album** disambig, but not the **track** disambig. Can this be inserted into a future release? This way, my beets.yaml config could look something like this:

`paths:
    default: $albumartist_sort/[$year] $album/$track. $artist- $title
    comp: Various Artists/[$year] $album/$track. $artist- $title
    singleton: $artist_sort/$artist- $title [$trackdisambig]
`



Discussion:
Yes, sounds like a very reasonable addition.


Resolving patch:
diff --git a/beets/autotag/mb.py b/beets/autotag/mb.py
--- a/beets/autotag/mb.py
+++ b/beets/autotag/mb.py
@@ -223,6 +223,8 @@ def track_info(recording, index=None, medium=None, medium_index=None,
     if recording.get('length'):
         info.length = int(recording['length']) / (1000.0)
 
+    info.trackdisambig = recording.get('disambiguation')
+
     lyricist = []
     composer = []
     composer_sort = []
diff --git a/beets/library.py b/beets/library.py
--- a/beets/library.py
+++ b/beets/library.py
@@ -477,6 +477,7 @@ class Item(LibModel):
         'mb_artistid':          types.STRING,
         'mb_albumartistid':     types.STRING,
         'mb_releasetrackid':    types.STRING,
+        'trackdisambig':        types.STRING,
         'albumtype':            types.STRING,
         'label':                types.STRING,
         'acoustid_fingerprint': types.STRING,


Test patch:
diff --git a/test/test_mb.py b/test/test_mb.py
--- a/test/test_mb.py
+++ b/test/test_mb.py
@@ -111,7 +111,8 @@ def _make_release(self, date_str='2009', tracks=None, track_length=None,
         })
         return release
 
-    def _make_track(self, title, tr_id, duration, artist=False, video=False):
+    def _make_track(self, title, tr_id, duration, artist=False, video=False,
+                    disambiguation=None):
         track = {
             'title': title,
             'id': tr_id,
@@ -131,6 +132,8 @@ def _make_track(self, title, tr_id, duration, artist=False, video=False):
             ]
         if video:
             track['video'] = 'true'
+        if disambiguation:
+            track['disambiguation'] = disambiguation
         return track
 
     def test_parse_release_with_year(self):
@@ -445,6 +448,18 @@ def test_no_skip_video_data_tracks_if_configured(self):
         self.assertEqual(d.tracks[1].title, 'TITLE TWO')
         self.assertEqual(d.tracks[2].title, 'TITLE VIDEO')
 
+    def test_track_disambiguation(self):
+        tracks = [self._make_track('TITLE ONE', 'ID ONE', 100.0 * 1000.0),
+                  self._make_track('TITLE TWO', 'ID TWO', 200.0 * 1000.0,
+                                   disambiguation="SECOND TRACK")]
+        release = self._make_release(tracks=tracks)
+
+        d = mb.album_info(release)
+        t = d.tracks
+        self.assertEqual(len(t), 2)
+        self.assertEqual(t[0].trackdisambig, None)
+        self.assertEqual(t[1].trackdisambig, "SECOND TRACK")
+
 
 class ParseIDTest(_common.TestCase):
     def test_parse_id_correct(self):
Repository: beetbox/beets

Issue:
Lyrics plugin crashing on tekstowo.pl
I just found it crashing while searching tekstowo.pl (I'm on https://github.com/beetbox/beets/commit/afc072801c4a254e6b4114d89133d6bebc3e34b9).

These are the relevant lines of error.

```
    return html.find("div", class_="song-text").get_text()
AttributeError: 'NoneType' object has no attribute 'get_text'
```

I also printed the html to the console, but I am unsure why the error is appearing. The div with the class song-text seems to exist and I've never worked on beets before. Could it have something to do with there being two divs with the class?

I uploaded the html, but had to do it with txt extension due to GitHub limitations.

[temp.txt](https://github.com/beetbox/beets/files/6292601/temp.txt)

_Originally posted by @njelich in https://github.com/beetbox/beets/issues/3903#issuecomment-817359091_


Discussion:
Paging @xhocquet, as per the other issue.
Looking!

Resolving patch:
diff --git a/beetsplug/lyrics.py b/beetsplug/lyrics.py
--- a/beetsplug/lyrics.py
+++ b/beetsplug/lyrics.py
@@ -437,8 +437,14 @@ def parse_search_results(self, html):
         except HTMLParseError:
             return None
 
-        song_row = html.find("div", class_="content"). \
-            find_all("div", class_="box-przeboje")[0]
+        song_rows = html.find("div", class_="content"). \
+            find("div", class_="card"). \
+            find_all("div", class_="box-przeboje")
+
+        if not song_rows:
+            return None
+
+        song_row = song_rows[0]
 
         if not song_row:
             return None


Test patch:
Repository: beetbox/beets

Issue:
import: Support importing .7z archives
### Use case

I'm trying to use beets to import music currently bundled in .7z archives.

### Solution

Should work similar to how importing of .zip and .rar etc. works.

### Alternatives

There is currently a beets feature supporting import for archives, however, it doesn’t (currently) support .7z archives. There seem to be some Python libraries available for handling .7z/LZMA, but not sure if any of them are directly usable by beets (ie., they don’t seem to share a similar interface to the current archive extractors from a cursory glance).


Discussion:
Sounds like a nice addition! If you've already done some research on 7z libraries, maybe you could link them here? That might be useful for anyone who's interested in implementing it. I don't think the current unzipping stage is set in stone, see also the discussion in https://github.com/beetbox/beets/issues/3538.
I have not done much more research than going to https://pypi.org/search/?q=lzma and https://pypi.org/search/?q=7z and looking at some of the modules, trying to see if they had a similar API to what is currently used by beets. Don’t remember which specific ones I looked at.

Resolving patch:
diff --git a/beets/importer.py b/beets/importer.py
--- a/beets/importer.py
+++ b/beets/importer.py
@@ -1054,6 +1054,12 @@ def handlers(cls):
                 pass
             else:
                 cls._handlers.append((is_rarfile, RarFile))
+            try:
+                from py7zr import is_7zfile, SevenZipFile
+            except ImportError:
+                pass
+            else:
+                cls._handlers.append((is_7zfile, SevenZipFile))
 
         return cls._handlers
 
diff --git a/setup.py b/setup.py
--- a/setup.py
+++ b/setup.py
@@ -130,7 +130,9 @@ def build_manpages():
         ] + [
             'discogs-client' if (sys.version_info < (3, 0, 0))
             else 'python3-discogs-client'
-        ],
+        ] + (
+            ['py7zr'] if (sys.version_info > (3, 5, 0)) else []
+        ),
         'lint': [
             'flake8',
             'flake8-coding',


Test patch:
diff --git a/test/rsrc/archive.7z b/test/rsrc/archive.7z
new file mode 100644
Binary files /dev/null and b/test/rsrc/archive.7z differ
diff --git a/test/test_importer.py b/test/test_importer.py
--- a/test/test_importer.py
+++ b/test/test_importer.py
@@ -450,6 +450,12 @@ def create_archive(self):
         return os.path.join(_common.RSRC, b'archive.rar')
 
 
+class Import7zTest(ImportZipTest):
+
+    def create_archive(self):
+        return os.path.join(_common.RSRC, b'archive.7z')
+
+
 @unittest.skip('Implement me!')
 class ImportPasswordRarTest(ImportZipTest):
Repository: beetbox/beets

Issue:
unimported: Add an option to ignore some folders
I use a hard drive as my Beets library 'folder'. 
Because of its size I also store some other non-imported music folders on that drive.
I ran into the situation that running 'beets unimported' showed me all the files in those unimported folders. 
It's logical that the plugin scans those too but a more specific scan would be great.
I could circumvent this by placing all Beets folders in another folder instead of the root of the drive but that would make for a deeper hierarchy which I wouldn't like.

### Proposed solution

Add extra options for the command line
`beets unimported /specific_folder`
or in config.yaml
```
unimported:
    ignore_folders: folder-with-non-imported-files
```


Discussion:
To clarify, do you mean to refer to the [unimported](https://beets.readthedocs.io/en/stable/plugins/unimported.html) plugin? (Not the lyrics plugin, which seems unrelated?)
> To clarify, do you mean to refer to the [unimported](https://beets.readthedocs.io/en/stable/plugins/unimported.html) plugin? (Not the lyrics plugin, which seems unrelated?)

Yes my bad, I was caught up in two separate cases. I corrected the first post.
Cool; thanks. I think a config option for this plugin to ignore some directories seems perfectly reasonable.
I opened #4086 for this, let me know your thoughts

Resolving patch:
diff --git a/beetsplug/unimported.py b/beetsplug/unimported.py
--- a/beetsplug/unimported.py
+++ b/beetsplug/unimported.py
@@ -38,13 +38,23 @@ def __init__(self):
 
     def commands(self):
         def print_unimported(lib, opts, args):
-            ignore_exts = [('.' + x).encode() for x
-                           in self.config['ignore_extensions'].as_str_seq()]
+            ignore_exts = [
+                ('.' + x).encode()
+                for x in self.config["ignore_extensions"].as_str_seq()
+            ]
+            ignore_dirs = [
+                os.path.join(lib.directory, x.encode())
+                for x in self.config["ignore_subdirectories"].as_str_seq()
+            ]
             in_folder = {
-                os.path.join(r, file) for r, d, f in os.walk(lib.directory)
-                for file in f if not any(
-                    [file.endswith(extension) for extension in
-                     ignore_exts])}
+                os.path.join(r, file)
+                for r, d, f in os.walk(lib.directory)
+                for file in f
+                if not any(
+                    [file.endswith(ext) for ext in ignore_exts]
+                    + [r in ignore_dirs]
+                )
+            }
             in_library = {x.path for x in lib.items()}
             art_files = {x.artpath for x in lib.albums()}
             for f in in_folder - in_library - art_files:


Test patch:
Repository: beetbox/beets

Issue:
None
None


Discussion:
Good question! Could you please email me directly at adrian@radbox.org?

Resolving patch:
diff --git a/beetsplug/aura.py b/beetsplug/aura.py
--- a/beetsplug/aura.py
+++ b/beetsplug/aura.py
@@ -17,6 +17,7 @@
 
 from mimetypes import guess_type
 import re
+import os.path
 from os.path import isfile, getsize
 
 from beets.plugins import BeetsPlugin
@@ -595,6 +596,24 @@ def single_resource(self, artist_id):
         return self.single_resource_document(artist_resource)
 
 
+def safe_filename(fn):
+    """Check whether a string is a simple (non-path) filename.
+
+    For example, `foo.txt` is safe because it is a "plain" filename. But
+    `foo/bar.txt` and `../foo.txt` and `.` are all non-safe because they
+    can traverse to other directories other than the current one.
+    """
+    # Rule out any directories.
+    if os.path.basename(fn) != fn:
+        return False
+
+    # In single names, rule out Unix directory traversal names.
+    if fn in ('.', '..'):
+        return False
+
+    return True
+
+
 class ImageDocument(AURADocument):
     """Class for building documents for /images/(id) endpoints."""
 
@@ -616,6 +635,8 @@ def get_image_path(image_id):
         parent_type = id_split[0]
         parent_id = id_split[1]
         img_filename = "-".join(id_split[2:])
+        if not safe_filename(img_filename):
+            return None
 
         # Get the path to the directory parent's images are in
         if parent_type == "album":
@@ -631,7 +652,7 @@ def get_image_path(image_id):
             # Images for other resource types are not supported
             return None
 
-        img_path = dir_path + "/" + img_filename
+        img_path = os.path.join(dir_path, img_filename)
         # Check the image actually exists
         if isfile(img_path):
             return img_path


Test patch:
Repository: beetbox/beets

Issue:
[Lyrics Plugin] Genius failed to find artist
Hi, uppon requesting lyrics with beet -vv lyrics the genius source always fails and regardless of artist and song always gives this message.
In the Case of Halsey:
`lyrics: Genius failed to find a matching artist for 'Halsey'`
Maybe this is a problem with how the plugin handles Charactersets or smth, since on the regular Genius Site Lyrics for this song exist. 


Discussion:
That's odd! To try debugging this, you might try seeing what a search like `https://api.genius.com/search?q=Halsey` produces directly from the Genius API. You'll need to provide an API key (you could try using beets's own, which is in its source code) and figure out the appropriate curl or httpie incantation to authenticate the request.
Sorry for the late answer. I could find the API key in lyrics.py but sadly I wasn't able to figure out how to make the proper request. I however would really like to have genius lyrics in the file tags, and solve this problem. Is there any other way I could debug this?
> Sorry for the late answer. I could find the API key in lyrics.py but sadly I wasn't able to figure out how to make the proper request. I however would really like to have genius lyrics in the file tags, and solve this problem. Is there any other way I could debug this?

There are a few related comments at the bottom of https://github.com/beetbox/beets/issues/3903 (fwiw, the query still doesn't seem to work for me...)
I had tried some other curl commands  but none worked for me using the given API key. One time though beet lyrics worked for a very short time, but pulled the same lyrics for all songs in the album...
After few more tries with various installs this problem still persists. Is there maybe an option to use an own genius api key? Does redacted in this context mean that the genius api key option can't be used any longer or that it will be retired soon? 1.5.1 also seems to include some changes with genius is there a way to upgrade to the unfinished version using pip?
No, "redacted" is just our way of preventing people from accidentally leaking secrets when they post their config online.

To run the latest version from source, there are instructions in the FAQ.
Thanks! Sorry for amount of questions i have. Does it make any difference at all what I pick for redirection url in the genius api panel? Since just putting in a client acess token won't work. But I don't know how to put client id and secret at once
Still haven't figured it out

Resolving patch:
diff --git a/beetsplug/lyrics.py b/beetsplug/lyrics.py
--- a/beetsplug/lyrics.py
+++ b/beetsplug/lyrics.py
@@ -377,7 +377,7 @@ def _search(self, artist, title):
         data = {'q': title + " " + artist.lower()}
         try:
             response = requests.get(
-                search_url, data=data, headers=self.headers)
+                search_url, params=data, headers=self.headers)
         except requests.RequestException as exc:
             self._log.debug('Genius API request failed: {0}', exc)
             return None


Test patch:
Repository: beetbox/beets

Issue:
spotify: Use pagination to fetch beyond the first 50 tracks of a release
Not sure if this is a problem related to the plugin, or if the Spotify API doesn't serve more than 50 tracks per release. The other tracks are reported "Unmatched" during import.


Discussion:
Interesting! Do you know if there's anything to be done about this? (That is, does the API support any method for getting the remaining tracks?)
The [get_album_tracks](https://developer.spotify.com/documentation/web-api/reference/#/operations/get-an-albums-tracks) has a limit of 50 tracks. The API has a field to specify `offset` that can be used to break the album if it has more than 50 tracks. 
Great; thanks! Seems like a (maybe) straightforward feature to add if anyone’s interested.
I wish I could code :)

Looks like Spotify integration needs some love. We should also capture the `albumid` while we are at it. 
I just realized that this may also be a problem for `deezer`. I can only fetch the first 25 tracks per album.

Resolving patch:
diff --git a/beetsplug/spotify.py b/beetsplug/spotify.py
--- a/beetsplug/spotify.py
+++ b/beetsplug/spotify.py
@@ -194,9 +194,16 @@ def album_for_id(self, album_id):
                 )
             )
 
+        tracks_data = album_data['tracks']
+        tracks_items = tracks_data['items']
+        while tracks_data['next']:
+            tracks_data = self._handle_response(requests.get,
+                                                tracks_data['next'])
+            tracks_items.extend(tracks_data['items'])
+
         tracks = []
         medium_totals = collections.defaultdict(int)
-        for i, track_data in enumerate(album_data['tracks']['items'], start=1):
+        for i, track_data in enumerate(tracks_items, start=1):
             track = self._get_track(track_data)
             track.index = i
             medium_totals[track.medium] += 1


Test patch:
Repository: beetbox/beets

Issue:
discogs: discogs_albumid is always 0
Most of my music is imported using the discogs plugin (beets v1.6.0, formerly imported via beets 1.4.9), but the every single discogs_albumid field is equal to 0. I do notice, however, the mb_albumid field contains what should be in discogs_albumid.

E.g.
```
         data_source: Discogs
     discogs_albumid: 0
    discogs_artistid: 1954908
     discogs_labelid: 1085864
    mb_albumartistid: 1954908
          mb_albumid: 10346192
   mb_releasegroupid: 1185315
```

Reproduce this by importing an album and using Discogs as the source. Re-importing will do.


Discussion:
Thanks! I expect that something changed in the Discogs API about reporting IDs, as I mentioned in https://github.com/beetbox/beets/discussions/4224#discussioncomment-1915369:

> It is probably related to #4080. I think #4085 probably should have eliminated `extract_release_id` altogether and replaced it with the new `extract_release_id_regex` or similar.

To debug this, the first step would be to dump out the argument to `extract_release_id` and see what it consists of. If it's a URL, it probably works to just call `extract_release_id_regex` instead.
That works.
@jordanbs have you found the time to open a PR for this? Or can you describe the fix here. I'm also interested in getting this fixed. Thanks :-)

Unfortunately I'm not able to do that.

But you can!

On line 317 of beetsplug/discogs.py, replace `extract_release_id` with `extract_release_id_regex`.

Resolving patch:
diff --git a/beetsplug/discogs.py b/beetsplug/discogs.py
--- a/beetsplug/discogs.py
+++ b/beetsplug/discogs.py
@@ -326,7 +326,7 @@ def get_album_info(self, result):
         else:
             genre = base_genre
 
-        discogs_albumid = self.extract_release_id(result.data.get('uri'))
+        discogs_albumid = self.extract_release_id_regex(result.data.get('uri'))
 
         # Extract information for the optional AlbumInfo fields that are
         # contained on nested discogs fields.
@@ -378,12 +378,6 @@ def format(self, classification):
         else:
             return None
 
-    def extract_release_id(self, uri):
-        if uri:
-            return uri.split("/")[-1]
-        else:
-            return None
-
     def get_tracks(self, tracklist):
         """Returns a list of TrackInfo objects for a discogs tracklist.
         """


Test patch:
diff --git a/test/test_discogs.py b/test/test_discogs.py
--- a/test/test_discogs.py
+++ b/test/test_discogs.py
@@ -337,6 +337,7 @@ def test_parse_tracklist_disctitles(self):
     def test_parse_minimal_release(self):
         """Test parsing of a release with the minimal amount of information."""
         data = {'id': 123,
+                'uri': 'https://www.discogs.com/release/123456-something',
                 'tracklist': [self._make_track('A', '1', '01:01')],
                 'artists': [{'name': 'ARTIST NAME', 'id': 321, 'join': ''}],
                 'title': 'TITLE'}
Repository: beetbox/beets

Issue:
Spotifysync crashes when tracks do not have audio-features
Some tracks in Spotify do not have audio-features. This causes `spotifysync` to crash:

```
spotify: Processing 48/471 tracks - Arijit Singh, Arko - OM - Rashtra Kavach - Seher
error: Spotify API error:
{
  "error" : {
    "status" : 404,
    "message" : "analysis not found"
  }
}
URL:
https://api.spotify.com/v1/audio-features/5pjSpt2mstf5JTf46FbT48
params:
None
```

`spotifysync` should gracefully handle such errors. Maybe we need a try-except block [here](https://github.com/beetbox/beets/blob/master/beetsplug/spotify.py#L622). Thoughts?


Discussion:

Resolving patch:
diff --git a/beetsplug/spotify.py b/beetsplug/spotify.py
--- a/beetsplug/spotify.py
+++ b/beetsplug/spotify.py
@@ -35,6 +35,10 @@
 DEFAULT_WAITING_TIME = 5
 
 
+class SpotifyAPIError(Exception):
+    pass
+
+
 class SpotifyPlugin(MetadataSourcePlugin, BeetsPlugin):
     data_source = 'Spotify'
 
@@ -189,6 +193,9 @@ def _handle_response(self, request_type, url, params=None):
                     seconds.', seconds)
                 time.sleep(int(seconds) + 1)
                 return self._handle_response(request_type, url, params=params)
+            elif response.status_code == 404:
+                raise SpotifyAPIError("API Error {0.status_code} for {1}"
+                                      .format(response, url))
             else:
                 raise ui.UserError(
                     '{} API error:\n{}\nURL:\n{}\nparams:\n{}'.format(
@@ -621,6 +628,9 @@ def _fetch_info(self, items, write, force):
             item['spotify_track_popularity'] = popularity
             audio_features = \
                 self.track_audio_features(spotify_track_id)
+            if audio_features is None:
+                self._log.info('No audio features found for: {}', item)
+                continue
             for feature in audio_features.keys():
                 if feature in self.spotify_audio_features.keys():
                     item[self.spotify_audio_features[feature]] = \
@@ -639,7 +649,9 @@ def track_popularity(self, track_id=None):
 
     def track_audio_features(self, track_id=None):
         """Fetch track audio features by its Spotify ID."""
-        track_data = self._handle_response(
-            requests.get, self.audio_features_url + track_id
-        )
-        return track_data
+        try:
+            return self._handle_response(
+                requests.get, self.audio_features_url + track_id)
+        except SpotifyAPIError as e:
+            self._log.debug('Spotify API error: {}', e)
+            return None


Test patch: