Musify

Latest version: v1.2.5

Safety actively analyzes 710445 Python packages for vulnerabilities to keep your Python projects secure.

Scan your dependencies

Page 4 of 5

1.0.1

Documentation
----------------

* Update PyPI classifiers for release
* Update readme

1.0.0

Added
-----

* Custom API caching backend to replace dependency on ``requests-cache`` package.
Currently only supports SQLite backend. More backends can be implemented in future if desired.
* Cache settings for specific `GET` request endpoints on :py:class:`.SpotifyAPI` replacing need
for per method ``use_cache`` parameter.
* The following classes should now be run as AsyncContextManagers to function correctly:
* :py:class:`.SQLiteCache`
* :py:class:`.RequestHandler`
* :py:class:`.CachedSession`
* :py:class:`.RemoteAPI` & :py:class:`.SpotifyAPI`
* Introduce print wrapper for logger and remove most bare ``print`` statements across package.
* :py:meth:`.SpotifyAPI.extend_items` now enriches collection item responses with the parent collection response.
* ARTISTS field added to LocalTrackField
* Add compatibility with ``yarl`` package for any logic which uses URL logic.
* Add compatibility for pathlib.Path for any logic which uses path logic.
* Extended logging on :py:func:`.report_playlist_differences`
* ``source`` property on :py:class:`.Library`
* :py:meth:`.RemoteAPI.get_or_create_playlist` method for only creating a playlist when it doesn't
already exist by name. Gets the existing playlist otherwise
* Added :py:meth:`.MusifyCollection.outer_difference` method to cover the logic previously handled
by the mislabelled :py:meth:`.MusifyCollection.outer_difference` method
* :py:class:`.RemoteDataWrangler` and its implementations now handle URL objects from the ``yarl`` package
* :py:meth:`.RemoteAPI.follow_playlist` method
* Wait time logic for :py:class:`.RequestHandler`. This waits by a certain time after each request,
incrementing this wait time every time a 429 code is returned.
This allows better handling of rate limits, with the aim of preventing a lock out from a service.

Changed
-------

* :py:class:`.RequestHandler` now handles requests asynchronously. These changes to async calls have
been implemented all the way on :py:class:`.RemoteAPI` and all other objects that depend on it.
* All I/O operations on local libraries and their dependent objects now run asynchronously.
* Dependency injection pattern for :py:class:`.RequestHandler`.
Now takes :py:class:`.APIAuthoriser` and generator for :py:class:`.ClientSession` objects for instantiation
instead of kwargs for :py:class:`.APIAuthoriser`.
* Dependency injection pattern for :py:class:`.RemoteAPI`.
Now takes :py:class:`.APIAuthoriser` and generator for :py:class:`.ResponseCache` objects for instantiation
instead of kwargs for :py:class:`.APIAuthoriser`.
* :py:class:`.APIAuthoriser` kwargs given to :py:class:`.SpotifyAPI` now merge with default kwargs.
* Moved ``remote_wrangler`` attribute from :py:class:`.MusifyCollection` to :py:class:`.LocalCollection`.
This attribute was only needed by :py:class:`.LocalCollection` branch of child classes.
* Moved ``logger`` attribute from :py:class:`.Library` to :py:class:`.RemoteLibrary`.
* Switch some dependencies to be optional for groups of operation: progress bars, musicbee, sqlite
* Replace urllib usages with ``yarl`` package.
* Replace all path logic to use pathlib.Path instead. All
* :py:class:`.SpotifyAPI` now logs to the new central :py:meth:`.RequestHandler.log` method
to help unify log formatting.
* ``user_id`` and ``user_name`` now raise an error when called before setting ``user_data`` attribute.
This is due to avoiding asynchronous calls in a property.
It is therefore best to now enter the async context of the api to set these automatically.
* Renamed :py:meth:`.LocalGenres.genres` to :py:meth:`.LocalGenres.related_genres`
* Reduced scope of :py:meth:`.TagWriter._delete_tag` method to private
* :py:class:`.LocalTrack` now removes any loaded embedded image from the mutagen file object.
This is to reduce memory usage when loading many of these objects.
* Extend logging on :py:meth:`.LocalCollection.log_save_tracks_result` to show when no tags
have been or would be updated.
* :py:class:`.RemoteItemChecker` now uses the new :py:meth:`.RemoteAPI.get_or_create_playlist` method
when creating playlists to avoid creating many duplicate playlists which could have lead to playlist
creation explosion in repeated uses. The processor also accounts for any items that may have existed
in the playlist before it was run and discounts them from any matches.
* :py:class:`.RemoteItemChecker` also uses the new :py:meth:`.RemoteAPI.follow_playlist` method
when creating playlists to ensure that a user is following the playlists it creates to avoid 'ghost playlist' issue.
* :py:meth:`.SpotifyAPI.create_playlist` now returns the full response rather than just the URL of the playlist.
* Moved :py:class:`.RemoteItemChecker` and :py:class:`.RemoteItemSearcher` to `musify.processors` package.
* Moved :py:class:`.RemoteDataWrangler` up a level to `musify.libraries.remote.core`.
* Renamed `musify.libraries.remote.spotify.processors` module to `musify.libraries.remote.spotify.wrangle`.
* Moved `musify.logger` module to `musify` base package.
* Restructured contents of `musify.core` package to modules in `musify` base package.

