We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN 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?


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `beetsplug/ftintitle.py`
Content:
```
1 # This file is part of beets.
2 # Copyright 2013, Verrus, <github.com/Verrus/beets-plugin-featInTitle>
3 #
4 # Permission is hereby granted, free of charge, to any person obtaining
5 # a copy of this software and associated documentation files (the
6 # "Software"), to deal in the Software without restriction, including
7 # without limitation the rights to use, copy, modify, merge, publish,
8 # distribute, sublicense, and/or sell copies of the Software, and to
9 # permit persons to whom the Software is furnished to do so, subject to
10 # the following conditions:
11 #
12 # The above copyright notice and this permission notice shall be
13 # included in all copies or substantial portions of the Software.
14 
15 """Moves "featured" artists to the title from the artist field.
16 """
17 from beets import plugins
18 from beets import ui
19 from beets.util import displayable_path
20 from beets import config
21 import logging
22 import re
23 
24 log = logging.getLogger('beets')
25 
26 
27 def split_on_feat(artist):
28     """Given an artist string, split the "main" artist from any artist
29     on the right-hand side of a string like "feat". Return the main
30     artist, which is always a string, and the featuring artist, which
31     may be a string or None if none is present.
32     """
33     # split on the first "feat".
34     regex = re.compile(plugins.feat_tokens(), re.IGNORECASE)
35     parts = [s.strip() for s in regex.split(artist, 1)]
36     if len(parts) == 1:
37         return parts[0], None
38     else:
39         return tuple(parts)
40 
41 
42 def contains_feat(title):
43     """Determine whether the title contains a "featured" marker.
44     """
45     return bool(re.search(plugins.feat_tokens(), title, flags=re.IGNORECASE))
46 
47 
48 def update_metadata(item, feat_part, drop_feat, loglevel=logging.DEBUG):
49     """Choose how to add new artists to the title and set the new
50     metadata. Also, print out messages about any changes that are made.
51     If `drop_feat` is set, then do not add the artist to the title; just
52     remove it from the artist field.
53     """
54     # In all cases, update the artist fields.
55     log.log(loglevel, u'artist: {0} -> {1}'.format(
56         item.artist, item.albumartist))
57     item.artist = item.albumartist
58     if item.artist_sort:
59         # Just strip the featured artist from the sort name.
60         item.artist_sort, _ = split_on_feat(item.artist_sort)
61 
62     # Only update the title if it does not already contain a featured
63     # artist and if we do not drop featuring information.
64     if not drop_feat and not contains_feat(item.title):
65         new_title = u"{0} feat. {1}".format(item.title, feat_part)
66         log.log(loglevel, u'title: {0} -> {1}'.format(item.title, new_title))
67         item.title = new_title
68 
69 
70 def ft_in_title(item, drop_feat, loglevel=logging.DEBUG):
71     """Look for featured artists in the item's artist fields and move
72     them to the title.
73     """
74     artist = item.artist.strip()
75     albumartist = item.albumartist.strip()
76 
77     # Check whether there is a featured artist on this track and the
78     # artist field does not exactly match the album artist field. In
79     # that case, we attempt to move the featured artist to the title.
80     _, featured = split_on_feat(artist)
81     if featured and albumartist != artist and albumartist:
82         log.log(loglevel, displayable_path(item.path))
83         feat_part = None
84 
85         # Look for the album artist in the artist field. If it's not
86         # present, give up.
87         albumartist_split = artist.split(albumartist)
88         if len(albumartist_split) <= 1:
89             log.log(loglevel, 'album artist not present in artist')
90 
91         # If the last element of the split (the right-hand side of the
92         # album artist) is nonempty, then it probably contains the
93         # featured artist.
94         elif albumartist_split[-1] != '':
95             # Extract the featured artist from the right-hand side.
96             _, feat_part = split_on_feat(albumartist_split[-1])
97 
98         # Otherwise, if there's nothing on the right-hand side, look for a
99         # featuring artist on the left-hand side.
100         else:
101             lhs, rhs = split_on_feat(albumartist_split[0])
102             if rhs:
103                 feat_part = lhs
104 
105         # If we have a featuring artist, move it to the title.
106         if feat_part:
107             update_metadata(item, feat_part, drop_feat, loglevel)
108         else:
109             log.log(loglevel, u'no featuring artists found')
110 
111 
112 class FtInTitlePlugin(plugins.BeetsPlugin):
113     def __init__(self):
114         super(FtInTitlePlugin, self).__init__()
115 
116         self.config.add({
117             'auto': True,
118             'drop': False,
119         })
120 
121         self._command = ui.Subcommand(
122             'ftintitle',
123             help='move featured artists to the title field')
124 
125         self._command.parser.add_option(
126             '-d', '--drop', dest='drop',
127             action='store_true', default=False,
128             help='drop featuring from artists and ignore title update')
129 
130         if self.config['auto']:
131             self.import_stages = [self.imported]
132 
133     def commands(self):
134 
135         def func(lib, opts, args):
136             self.config.set_args(opts)
137             drop_feat = self.config['drop'].get(bool)
138             write = config['import']['write'].get(bool)
139 
140             for item in lib.items(ui.decargs(args)):
141                 ft_in_title(item, drop_feat, logging.INFO)
142                 item.store()
143                 if write:
144                     item.try_write()
145 
146         self._command.func = func
147         return [self._command]
148 
149     def imported(self, session, task):
150         """Import hook for moving featuring artist automatically.
151         """
152         drop_feat = self.config['drop'].get(bool)
153 
154         for item in task.imported_items():
155             ft_in_title(item, drop_feat, logging.DEBUG)
156             item.store()
157
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/beetsplug/ftintitle.py b/beetsplug/ftintitle.py
--- a/beetsplug/ftintitle.py
+++ b/beetsplug/ftintitle.py
@@ -83,7 +83,7 @@
 
         # 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')

{"golden_diff": "diff --git a/beetsplug/ftintitle.py b/beetsplug/ftintitle.py\n--- a/beetsplug/ftintitle.py\n+++ b/beetsplug/ftintitle.py\n@@ -83,7 +83,7 @@\n \n         # Look for the album artist in the artist field. If it's not\n         # present, give up.\n-        albumartist_split = artist.split(albumartist)\n+        albumartist_split = artist.split(albumartist, 1)\n         if len(albumartist_split) <= 1:\n             ui.print_('album artist not present in artist')\n", "issue": "ftintitle: does not gracefully handle duplicate artist name\nUsing 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.\n\n```\nArtist: The Roots feat. Talib Kweli / The Roots\nAlbum Artist: The Roots\n```\n\nWhen 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 / ', '']`.\n\nThe 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. \n\nIf 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`.\n\nBoth elements `0` and `2` are blank, so no featured part is found.\n\nI've thought of two solutions, but am not sure which one would make more sense\n- Attempt to remove duplicate album artists from the artist string before splitting\n- Add another/change the current case to iterate over the split parts to find the first non-blank item\n\nEither 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.\n\nThoughts?\n\n", "before_files": [{"content": "# This file is part of beets.\n# Copyright 2013, Verrus, <github.com/Verrus/beets-plugin-featInTitle>\n#\n# Permission is hereby granted, free of charge, to any person obtaining\n# a copy of this software and associated documentation files (the\n# \"Software\"), to deal in the Software without restriction, including\n# without limitation the rights to use, copy, modify, merge, publish,\n# distribute, sublicense, and/or sell copies of the Software, and to\n# permit persons to whom the Software is furnished to do so, subject to\n# the following conditions:\n#\n# The above copyright notice and this permission notice shall be\n# included in all copies or substantial portions of the Software.\n\n\"\"\"Moves \"featured\" artists to the title from the artist field.\n\"\"\"\nfrom beets import plugins\nfrom beets import ui\nfrom beets.util import displayable_path\nfrom beets import config\nimport logging\nimport re\n\nlog = logging.getLogger('beets')\n\n\ndef split_on_feat(artist):\n    \"\"\"Given an artist string, split the \"main\" artist from any artist\n    on the right-hand side of a string like \"feat\". Return the main\n    artist, which is always a string, and the featuring artist, which\n    may be a string or None if none is present.\n    \"\"\"\n    # split on the first \"feat\".\n    regex = re.compile(plugins.feat_tokens(), re.IGNORECASE)\n    parts = [s.strip() for s in regex.split(artist, 1)]\n    if len(parts) == 1:\n        return parts[0], None\n    else:\n        return tuple(parts)\n\n\ndef contains_feat(title):\n    \"\"\"Determine whether the title contains a \"featured\" marker.\n    \"\"\"\n    return bool(re.search(plugins.feat_tokens(), title, flags=re.IGNORECASE))\n\n\ndef update_metadata(item, feat_part, drop_feat, loglevel=logging.DEBUG):\n    \"\"\"Choose how to add new artists to the title and set the new\n    metadata. Also, print out messages about any changes that are made.\n    If `drop_feat` is set, then do not add the artist to the title; just\n    remove it from the artist field.\n    \"\"\"\n    # In all cases, update the artist fields.\n    log.log(loglevel, u'artist: {0} -> {1}'.format(\n        item.artist, item.albumartist))\n    item.artist = item.albumartist\n    if item.artist_sort:\n        # Just strip the featured artist from the sort name.\n        item.artist_sort, _ = split_on_feat(item.artist_sort)\n\n    # Only update the title if it does not already contain a featured\n    # artist and if we do not drop featuring information.\n    if not drop_feat and not contains_feat(item.title):\n        new_title = u\"{0} feat. {1}\".format(item.title, feat_part)\n        log.log(loglevel, u'title: {0} -> {1}'.format(item.title, new_title))\n        item.title = new_title\n\n\ndef ft_in_title(item, drop_feat, loglevel=logging.DEBUG):\n    \"\"\"Look for featured artists in the item's artist fields and move\n    them to the title.\n    \"\"\"\n    artist = item.artist.strip()\n    albumartist = item.albumartist.strip()\n\n    # Check whether there is a featured artist on this track and the\n    # artist field does not exactly match the album artist field. In\n    # that case, we attempt to move the featured artist to the title.\n    _, featured = split_on_feat(artist)\n    if featured and albumartist != artist and albumartist:\n        log.log(loglevel, displayable_path(item.path))\n        feat_part = None\n\n        # Look for the album artist in the artist field. If it's not\n        # present, give up.\n        albumartist_split = artist.split(albumartist)\n        if len(albumartist_split) <= 1:\n            log.log(loglevel, 'album artist not present in artist')\n\n        # If the last element of the split (the right-hand side of the\n        # album artist) is nonempty, then it probably contains the\n        # featured artist.\n        elif albumartist_split[-1] != '':\n            # Extract the featured artist from the right-hand side.\n            _, feat_part = split_on_feat(albumartist_split[-1])\n\n        # Otherwise, if there's nothing on the right-hand side, look for a\n        # featuring artist on the left-hand side.\n        else:\n            lhs, rhs = split_on_feat(albumartist_split[0])\n            if rhs:\n                feat_part = lhs\n\n        # If we have a featuring artist, move it to the title.\n        if feat_part:\n            update_metadata(item, feat_part, drop_feat, loglevel)\n        else:\n            log.log(loglevel, u'no featuring artists found')\n\n\nclass FtInTitlePlugin(plugins.BeetsPlugin):\n    def __init__(self):\n        super(FtInTitlePlugin, self).__init__()\n\n        self.config.add({\n            'auto': True,\n            'drop': False,\n        })\n\n        self._command = ui.Subcommand(\n            'ftintitle',\n            help='move featured artists to the title field')\n\n        self._command.parser.add_option(\n            '-d', '--drop', dest='drop',\n            action='store_true', default=False,\n            help='drop featuring from artists and ignore title update')\n\n        if self.config['auto']:\n            self.import_stages = [self.imported]\n\n    def commands(self):\n\n        def func(lib, opts, args):\n            self.config.set_args(opts)\n            drop_feat = self.config['drop'].get(bool)\n            write = config['import']['write'].get(bool)\n\n            for item in lib.items(ui.decargs(args)):\n                ft_in_title(item, drop_feat, logging.INFO)\n                item.store()\n                if write:\n                    item.try_write()\n\n        self._command.func = func\n        return [self._command]\n\n    def imported(self, session, task):\n        \"\"\"Import hook for moving featuring artist automatically.\n        \"\"\"\n        drop_feat = self.config['drop'].get(bool)\n\n        for item in task.imported_items():\n            ft_in_title(item, drop_feat, logging.DEBUG)\n            item.store()\n", "path": "beetsplug/ftintitle.py"}], "after_files": [{"content": "# This file is part of beets.\n# Copyright 2013, Verrus, <github.com/Verrus/beets-plugin-featInTitle>\n#\n# Permission is hereby granted, free of charge, to any person obtaining\n# a copy of this software and associated documentation files (the\n# \"Software\"), to deal in the Software without restriction, including\n# without limitation the rights to use, copy, modify, merge, publish,\n# distribute, sublicense, and/or sell copies of the Software, and to\n# permit persons to whom the Software is furnished to do so, subject to\n# the following conditions:\n#\n# The above copyright notice and this permission notice shall be\n# included in all copies or substantial portions of the Software.\n\n\"\"\"Moves \"featured\" artists to the title from the artist field.\n\"\"\"\nfrom beets import plugins\nfrom beets import ui\nfrom beets.util import displayable_path\nfrom beets import config\nimport logging\nimport re\n\nlog = logging.getLogger('beets')\n\n\ndef split_on_feat(artist):\n    \"\"\"Given an artist string, split the \"main\" artist from any artist\n    on the right-hand side of a string like \"feat\". Return the main\n    artist, which is always a string, and the featuring artist, which\n    may be a string or None if none is present.\n    \"\"\"\n    # split on the first \"feat\".\n    regex = re.compile(plugins.feat_tokens(), re.IGNORECASE)\n    parts = [s.strip() for s in regex.split(artist, 1)]\n    if len(parts) == 1:\n        return parts[0], None\n    else:\n        return tuple(parts)\n\n\ndef contains_feat(title):\n    \"\"\"Determine whether the title contains a \"featured\" marker.\n    \"\"\"\n    return bool(re.search(plugins.feat_tokens(), title, flags=re.IGNORECASE))\n\n\ndef update_metadata(item, feat_part, drop_feat):\n    \"\"\"Choose how to add new artists to the title and set the new\n    metadata. Also, print out messages about any changes that are made.\n    If `drop_feat` is set, then do not add the artist to the title; just\n    remove it from the artist field.\n    \"\"\"\n    # In all cases, update the artist fields.\n    ui.print_(u'artist: {0} -> {1}'.format(item.artist, item.albumartist))\n    item.artist = item.albumartist\n    if item.artist_sort:\n        # Just strip the featured artist from the sort name.\n        item.artist_sort, _ = split_on_feat(item.artist_sort)\n\n    # Only update the title if it does not already contain a featured\n    # artist and if we do not drop featuring information.\n    if not drop_feat and not contains_feat(item.title):\n        new_title = u\"{0} feat. {1}\".format(item.title, feat_part)\n        ui.print_(u'title: {0} -> {1}'.format(item.title, new_title))\n        item.title = new_title\n\n\ndef ft_in_title(item, drop_feat):\n    \"\"\"Look for featured artists in the item's artist fields and move\n    them to the title.\n    \"\"\"\n    artist = item.artist.strip()\n    albumartist = item.albumartist.strip()\n\n    # Check whether there is a featured artist on this track and the\n    # artist field does not exactly match the album artist field. In\n    # that case, we attempt to move the featured artist to the title.\n    _, featured = split_on_feat(artist)\n    if featured and albumartist != artist and albumartist:\n        ui.print_(displayable_path(item.path))\n        feat_part = None\n\n        # Look for the album artist in the artist field. If it's not\n        # present, give up.\n        albumartist_split = artist.split(albumartist, 1)\n        if len(albumartist_split) <= 1:\n            ui.print_('album artist not present in artist')\n\n        # If the last element of the split (the right-hand side of the\n        # album artist) is nonempty, then it probably contains the\n        # featured artist.\n        elif albumartist_split[-1] != '':\n            # Extract the featured artist from the right-hand side.\n            _, feat_part = split_on_feat(albumartist_split[-1])\n\n        # Otherwise, if there's nothing on the right-hand side, look for a\n        # featuring artist on the left-hand side.\n        else:\n            lhs, rhs = split_on_feat(albumartist_split[0])\n            if rhs:\n                feat_part = lhs\n\n        # If we have a featuring artist, move it to the title.\n        if feat_part:\n            update_metadata(item, feat_part, drop_feat)\n        else:\n            ui.print_(u'no featuring artists found')\n\n        ui.print_()\n\n\nclass FtInTitlePlugin(plugins.BeetsPlugin):\n    def __init__(self):\n        super(FtInTitlePlugin, self).__init__()\n\n        self.config.add({\n            'auto': True,\n            'drop': False,\n        })\n\n        self._command = ui.Subcommand(\n            'ftintitle',\n            help='move featured artists to the title field')\n\n        self._command.parser.add_option(\n            '-d', '--drop', dest='drop',\n            action='store_true', default=False,\n            help='drop featuring from artists and ignore title update')\n\n        if self.config['auto']:\n            self.import_stages = [self.imported]\n\n    def commands(self):\n\n        def func(lib, opts, args):\n            self.config.set_args(opts)\n            drop_feat = self.config['drop'].get(bool)\n            write = config['import']['write'].get(bool)\n\n            for item in lib.items(ui.decargs(args)):\n                ft_in_title(item, drop_feat)\n                item.store()\n                if write:\n                    item.try_write()\n\n        self._command.func = func\n        return [self._command]\n\n    def imported(self, session, task):\n        \"\"\"Import hook for moving featuring artist automatically.\n        \"\"\"\n        drop_feat = self.config['drop'].get(bool)\n\n        for item in task.imported_items():\n            ft_in_title(item, drop_feat)\n            item.store()\n", "path": "beetsplug/ftintitle.py"}]}