pymcws 1.1.0
Python API for the MCWS interface of JRiver Media Center
License: MIT
Keywords: JRiver,MCWS

# pyMCWS
A python API wrapper for MCWS, the web interface of the excellent JRiver Media Center.
The aim is to replicate the MCWS functionality as close as possible in a pythonian,
easy to use manner. Additionally, common use-cases can be implemented in
easily accessible recipes.

Currently, the minimum required version of JRiver MC is 26. Backwards compatibility is possible,
but will have to be requested - it is mainly the automatic field conversion that is preventing it.

## Usage
use your package manager of choice to install pymcws:

```bash
pip install pymcws
```

First order of action is to import pymcws. You can just import the package and use
it as a one-stop-shop-all:

```python
import pymcws as mcws
```

using this method, all functions and recipes are imported and available via the
mcws object. You can then initialize a server and start using commands:

```python
# get the server
office = mcws.get_media_server("AccessKey", "readonly", "supersecretpassword")
# use a recipe to play an album
files = office.recipes.query_album("Ludovico Einaudi", "I Giorni")
office.playback.playpause()
zones = office.playback.zones()
for zone in zones:
    print(zone.index, zone.id, zone.name, zone.guid, zone.is_dlna)
office.playback.playpause(zones[0])

```

For a full set of examples, please see examples.py.

## Using the API and recipes
pymcws wraps the MCWS API in a 1:1 manner. If you are looking for http://localhost:52199/MCWS/v1/Playback/Stop,
then that's located under pymcws.playback.stop. This way, you can import API functions to your scripts as needed.

To call these functions, you need a server. The easiest way to get one is to call pymcws.get_media_server() along with an access key, username and password. The server returned in this way already imports the API functions and provides them locally. These two calls are functionally identical:

```python
# get the server
office.playback.playpause()
mcws.playback.playpause(office)
```

Use whichever you prefer. If you intend to use the second option exclusively, consider using pymcws.get_media_server_light() to get your server - the returned class does not import API functions directly.

The general philosophy of pymcws is to make communication with mcws as easy as possible. Wherever possible, 
the behaviour if the API has been replicated 1:1, where exceptions exist, they are documented. The main difference is that pymcws provides classes that model complex entities like zones and files, and uses these
classes to facilitate interaction. More on these classes in the following sections.

Finally, pymcws provides convenience methods that enable users to quickly execute common tasks. These are 
stored in pymcws.recipes and contain functionality like playing and querying albums.

## The MediaServer class
The MediaServer class covers all functionality to communicate with JRiver Media Center.
The most important feature is connection negotiation. When providing an access key, the server is resolved,
and the best connection strategy is chosen. Inside your home network, this will be the local IP,
outside it will be global IP.

## Working with Files
JRiver Media Center has a complex model for files and allows adding custom fields with varying types.
pymcws queries these field definitions and automatically performs type conversions for them, allowing users 
to work with common types like string, int, float, datetime etc. directly. These conversions happen both ways:
When saving changes to files, the types are converted back to jriver-compatible versions. 

Files themselves are simply (extended) dictionaries. Calling my_file["Date"] returns the datetime of the corresponding field. Changing values works the same way as well, but changes are not persisted immediately. Files keep track of which values you have modified. Once you are happy, call pymcws.file.set_info() and pass it the file to save the changes. pymcws will only transmit changed and new fields.
Please do not create a file yourself, as jriver takes care of assigning a key. Instead,
call pymcws.library.create_file to get a new file and start populating it with values.

## Working with Zones
Zones are the places where you can play music, accordingly they are mainly used for playback commands.
List them with pymcws.playback.zones(), and use them to specify which zone the command is for.
The zone argument is always optional, if no zone is provided, JRiver Media Center will use the zone currently selected in the UI.

## The function I need is not in pymcws!
That's quite possible. I mainly extend pymcws as I need new features. The current structure makes it easy to add
functionality quickly. Please feel free to open an issue in the issue tracker.

## Contributing
Contributions are very welcome. Please create pull requests at your leisure.
If you are not of the coding kind, you can also leave a request for a specific
functionality in the issue tracker.  


# Version History

### v1.1.0
* Added sensible default behaviour to library.playlist() and files.search(). Both will now return lists of MediaFiles by default.

### v1.0.1
* Upgraded to Python 3.9 and improved type hinting.
* Added files.playback() to retrieve current playlist from zones based on https://github.com/kenomaerz/pymcws/issues/7.
* Added library.create_fields() to create new fields. However, MCWS currently fails to execute the request, see https://yabb.jriver.com/interact/index.php/topic,131470.0.html

### v1.0.0
* Major rewrite of pymcws that fixes everything I started to dislike about the structure.
* Usage is more intuitive now, see Readme.md and example.py for details.
* Editing and saving files is now possible.
* Several additional endpoints implemented.
* Finally added tests. Please read the documentation carefully if you intend to run them. They can destroy your library.

### v0.2.2
* Implemented playback_loadDSPPreset based on https://github.com/kenomaerz/pymcws/issues/6.

### v0.2.1
* Introduced session management for established media servers.

### v0.2.0
* Added automatic field resolution. Fields are automatically converted to and from their corresponding python types by the API, sparing you the postprocessing.
* Because of this, the required version of MC is now 26. Earlier version support is possible but needs to be requested.
* Play recipes use more reasonable defaults for shuffle and repeat.
* Several smaller bugfixes.


### v0.1.0
* Added remote connection capabilities. The MediaServer class queries JRiver's web service and tries to determine the best possible connection method automatically.

### v0.0.7
* Fixed zones being ignored in play_recipes.

### v0.0.6
* Fixed failing package installation on case-aware file systems.

### v0.0.5
* Created query recipes for easier querying.
* Improved image and cover art handling.
* Implemented library_values.
* Implemented automatic query escaping for the jriver search language.
* Play recipes allow  setting shuffle and repeat states.
* Introduced zone handling.
* Full automatic local ip resolution, also for multiple network adapters.

### v0.0.4
* Support for getting file info and parsing MPLs.
* Support for getting images for library files.
* More lenient timeouts for local connections should prevent huge queries from failing.

### v0.0.3
* MediaServer now throws exception if key cannot be resolved instead of failing silently.
* Added mute, shuffle and repeat.
* Added volume control.
* Improved example.py to explain usage better.
* Fixed wrong behavior of playback_stop.

### v0.0.2
* api.py now has a method to get a server directly from pymcws object. This allows basic usage by only importing pymcws.

### v0.0.1
* Initial release and proof of concept.
* Resolve media network access keys.
* Issue playback commands.
* Search and play files to different zones on server.
* First play_recipes that facilitate playback of files.