Fixed
-----

* Added missing variables to __slots__ definitions
* Correctly applied __slots__ pattern to child classes. Now works as expected.
* :py:class:`.LocalTrack` now copies tags as expected when calling ``copy.copy()``
* Bug where loading an M3U playlist with new track objects would force all created track objects
to have lower case paths
* :py:meth:`.RemoteLibrary.restore_playlists` now correctly handles the backup
output from :py:meth:`.RemoteLibrary.backup_playlists`
* Issue detecting stdout_handlers affecting :py:meth:`.MusifyLogger.print` and :py:meth:`.MusifyLogger.get_iterator`.
Now works as expected.
* :py:meth:`.LocalLibrary.artists` now generates a :py:class:`.LocalArtist` object per individual artist
rather than on combined artists
* Issue where :py:meth:`.SpotifyAPI.extend_items` did not show progress when extending some types of responses
* Fixed logic in :py:meth:`.MusifyCollection.intersection` and :py:meth:`.MusifyCollection.difference`

Removed
-------

* Dependency on ``requests`` package in favour of ``aiohttp`` for async requests.
* Dependency on ``requests-cache`` package in favour of custom cache implementation.
* ``use_cache`` parameter from all :py:class:`.RemoteAPI` related methods.
Cache settings now handled by :py:class:`.ResponseCache`
* ThreadPoolExecutor use on :py:class:`.RemoteItemSearcher`. Now uses asynchronous logic instead.
* `last_modified` field as attribute to ignore when getting attributes
to print on `LocalCollection` to improve performance
* Removed logger filters and handlers. Moved to CLI repo.
* Deleted `musify.libraries.remote.core.processors` package.

Documentation
-------------

* Updated how-to section to reflect implementation of async logic to underlying code
* Created a how-to page for installation

0.9.2

=====

Added
-----

* ``REMOTE_SOURCES`` global variable in the ``libraries.remote`` module which lists the
names of all the fully supported remote sources.
Also, added the ``SOURCE_NAME`` global variable for the Spotify module.

Changed
-------

* :py:class:`.FilterComparers` now accepts a single :py:class:`.Comparer` on the ``comparers`` argument.
* :py:class:`.MusicBee` class attributes were renamed to classify that full paths are also valid, not just filenames.
* :py:class:`.ItemDownloadHelper` ``urls`` init arg now has default arg of empty tuple.

Documentation
-------------

* Fixed error in 'sync data' how-to.

Fixed
-----

* :py:class:`.Comparer` now considers strings as converted on first pass when converting expected values.
* Printing of new line at the end of :py:meth:`.RemoteLibrary.extend`

0.9.1

Fixed
-----

* Bug in :py:meth:`.ItemMatcher.match` where operations always returned the last item in the given list of ``results``

0.9.0

Added
-----

* :py:class:`.RemoteAPI` methods now accept :py:class:`.RemoteResponse` objects as input, refreshing them automatically
* Property 'kind' to all objects which have an associated :py:class:`.RemoteObjectType`
* Introduced :py:class:`.MusifyItemSettable` class to allow distinction
between items that can have their properties set and those that can't
* Extend :py:class:`.FilterMatcher` with group_by tag functionality
* Now fully supports parsing of processors relating to :py:class:`.XAutoPF` objects with full I/O of settings
to/from their related XML files on disk
* Now supports creating new :py:class:`.XAutoPF` files from scratch without the file needing to already exist
For XML values not directly controlled by Musify, users can use the 'default_xml' class attribute
to control the initial default values applied in this scenario
* 'length' property on :py:class:`.MusifyCollection` and implementation on all subclasses

Changed
-------

