Prevents this crash:
```
$ beet import ~/Music/Music/_/[1405]/00.mp3
Traceback (most recent call last):
File "/nix/store/lfv9ns20hz2bg6d44js378vcxjfm9261-beets-2.3.1/bin/.beet-wrapped", line 9, in <module>
sys.exit(main())
~~~~^^
File "/nix/store/lfv9ns20hz2bg6d44js378vcxjfm9261-beets-2.3.1/lib/python3.13/site-packages/beets/ui/__init__.py", line 1859, in main
_raw_main(args)
~~~~~~~~~^^^^^^
File "/nix/store/lfv9ns20hz2bg6d44js378vcxjfm9261-beets-2.3.1/lib/python3.13/site-packages/beets/ui/__init__.py", line 1838, in _raw_main
subcommand.func(lib, suboptions, subargs)
~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/nix/store/lfv9ns20hz2bg6d44js378vcxjfm9261-beets-2.3.1/lib/python3.13/site-packages/beets/ui/commands.py", line 1390, in import_func
import_files(lib, byte_paths, query)
~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^
File "/nix/store/lfv9ns20hz2bg6d44js378vcxjfm9261-beets-2.3.1/lib/python3.13/site-packages/beets/ui/commands.py", line 1330, in import_files
session.run()
~~~~~~~~~~~^^
File "/nix/store/lfv9ns20hz2bg6d44js378vcxjfm9261-beets-2.3.1/lib/python3.13/site-packages/beets/importer/session.py", line 234, in run
pl.run_parallel(QUEUE_SIZE)
~~~~~~~~~~~~~~~^^^^^^^^^^^^
File "/nix/store/lfv9ns20hz2bg6d44js378vcxjfm9261-beets-2.3.1/lib/python3.13/site-packages/beets/util/pipeline.py", line 471, in run_parallel
raise exc_info[1].with_traceback(exc_info[2])
File "/nix/store/lfv9ns20hz2bg6d44js378vcxjfm9261-beets-2.3.1/lib/python3.13/site-packages/beets/util/pipeline.py", line 336, in run
out = self.coro.send(msg)
File "/nix/store/lfv9ns20hz2bg6d44js378vcxjfm9261-beets-2.3.1/lib/python3.13/site-packages/beets/util/pipeline.py", line 219, in coro
func(*(args + (task,)))
~~~~^^^^^^^^^^^^^^^^^^^
File "/nix/store/lfv9ns20hz2bg6d44js378vcxjfm9261-beets-2.3.1/lib/python3.13/site-packages/beets/importer/stages.py", line 141, in lookup_candidates
plugins.send("import_task_start", session=session, task=task)
~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/nix/store/lfv9ns20hz2bg6d44js378vcxjfm9261-beets-2.3.1/lib/python3.13/site-packages/beets/plugins.py", line 505, in send
result = handler(**arguments)
File "/nix/store/lfv9ns20hz2bg6d44js378vcxjfm9261-beets-2.3.1/lib/python3.13/site-packages/beets/plugins.py", line 200, in wrapper
return func(*args, **kwargs)
File "/nix/store/lfv9ns20hz2bg6d44js378vcxjfm9261-beets-2.3.1/lib/python3.13/site-packages/beetsplug/fromfilename.py", line 165, in filename_task
apply_matches(d, self._log)
~~~~~~~~~~~~~^^^^^^^^^^^^^^
File "/nix/store/lfv9ns20hz2bg6d44js378vcxjfm9261-beets-2.3.1/lib/python3.13/site-packages/beetsplug/fromfilename.py", line 124, in apply_matches
item.title = str(d[item][title_field])
~~~~~~~^^^^^^^^^^^^^
KeyError: 'title'
```
Some more changes to the regular expressions in the "PATTERNS" list.
Also allow "_" as a separator, where only "-" was allowed.
Replaced similar regexps containing different combinations of \s, "-", "."
with a single regexp using a set of characters [\s.\-_].
Delete the remaining usages of BeetsPlugin.listen().
Since BeetsPlugin.listeners are wrapped by a loglevel-setting function,
we cannot easily check their unicity anymore.
BeetsPlugin._raw_listeners set holds the raw listeners.
Legacy plugins that did not handle enough arguments in their listenings
functions may break: dedicated code is now deleted for it would not work
with the decorated listeners.
Tests got fixed. Some modifications were done empirically: if it passes
then it's okay.
Include import of __future__ features division, absolute_imports and
print_function everywhere. Don't add unicode_literals yet for it is
harder to convert.
Goal is smoothing the transition to python 3.