Commit graph

51 commits

Author SHA1 Message Date
452867699e
Update Mypy so I can use PEP 695 type param syntax 2024-07-30 10:09:33 +10:00
3ef3112014
Load crossfade settings into Playback.settings too 2024-07-29 11:14:48 +10:00
c29f4b9b27
Add 'heartbeat' to MPD client, so we notice if we disconnect 2024-07-29 10:55:27 +10:00
68609f3d07
Wrap Song in a broader Playback state object with stuff like volume and repeat mode 2024-07-26 09:53:17 +10:00
085bca7974
Declare nextsong index as part of MPD status response 2024-07-26 09:49:45 +10:00
dbd507bccb
Support current songs with no duration, such as streams 2024-07-23 13:38:41 +10:00
012bc0b025
Generate serialisation schema for songs, not validation schema 2024-07-23 13:34:50 +10:00
d9c8e0fe28
Find the current song's URL and pass it on when possible 2024-07-23 13:30:06 +10:00
b8bcdc5a83
Wrap MPD's state into a transfer struct before finalising the Song 2024-07-23 13:12:06 +10:00
1bb2032b9f
Ditch convert_if_exists, just use option_fmap which I prefer 2024-07-23 11:04:18 +10:00
fda799e32e
Fix inheritance of MusicBrainzTags into MPD response types 2024-07-23 10:52:43 +10:00
e2268c0c34
Allow websocket server to reuse its port (handle crashes better) 2024-07-23 10:45:06 +10:00
1e6dffcdcc
Support multivalued tags for MusicBrainz IDs too 2024-07-23 10:43:22 +10:00
86761bc420
Don't worry about ormsgpack import error, it's always required now 2024-07-23 10:37:38 +10:00
21b7c28692
Add descriptions to websockets config 2024-07-13 19:28:18 +10:00
ca5086f93a
Fix path to MPD logo in Cocoa receiver (oops) 2024-07-13 18:38:16 +10:00
582a4628b7
Introduce new WebSockets receiver impl
When enabled, this new receiver will spin up a local WebSockets server
and will send the currently playing song information to any clients that
connect. It's designed with Übersicht in mind, since WebSockets is the
easiest way to efficiently push events into an Übersicht widget, but
I'm sure it'd work for a variety of other purposes too.

Currently the socket is only used in one direction, pushing the current
song info from server to client, but I'll probably extend it to support
sending MPD commands from WebSockets clients as well.
2024-07-13 18:34:53 +10:00
04859b8c8b
Adjust receiver protocol to accommodate config 2024-07-11 12:15:34 +10:00
09fe3b3e6c
Expand MusicBrainz support to be much more comprehensive 2024-07-11 12:12:56 +10:00
00ba34bd0b
Refactor Cocoa stuff into a 'receiver'
The idea here is that there are other places that might want to know
what's playing, besides MPNowPlayingInfoCenter. For example, to expose
the now playing info to Übersicht efficiently, it needs to be available
from a web browser, ideally using WebSockets. So there could be a
receiver that runs a small WebSockets server and sends out now playing
info to anyone who connects.

Additionally, I hope to write receivers for MPRIS and for the System
Media Transport Controls on Windows, making mpd-now-playable equally
useful across all platforms.

None of this is implemented yet, of course, but I hope to get the
WebSockets receiver done pretty soon!

I'm going to keep the default behaviour unchanged. Unless you
explicitly configure different receivers in config.toml,
mpd-now-playable will just behave as an MPNowPlayingInfoCenter
integration as it's always done.
2024-07-09 12:52:49 +10:00
27d8c37139
Significantly overhaul configuration management
Everything now uses bog-standard Python dataclasses, with Pydantic
providing validation and type conversion through separate classes using
its type adapter feature. It's also possible to define your classes
using Pydantic's own model type directly, making the type adapter
unnecessary, but I didn't want to do things that way because no actual
validation is needed when constructing a Song instance for example.
Having Pydantic do its thing only on-demand was preferable.

I tried a number of validation libraries before settling on Pydantic for
this. It's not the fastest option out there (msgspec is I think), but it
makes adding support for third-party types like yarl.URL really easy, it
generates a nice clean JSON Schema which is easy enough to adjust to my
requirements through its GenerateJsonSchema hooks, and raw speed isn't
all that important anyway since this is a single-user desktop program
that reads its configuration file once on startup.

Also, MessagePack is now mandatory if you're caching to an external
service. It just didn't make a whole lot sense to explicitly install
mpd-now-playable's Redis or Memcached support and then use pickling with
them.