* Major refactoring and restructuring to all modules to improve modularity and add composition
* The following classes and methods have been modified to implement concurrency to improve performance:
* :py:meth:`.LocalLibrary.load_tracks`
* :py:meth:`.LocalLibrary.save_tracks`
* :py:meth:`.LocalLibrary.load_playlists`
* :py:meth:`.LocalLibrary.save_playlists`
* :py:meth:`.LocalLibrary.json` + optimisation for extracting JSON data from tracks
* :py:class:`.ItemMatcher`
* :py:class:`.RemoteItemChecker`
* :py:class:`.RemoteItemSearcher`
* Made :py:func:`.load_tracks` and :py:func:`.load_playlists` utility functions more DRY
* Move :py:meth:`.TagReader.load` from :py:class:`.LocalTrack` to super class :py:class:`.TagReader`
* :py:meth:`.SpotifyAPI.extend_items` now skips on responses that are already fully extended
* :py:meth:`.SpotifyArtist.load` now uses the base `load` method from :py:class:`.SpotifyCollectionLoader`
meaning it now takes full advantage of the item filtering this method offers.
As part of this, the base method was made more generic to accommodate all :py:class:`.SpotifyObject` types
* Renamed 'kind' property on :py:class:`.LocalTrack` to 'type' to avoid clashing property names
* :py:class:`.ItemMatcher`, :py:class:`.RemoteItemChecker`, and :py:class:`.RemoteItemSearcher` now accept
all MusifyItem types that may have their URI property set manually
* :py:class:`.RemoteItemChecker` and :py:class:`.RemoteItemSearcher` no longer inherit from :py:class:`.ItemMatcher`.
Composite pattern used instead.
* :py:class:`.ItemSorter` now shuffles randomly on unsupported types
+ prioritises fields settings over shuffle settings
* :py:meth:`.Comparer._in_range` now uses inclusive range i.e. ``a <= x <= b`` where ``x`` is the value to compare
and ``a`` and ``b`` are the limits. Previously used exclusive range i.e. ``a < x < b``
* Removed ``from_xml`` and ``to_xml`` methods from all :py:class:`.MusicBeeProcessor` subclasses.
Moved this logic to :py:class:`.XMLPlaylistParser` as distinct 'get' methods for each processor type
* Moved loading of XML file logic from :py:class:`.XAutoPF` to :py:class:`.XMLPlaylistParser`.
:py:class:`.XMLPlaylistParser` is now solely responsible for all XML parsing and handling
for :py:class:`.XAutoPF` files

Fixed
-----

* :py:class:`.Comparer` dynamic processor methods which process string values now cast expected types before processing

Removed
-------

* Redundant ShuffleBy enum and related arguments from :py:class:`.ItemSorter`
* ``ItemProcessor`` and ``MusicBeeProcessor`` abstraction layers. No longer needed after some refactoring
* ``get_filtered_playlists`` method from :py:class:`.Library`.
This contained author specific logic and was not appropriate for general use

Documentation
-------------

* Added info on lint checking for the contributing page

0.8.1

Changed
-------

* :py:class:`.ItemSorter` now accepts ``shuffle_weight`` between -1 and 1 instead of 0 and 1.
This parameter's logic has not yet been implemented so no changes to functionality have been made yet.
* Move :py:meth:`.get_filepaths` from :py:class:`.LocalTrack` to super class :py:class:`.File`

Documentation
-------------

* References to python objects now link correctly

Fixed
-----

* Comments from :py:class:`.LocalTrack` metadata loading no longer gets wiped after setting URI on init
* Tweaked assignment of description of IDv3 comment tags for :py:class:`.MP3`
* :py:func:`.align_string` function now handles combining unicode characters properly for fixed-width fonts
* :py:meth:`.LocalTrack.get_filepaths` on LocalTrack no longer returns paths from ``$RECYCLE.BIN`` folders.
These are deleted files and were causing the package to crash when trying to load them.
* :py:meth:`.PrettyPrinter.json` and :py:meth:`.PrettyPrinter._to_str` converts attribute keys to string
to ensure safe json/str/repr output
* :py:class:`.FilterMatcher` and :py:class:`.FilterComparers` now correctly import conditions from XML playlist files.
Previously, these filters could not import nested match conditions from files.
Changes to logic also made to :py:meth:`.Comparer.from_xml` to accommodate.
* :py:class:`.XMLLibraryParser` now handles empty arrays correctly. Previously would crash.
* Fixed :py:class:`.Comparer` dynamic process method alternate names for ``in_the_last`` and ``not_in_the_last``

Removed
-------

* Abstract uri.setter method on :py:class:`.Item`

Page 4 of 5

© 2025 Safety CLI Cybersecurity Inc. All Rights Reserved.