We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
play: Configuration option to include a UTF-8-BOM (and possibly use .m3u8 extension)
### Problem
Currently, the play plugin's generated m3u files don't behave with foobar2000 if they have special characters (i.e. [en dash](https://unicode-table.com/en/2013/) "–"). If I modify the m3u file to have an m3u8 extension and add the appropriate [BOM](https://en.wikipedia.org/wiki/Byte_order_mark), it works just fine.

Running this command in verbose (`-vv`) mode:

```sh
λ beet -vv play -a 009                                                                         
user configuration: C:\Users\mikey\AppData\Roaming\beets\config.yaml                           
data directory: C:\Users\mikey\AppData\Roaming\beets                                           
plugin paths:                                                                                  
Sending event: pluginload                                                                      
library database: D:\beets.db                                                                  
library directory: D:\Music                                                                    
Sending event: library_opened                                                                  
Playing 1 album.                                                                               
play: executing command: foobar2000 ['C:\\Users\\mikey\\AppData\\Local\\Temp\\tmp911i_r7f.m3u']
                                                                                               
```

Led to this problem:

```
Foobar can't find the files specified in the m3u file.
```
The file path attempting to be played is "D:\Music\Compilations\Monstercat 009 – Reunion"


### Setup

* OS: Windows 10 Pro 1803
* Python version: 3.6.4
* beets version: 1.4.6
* Turning off plugins made problem go away (yes/no): N/A

My configuration (output of `beet config`) is:

```yaml
directory: D:\\Music
library: D:\\beets.db

plugins: chroma fetchart mbsync fromfilename web play

import:
    move: yes
    write: yes

replace:
    '[\\/]': _
    ^\.: _
    '[\x00-\x1f]': _
    '[<>:"\?\*\|]': _
    \.$: _
    \s+$: ''
    ^\s+: ''
    ^-: _
play:
    command: foobar2000
    use_folders: no
    relative_to:
    raw: no
    warning_threshold: 100
sort_item: album+ disc+ track+ artist+
fetchart:
    auto: yes
    minwidth: 0
    maxwidth: 0
    enforce_ratio: no
    cautious: no
    cover_names:
    - cover
    - front
    - art
    - album
    - folder
    sources:
    - filesystem
    - coverart
    - itunes
    - amazon
    - albumart
    google_key: REDACTED
    google_engine: 001442825323518660753:hrh5ch1gjzm
    fanarttv_key: REDACTED
    store_source: no
web:
    host: 127.0.0.1
    port: 8337
    cors: ''
    reverse_proxy: no
    include_paths: no
chroma:
    auto: yes
```


--- 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/play.py`
Content:
```
1 # -*- coding: utf-8 -*-
2 # This file is part of beets.
3 # Copyright 2016, David Hamp-Gonsalves
4 #
5 # Permission is hereby granted, free of charge, to any person obtaining
6 # a copy of this software and associated documentation files (the
7 # "Software"), to deal in the Software without restriction, including
8 # without limitation the rights to use, copy, modify, merge, publish,
9 # distribute, sublicense, and/or sell copies of the Software, and to
10 # permit persons to whom the Software is furnished to do so, subject to
11 # the following conditions:
12 #
13 # The above copyright notice and this permission notice shall be
14 # included in all copies or substantial portions of the Software.
15 
16 """Send the results of a query to the configured music player as a playlist.
17 """
18 from __future__ import division, absolute_import, print_function
19 
20 from beets.plugins import BeetsPlugin
21 from beets.ui import Subcommand
22 from beets.ui.commands import PromptChoice
23 from beets import config
24 from beets import ui
25 from beets import util
26 from os.path import relpath
27 from tempfile import NamedTemporaryFile
28 import subprocess
29 
30 # Indicate where arguments should be inserted into the command string.
31 # If this is missing, they're placed at the end.
32 ARGS_MARKER = '$args'
33 
34 
35 def play(command_str, selection, paths, open_args, log, item_type='track',
36          keep_open=False):
37     """Play items in paths with command_str and optional arguments. If
38     keep_open, return to beets, otherwise exit once command runs.
39     """
40     # Print number of tracks or albums to be played, log command to be run.
41     item_type += 's' if len(selection) > 1 else ''
42     ui.print_(u'Playing {0} {1}.'.format(len(selection), item_type))
43     log.debug(u'executing command: {} {!r}', command_str, open_args)
44 
45     try:
46         if keep_open:
47             command = util.shlex_split(command_str)
48             command = command + open_args
49             subprocess.call(command)
50         else:
51             util.interactive_open(open_args, command_str)
52     except OSError as exc:
53         raise ui.UserError(
54             "Could not play the query: {0}".format(exc))
55 
56 
57 class PlayPlugin(BeetsPlugin):
58 
59     def __init__(self):
60         super(PlayPlugin, self).__init__()
61 
62         config['play'].add({
63             'command': None,
64             'use_folders': False,
65             'relative_to': None,
66             'raw': False,
67             'warning_threshold': 100,
68         })
69 
70         self.register_listener('before_choose_candidate',
71                                self.before_choose_candidate_listener)
72 
73     def commands(self):
74         play_command = Subcommand(
75             'play',
76             help=u'send music to a player as a playlist'
77         )
78         play_command.parser.add_album_option()
79         play_command.parser.add_option(
80             u'-A', u'--args',
81             action='store',
82             help=u'add additional arguments to the command',
83         )
84         play_command.parser.add_option(
85             u'-y', u'--yes',
86             action="store_true",
87             help=u'skip the warning threshold',
88         )
89         play_command.func = self._play_command
90         return [play_command]
91 
92     def _play_command(self, lib, opts, args):
93         """The CLI command function for `beet play`. Create a list of paths
94         from query, determine if tracks or albums are to be played.
95         """
96         use_folders = config['play']['use_folders'].get(bool)
97         relative_to = config['play']['relative_to'].get()
98         if relative_to:
99             relative_to = util.normpath(relative_to)
100         # Perform search by album and add folders rather than tracks to
101         # playlist.
102         if opts.album:
103             selection = lib.albums(ui.decargs(args))
104             paths = []
105 
106             sort = lib.get_default_album_sort()
107             for album in selection:
108                 if use_folders:
109                     paths.append(album.item_dir())
110                 else:
111                     paths.extend(item.path
112                                  for item in sort.sort(album.items()))
113             item_type = 'album'
114 
115         # Perform item query and add tracks to playlist.
116         else:
117             selection = lib.items(ui.decargs(args))
118             paths = [item.path for item in selection]
119             item_type = 'track'
120 
121         if relative_to:
122             paths = [relpath(path, relative_to) for path in paths]
123 
124         if not selection:
125             ui.print_(ui.colorize('text_warning',
126                                   u'No {0} to play.'.format(item_type)))
127             return
128 
129         open_args = self._playlist_or_paths(paths)
130         command_str = self._command_str(opts.args)
131 
132         # Check if the selection exceeds configured threshold. If True,
133         # cancel, otherwise proceed with play command.
134         if opts.yes or not self._exceeds_threshold(
135                 selection, command_str, open_args, item_type):
136             play(command_str, selection, paths, open_args, self._log,
137                  item_type)
138 
139     def _command_str(self, args=None):
140         """Create a command string from the config command and optional args.
141         """
142         command_str = config['play']['command'].get()
143         if not command_str:
144             return util.open_anything()
145         # Add optional arguments to the player command.
146         if args:
147             if ARGS_MARKER in command_str:
148                 return command_str.replace(ARGS_MARKER, args)
149             else:
150                 return u"{} {}".format(command_str, args)
151         else:
152             # Don't include the marker in the command.
153             return command_str.replace(" " + ARGS_MARKER, "")
154 
155     def _playlist_or_paths(self, paths):
156         """Return either the raw paths of items or a playlist of the items.
157         """
158         if config['play']['raw']:
159             return paths
160         else:
161             return [self._create_tmp_playlist(paths)]
162 
163     def _exceeds_threshold(self, selection, command_str, open_args,
164                            item_type='track'):
165         """Prompt user whether to abort if playlist exceeds threshold. If
166         True, cancel playback. If False, execute play command.
167         """
168         warning_threshold = config['play']['warning_threshold'].get(int)
169 
170         # Warn user before playing any huge playlists.
171         if warning_threshold and len(selection) > warning_threshold:
172             if len(selection) > 1:
173                 item_type += 's'
174 
175             ui.print_(ui.colorize(
176                 'text_warning',
177                 u'You are about to queue {0} {1}.'.format(
178                     len(selection), item_type)))
179 
180             if ui.input_options((u'Continue', u'Abort')) == 'a':
181                 return True
182 
183         return False
184 
185     def _create_tmp_playlist(self, paths_list):
186         """Create a temporary .m3u file. Return the filename.
187         """
188         m3u = NamedTemporaryFile('wb', suffix='.m3u', delete=False)
189         for item in paths_list:
190             m3u.write(item + b'\n')
191         m3u.close()
192         return m3u.name
193 
194     def before_choose_candidate_listener(self, session, task):
195         """Append a "Play" choice to the interactive importer prompt.
196         """
197         return [PromptChoice('y', 'plaY', self.importer_play)]
198 
199     def importer_play(self, session, task):
200         """Get items from current import task and send to play function.
201         """
202         selection = task.items
203         paths = [item.path for item in selection]
204 
205         open_args = self._playlist_or_paths(paths)
206         command_str = self._command_str()
207 
208         if not self._exceeds_threshold(selection, command_str, open_args):
209             play(command_str, selection, paths, open_args, self._log,
210                  keep_open=True)
211
```
--- 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/play.py b/beetsplug/play.py
--- a/beetsplug/play.py
+++ b/beetsplug/play.py
@@ -65,6 +65,7 @@
             'relative_to': None,
             'raw': False,
             'warning_threshold': 100,
+            'bom': False,
         })
 
         self.register_listener('before_choose_candidate',
@@ -185,7 +186,12 @@
     def _create_tmp_playlist(self, paths_list):
         """Create a temporary .m3u file. Return the filename.
         """
+        utf8_bom = config['play']['bom'].get(bool)
         m3u = NamedTemporaryFile('wb', suffix='.m3u', delete=False)
+
+        if utf8_bom:
+            m3u.write(b'\xEF\xBB\xBF')
+
         for item in paths_list:
             m3u.write(item + b'\n')
         m3u.close()

{"golden_diff": "diff --git a/beetsplug/play.py b/beetsplug/play.py\n--- a/beetsplug/play.py\n+++ b/beetsplug/play.py\n@@ -65,6 +65,7 @@\n             'relative_to': None,\n             'raw': False,\n             'warning_threshold': 100,\n+            'bom': False,\n         })\n \n         self.register_listener('before_choose_candidate',\n@@ -185,7 +186,12 @@\n     def _create_tmp_playlist(self, paths_list):\n         \"\"\"Create a temporary .m3u file. Return the filename.\n         \"\"\"\n+        utf8_bom = config['play']['bom'].get(bool)\n         m3u = NamedTemporaryFile('wb', suffix='.m3u', delete=False)\n+\n+        if utf8_bom:\n+            m3u.write(b'\\xEF\\xBB\\xBF')\n+\n         for item in paths_list:\n             m3u.write(item + b'\\n')\n         m3u.close()\n", "issue": "play: Configuration option to include a UTF-8-BOM (and possibly use .m3u8 extension)\n### Problem\r\nCurrently, the play plugin's generated m3u files don't behave with foobar2000 if they have special characters (i.e. [en dash](https://unicode-table.com/en/2013/) \"\u2013\"). If I modify the m3u file to have an m3u8 extension and add the appropriate [BOM](https://en.wikipedia.org/wiki/Byte_order_mark), it works just fine.\r\n\r\nRunning this command in verbose (`-vv`) mode:\r\n\r\n```sh\r\n\u03bb beet -vv play -a 009                                                                         \r\nuser configuration: C:\\Users\\mikey\\AppData\\Roaming\\beets\\config.yaml                           \r\ndata directory: C:\\Users\\mikey\\AppData\\Roaming\\beets                                           \r\nplugin paths:                                                                                  \r\nSending event: pluginload                                                                      \r\nlibrary database: D:\\beets.db                                                                  \r\nlibrary directory: D:\\Music                                                                    \r\nSending event: library_opened                                                                  \r\nPlaying 1 album.                                                                               \r\nplay: executing command: foobar2000 ['C:\\\\Users\\\\mikey\\\\AppData\\\\Local\\\\Temp\\\\tmp911i_r7f.m3u']\r\n                                                                                               \r\n```\r\n\r\nLed to this problem:\r\n\r\n```\r\nFoobar can't find the files specified in the m3u file.\r\n```\r\nThe file path attempting to be played is \"D:\\Music\\Compilations\\Monstercat 009 \u2013 Reunion\"\r\n\r\n\r\n### Setup\r\n\r\n* OS: Windows 10 Pro 1803\r\n* Python version: 3.6.4\r\n* beets version: 1.4.6\r\n* Turning off plugins made problem go away (yes/no): N/A\r\n\r\nMy configuration (output of `beet config`) is:\r\n\r\n```yaml\r\ndirectory: D:\\\\Music\r\nlibrary: D:\\\\beets.db\r\n\r\nplugins: chroma fetchart mbsync fromfilename web play\r\n\r\nimport:\r\n    move: yes\r\n    write: yes\r\n\r\nreplace:\r\n    '[\\\\/]': _\r\n    ^\\.: _\r\n    '[\\x00-\\x1f]': _\r\n    '[<>:\"\\?\\*\\|]': _\r\n    \\.$: _\r\n    \\s+$: ''\r\n    ^\\s+: ''\r\n    ^-: _\r\nplay:\r\n    command: foobar2000\r\n    use_folders: no\r\n    relative_to:\r\n    raw: no\r\n    warning_threshold: 100\r\nsort_item: album+ disc+ track+ artist+\r\nfetchart:\r\n    auto: yes\r\n    minwidth: 0\r\n    maxwidth: 0\r\n    enforce_ratio: no\r\n    cautious: no\r\n    cover_names:\r\n    - cover\r\n    - front\r\n    - art\r\n    - album\r\n    - folder\r\n    sources:\r\n    - filesystem\r\n    - coverart\r\n    - itunes\r\n    - amazon\r\n    - albumart\r\n    google_key: REDACTED\r\n    google_engine: 001442825323518660753:hrh5ch1gjzm\r\n    fanarttv_key: REDACTED\r\n    store_source: no\r\nweb:\r\n    host: 127.0.0.1\r\n    port: 8337\r\n    cors: ''\r\n    reverse_proxy: no\r\n    include_paths: no\r\nchroma:\r\n    auto: yes\r\n```\r\n\n", "before_files": [{"content": "# -*- coding: utf-8 -*-\n# This file is part of beets.\n# Copyright 2016, David Hamp-Gonsalves\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\"\"\"Send the results of a query to the configured music player as a playlist.\n\"\"\"\nfrom __future__ import division, absolute_import, print_function\n\nfrom beets.plugins import BeetsPlugin\nfrom beets.ui import Subcommand\nfrom beets.ui.commands import PromptChoice\nfrom beets import config\nfrom beets import ui\nfrom beets import util\nfrom os.path import relpath\nfrom tempfile import NamedTemporaryFile\nimport subprocess\n\n# Indicate where arguments should be inserted into the command string.\n# If this is missing, they're placed at the end.\nARGS_MARKER = '$args'\n\n\ndef play(command_str, selection, paths, open_args, log, item_type='track',\n         keep_open=False):\n    \"\"\"Play items in paths with command_str and optional arguments. If\n    keep_open, return to beets, otherwise exit once command runs.\n    \"\"\"\n    # Print number of tracks or albums to be played, log command to be run.\n    item_type += 's' if len(selection) > 1 else ''\n    ui.print_(u'Playing {0} {1}.'.format(len(selection), item_type))\n    log.debug(u'executing command: {} {!r}', command_str, open_args)\n\n    try:\n        if keep_open:\n            command = util.shlex_split(command_str)\n            command = command + open_args\n            subprocess.call(command)\n        else:\n            util.interactive_open(open_args, command_str)\n    except OSError as exc:\n        raise ui.UserError(\n            \"Could not play the query: {0}\".format(exc))\n\n\nclass PlayPlugin(BeetsPlugin):\n\n    def __init__(self):\n        super(PlayPlugin, self).__init__()\n\n        config['play'].add({\n            'command': None,\n            'use_folders': False,\n            'relative_to': None,\n            'raw': False,\n            'warning_threshold': 100,\n        })\n\n        self.register_listener('before_choose_candidate',\n                               self.before_choose_candidate_listener)\n\n    def commands(self):\n        play_command = Subcommand(\n            'play',\n            help=u'send music to a player as a playlist'\n        )\n        play_command.parser.add_album_option()\n        play_command.parser.add_option(\n            u'-A', u'--args',\n            action='store',\n            help=u'add additional arguments to the command',\n        )\n        play_command.parser.add_option(\n            u'-y', u'--yes',\n            action=\"store_true\",\n            help=u'skip the warning threshold',\n        )\n        play_command.func = self._play_command\n        return [play_command]\n\n    def _play_command(self, lib, opts, args):\n        \"\"\"The CLI command function for `beet play`. Create a list of paths\n        from query, determine if tracks or albums are to be played.\n        \"\"\"\n        use_folders = config['play']['use_folders'].get(bool)\n        relative_to = config['play']['relative_to'].get()\n        if relative_to:\n            relative_to = util.normpath(relative_to)\n        # Perform search by album and add folders rather than tracks to\n        # playlist.\n        if opts.album:\n            selection = lib.albums(ui.decargs(args))\n            paths = []\n\n            sort = lib.get_default_album_sort()\n            for album in selection:\n                if use_folders:\n                    paths.append(album.item_dir())\n                else:\n                    paths.extend(item.path\n                                 for item in sort.sort(album.items()))\n            item_type = 'album'\n\n        # Perform item query and add tracks to playlist.\n        else:\n            selection = lib.items(ui.decargs(args))\n            paths = [item.path for item in selection]\n            item_type = 'track'\n\n        if relative_to:\n            paths = [relpath(path, relative_to) for path in paths]\n\n        if not selection:\n            ui.print_(ui.colorize('text_warning',\n                                  u'No {0} to play.'.format(item_type)))\n            return\n\n        open_args = self._playlist_or_paths(paths)\n        command_str = self._command_str(opts.args)\n\n        # Check if the selection exceeds configured threshold. If True,\n        # cancel, otherwise proceed with play command.\n        if opts.yes or not self._exceeds_threshold(\n                selection, command_str, open_args, item_type):\n            play(command_str, selection, paths, open_args, self._log,\n                 item_type)\n\n    def _command_str(self, args=None):\n        \"\"\"Create a command string from the config command and optional args.\n        \"\"\"\n        command_str = config['play']['command'].get()\n        if not command_str:\n            return util.open_anything()\n        # Add optional arguments to the player command.\n        if args:\n            if ARGS_MARKER in command_str:\n                return command_str.replace(ARGS_MARKER, args)\n            else:\n                return u\"{} {}\".format(command_str, args)\n        else:\n            # Don't include the marker in the command.\n            return command_str.replace(\" \" + ARGS_MARKER, \"\")\n\n    def _playlist_or_paths(self, paths):\n        \"\"\"Return either the raw paths of items or a playlist of the items.\n        \"\"\"\n        if config['play']['raw']:\n            return paths\n        else:\n            return [self._create_tmp_playlist(paths)]\n\n    def _exceeds_threshold(self, selection, command_str, open_args,\n                           item_type='track'):\n        \"\"\"Prompt user whether to abort if playlist exceeds threshold. If\n        True, cancel playback. If False, execute play command.\n        \"\"\"\n        warning_threshold = config['play']['warning_threshold'].get(int)\n\n        # Warn user before playing any huge playlists.\n        if warning_threshold and len(selection) > warning_threshold:\n            if len(selection) > 1:\n                item_type += 's'\n\n            ui.print_(ui.colorize(\n                'text_warning',\n                u'You are about to queue {0} {1}.'.format(\n                    len(selection), item_type)))\n\n            if ui.input_options((u'Continue', u'Abort')) == 'a':\n                return True\n\n        return False\n\n    def _create_tmp_playlist(self, paths_list):\n        \"\"\"Create a temporary .m3u file. Return the filename.\n        \"\"\"\n        m3u = NamedTemporaryFile('wb', suffix='.m3u', delete=False)\n        for item in paths_list:\n            m3u.write(item + b'\\n')\n        m3u.close()\n        return m3u.name\n\n    def before_choose_candidate_listener(self, session, task):\n        \"\"\"Append a \"Play\" choice to the interactive importer prompt.\n        \"\"\"\n        return [PromptChoice('y', 'plaY', self.importer_play)]\n\n    def importer_play(self, session, task):\n        \"\"\"Get items from current import task and send to play function.\n        \"\"\"\n        selection = task.items\n        paths = [item.path for item in selection]\n\n        open_args = self._playlist_or_paths(paths)\n        command_str = self._command_str()\n\n        if not self._exceeds_threshold(selection, command_str, open_args):\n            play(command_str, selection, paths, open_args, self._log,\n                 keep_open=True)\n", "path": "beetsplug/play.py"}], "after_files": [{"content": "# -*- coding: utf-8 -*-\n# This file is part of beets.\n# Copyright 2016, David Hamp-Gonsalves\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\"\"\"Send the results of a query to the configured music player as a playlist.\n\"\"\"\nfrom __future__ import division, absolute_import, print_function\n\nfrom beets.plugins import BeetsPlugin\nfrom beets.ui import Subcommand\nfrom beets.ui.commands import PromptChoice\nfrom beets import config\nfrom beets import ui\nfrom beets import util\nfrom os.path import relpath\nfrom tempfile import NamedTemporaryFile\nimport subprocess\n\n# Indicate where arguments should be inserted into the command string.\n# If this is missing, they're placed at the end.\nARGS_MARKER = '$args'\n\n\ndef play(command_str, selection, paths, open_args, log, item_type='track',\n         keep_open=False):\n    \"\"\"Play items in paths with command_str and optional arguments. If\n    keep_open, return to beets, otherwise exit once command runs.\n    \"\"\"\n    # Print number of tracks or albums to be played, log command to be run.\n    item_type += 's' if len(selection) > 1 else ''\n    ui.print_(u'Playing {0} {1}.'.format(len(selection), item_type))\n    log.debug(u'executing command: {} {!r}', command_str, open_args)\n\n    try:\n        if keep_open:\n            command = util.shlex_split(command_str)\n            command = command + open_args\n            subprocess.call(command)\n        else:\n            util.interactive_open(open_args, command_str)\n    except OSError as exc:\n        raise ui.UserError(\n            \"Could not play the query: {0}\".format(exc))\n\n\nclass PlayPlugin(BeetsPlugin):\n\n    def __init__(self):\n        super(PlayPlugin, self).__init__()\n\n        config['play'].add({\n            'command': None,\n            'use_folders': False,\n            'relative_to': None,\n            'raw': False,\n            'warning_threshold': 100,\n            'bom': False,\n        })\n\n        self.register_listener('before_choose_candidate',\n                               self.before_choose_candidate_listener)\n\n    def commands(self):\n        play_command = Subcommand(\n            'play',\n            help=u'send music to a player as a playlist'\n        )\n        play_command.parser.add_album_option()\n        play_command.parser.add_option(\n            u'-A', u'--args',\n            action='store',\n            help=u'add additional arguments to the command',\n        )\n        play_command.parser.add_option(\n            u'-y', u'--yes',\n            action=\"store_true\",\n            help=u'skip the warning threshold',\n        )\n        play_command.func = self._play_command\n        return [play_command]\n\n    def _play_command(self, lib, opts, args):\n        \"\"\"The CLI command function for `beet play`. Create a list of paths\n        from query, determine if tracks or albums are to be played.\n        \"\"\"\n        use_folders = config['play']['use_folders'].get(bool)\n        relative_to = config['play']['relative_to'].get()\n        if relative_to:\n            relative_to = util.normpath(relative_to)\n        # Perform search by album and add folders rather than tracks to\n        # playlist.\n        if opts.album:\n            selection = lib.albums(ui.decargs(args))\n            paths = []\n\n            sort = lib.get_default_album_sort()\n            for album in selection:\n                if use_folders:\n                    paths.append(album.item_dir())\n                else:\n                    paths.extend(item.path\n                                 for item in sort.sort(album.items()))\n            item_type = 'album'\n\n        # Perform item query and add tracks to playlist.\n        else:\n            selection = lib.items(ui.decargs(args))\n            paths = [item.path for item in selection]\n            item_type = 'track'\n\n        if relative_to:\n            paths = [relpath(path, relative_to) for path in paths]\n\n        if not selection:\n            ui.print_(ui.colorize('text_warning',\n                                  u'No {0} to play.'.format(item_type)))\n            return\n\n        open_args = self._playlist_or_paths(paths)\n        command_str = self._command_str(opts.args)\n\n        # Check if the selection exceeds configured threshold. If True,\n        # cancel, otherwise proceed with play command.\n        if opts.yes or not self._exceeds_threshold(\n                selection, command_str, open_args, item_type):\n            play(command_str, selection, paths, open_args, self._log,\n                 item_type)\n\n    def _command_str(self, args=None):\n        \"\"\"Create a command string from the config command and optional args.\n        \"\"\"\n        command_str = config['play']['command'].get()\n        if not command_str:\n            return util.open_anything()\n        # Add optional arguments to the player command.\n        if args:\n            if ARGS_MARKER in command_str:\n                return command_str.replace(ARGS_MARKER, args)\n            else:\n                return u\"{} {}\".format(command_str, args)\n        else:\n            # Don't include the marker in the command.\n            return command_str.replace(\" \" + ARGS_MARKER, \"\")\n\n    def _playlist_or_paths(self, paths):\n        \"\"\"Return either the raw paths of items or a playlist of the items.\n        \"\"\"\n        if config['play']['raw']:\n            return paths\n        else:\n            return [self._create_tmp_playlist(paths)]\n\n    def _exceeds_threshold(self, selection, command_str, open_args,\n                           item_type='track'):\n        \"\"\"Prompt user whether to abort if playlist exceeds threshold. If\n        True, cancel playback. If False, execute play command.\n        \"\"\"\n        warning_threshold = config['play']['warning_threshold'].get(int)\n\n        # Warn user before playing any huge playlists.\n        if warning_threshold and len(selection) > warning_threshold:\n            if len(selection) > 1:\n                item_type += 's'\n\n            ui.print_(ui.colorize(\n                'text_warning',\n                u'You are about to queue {0} {1}.'.format(\n                    len(selection), item_type)))\n\n            if ui.input_options((u'Continue', u'Abort')) == 'a':\n                return True\n\n        return False\n\n    def _create_tmp_playlist(self, paths_list):\n        \"\"\"Create a temporary .m3u file. Return the filename.\n        \"\"\"\n        utf8_bom = config['play']['bom'].get(bool)\n        m3u = NamedTemporaryFile('wb', suffix='.m3u', delete=False)\n\n        if utf8_bom:\n            m3u.write(b'\\xEF\\xBB\\xBF')\n\n        for item in paths_list:\n            m3u.write(item + b'\\n')\n        m3u.close()\n        return m3u.name\n\n    def before_choose_candidate_listener(self, session, task):\n        \"\"\"Append a \"Play\" choice to the interactive importer prompt.\n        \"\"\"\n        return [PromptChoice('y', 'plaY', self.importer_play)]\n\n    def importer_play(self, session, task):\n        \"\"\"Get items from current import task and send to play function.\n        \"\"\"\n        selection = task.items\n        paths = [item.path for item in selection]\n\n        open_args = self._playlist_or_paths(paths)\n        command_str = self._command_str()\n\n        if not self._exceeds_threshold(selection, command_str, open_args):\n            play(command_str, selection, paths, open_args, self._log,\n                 keep_open=True)\n", "path": "beetsplug/play.py"}]}