With all this fussing around done, I'm probably finally ready to
actually use that configuration file to configure new features! Yay!
2024-07-01 00:10:17 +10:00
3b7ddfa718
fix: handle missing environment variables more robustly 2024-06-28 14:14:24 +10:00
bc56686fc4
Support multivalued song tags (fixes #1)
python-mpd2 unreliably returns either a single value or a list of
values for commands like currentsong, which is super fun if you're
trying to write type stubs for it that statically describe its
behaviour. Whee.

Anyway, I ended up changing my internal song model to always use lists
for tags like artist and genre which are likely to have multiple values.
There's some finagling involved in massaging python-mpd2's output into
lists every time. However it's much nicer to work with an object that
always has a list of artists, even if it's a list of one or zero
artists, rather than an object that can have a single artist, a list of
multiple artists, or a null. So it's worth it.

The MPNowPlayingInfoCenter in MacOS only works with single string values
for these tags, not lists, so we have to join the artists and such into
a single string for its consumption. I'm using commas for the separator
at the moment, but I may make this a config option later on if there's
interest.
2024-06-23 17:24:37 +10:00
2f70c6f7fa
Prettier-print the generated config schema 2024-06-22 20:12:50 +10:00
3cb5db7528
Add field descriptions to the config schema :) 2024-06-22 20:12:23 +10:00
2def2aece5
Organise 'tools' modules into a subpackage 2024-06-22 18:48:32 +10:00
35703de261
Gitignore __version__.py to avoid spurious diffs 2024-06-22 18:41:49 +10:00
8e982e8a6b
Fixups to placate Ruff linter 2024-06-22 18:39:10 +10:00
dc037a0a4b
Support a TOML configuration file
The new config file currently only configures the same options that were
already available through environment variables. However I have ideas
for additional features that would be much nicer to support using a
structured configuration format like TOML rather than environment
variables, so config files exist now!

The previous environment variables are still supported and will be used
if you don't have a config file. I plan to keep supporting the MPD_HOST
and MPD_PORT environment variables forever since they're shared with
other MPD clients such as mpc, but I may eventually drop the environment
variables specific to mpd-now-playable in a future release.
2024-06-22 18:19:39 +10:00
796e3df87d
Display mpd-now-playable version on launch 2024-06-22 13:17:14 +10:00
fd7866ed14
Try both readpicture and albumart, prefer the former 2024-05-17 19:46:10 +10:00
569372d4e2
Add methods for calling MPD's albumart command 2024-05-17 19:46:04 +10:00
8ad255856e
Extend cache TTL now external caches are supported 2024-05-14 16:07:43 +10:00
4a2ac29d30
Use more conventional Redis key separators for album cache 2024-05-14 15:09:20 +10:00
a471b77c55
Avoid crashing if cache URL has no namespace 2024-05-14 14:07:25 +10:00
55d82c72c3
Support MPD_NOW_PLAYABLE_CACHE setting (Redis or Memcached) 2024-05-14 13:25:13 +10:00
b2f28de116
Support newer PyObjC by explicitly converting Paths to str 2024-05-14 13:23:41 +10:00
9fca1d566e
Support MusicBrainz release track ID
I still don't totally understand when MusicBrainz uses a track ID and
when it uses a release track ID - they're both displayed as the
"MusicBrainz Track ID" tag in Picard, despite being treated as different
tags by everything else - but supporting both is easy enough.
2024-05-14 10:06:39 +10:00
1caf4a184c
Cache 'no artwork', rather than repeatedly populating the cache with None 2024-05-09 12:12:54 +10:00
f7fc453c50
Don't crash if readpicture returns no image bytes 2024-05-09 12:10:22 +10:00
9b8988cf41
Fix path to mpd/logo.svg 2023-12-06 14:39:04 +11:00
3372180a97
Enable seeking to specific points in the current song 2023-12-06 13:54:40 +11:00
04a976f6f3
Support persistent track IDs (64-bit ints) 2023-12-06 12:27:24 +11:00
28da4da69f
Pass through more simple media item info to MacOS 2023-12-06 12:02:13 +11:00
eb7509a4e0
Whoops, correctly call MpdStateListener.start() 2023-12-06 11:54:28 +11:00
095c099a38
Use the same environment variables as mpc does 2023-12-06 11:42:50 +11:00
9ff488d807
Make most song info optional, to support untagged music 2023-12-06 10:54:51 +11:00
ffc399290f
Safely cache artwork for tracks without expected tags 2023-12-02 14:47:50 +11:00
5a3ddd570d
Fix some types in cocoa.py so they work with the stubs 2023-11-27 16:52:00 +11:00
a673f2ef90
Initial commit of source - working, but needs stubs for Cocoa 2023-11-27 15:49:33 +11:00