Skip to content

Commit e63940f

Browse files
author
GuardKenzie
authored
Merge pull request #17 from bartkl/main
Album art fetching from HTTP server
2 parents c275487 + 2b113f7 commit e63940f

File tree

4 files changed

+112
-35
lines changed

4 files changed

+112
-35
lines changed

README.md

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,19 +24,22 @@ pip install miniplayer
2424
The config file is located at `~/.config/miniplayer/config`. The example configuration file, [`config.example`](config.example), has all the default values. You will need to create the file yourself.
2525

2626
#### player
27-
* ***music_directory*:** The path to your music directory for extracting album art.
2827
* ***font_width*:** The width of your font in pixels in the actual terminal.
2928
* ***font_height*:** The height of your font in pixels in the actual terminal.
3029

3130
![font-example](https://github.com/GuardKenzie/miniplayer/blob/main/img/font.png?raw=true)
3231

33-
* ***image_method*:** The method to use for drawing album art. Available values are `pixcat` and `ueberzug`
34-
If you are not using Kitty, try `ueberzug`.
3532
* ***volume_step*:** The ammount (in percents) the volume will be adjusted on pressing the volume up and volume down keys.
3633
* ***album_art_only*:** Whether or not to only draw the album art and no other track info (`true/false`).
3734
* ***auto_close*:** Whether or not to automatically close the player once the mpd playlist has concluded (`true/false`).
3835
* ***show_playlist*:** Whether or not to show the playlist view.
3936

37+
#### art
38+
* ***music_directory*:** The path to your music directory for extracting album art from the files.
39+
* ***http_base_url*:** Base URL of webserver which serves the album art for your albums (takes precedence over `music_directory`). Useful for users of Android MPD clients _MAFA_ or _MPDroid_. For more information see [the MPDroid wiki](https://github.com/abarisain/dmix/wiki/Album-Art-on-your-LAN).
40+
* ***http_cover_filenames*:** Space separated list of filenames to use in the call to the webserver to fetch the album art.
41+
* ***image_method*:** The method to use for drawing album art. Available values are `pixcat` and `ueberzug`
42+
If you are not using Kitty, try `ueberzug`.
4043

4144
#### mpd
4245
* ***host*:** The mpd host
@@ -80,7 +83,7 @@ These keybinds can be changed by editing the config file. See the [`config.examp
8083

8184
## F.A.Q.
8285
- **Q:** Album art is not showing up.
83-
**A:** Make sure your `music_directory` is not quoted i.e. if your music directory is `~/My Music` then your config should look like `music_directory = ~/My Music`.
86+
**A:** If you're using `music_directory` for fetching your album art, make sure your it is not quoted i.e. if your music directory is `~/My Music` then your config should look like `music_directory = ~/My Music`.
8487
If this does not work, try changing `image_method` from `pixcat` to `ueberzug` or vice versa.
8588

8689
- **Q:** Album art is too big/too small.

bin/miniplayer

Lines changed: 98 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
#!/bin/python
22
import curses
33
import os
4+
import posixpath
5+
import requests
46
from mpd import MPDClient
57
import ffmpeg
68
import pixcat
@@ -9,21 +11,25 @@ import configparser
911
import ueberzug.lib.v0 as ueberzug
1012
from PIL import Image, ImageDraw
1113

14+
1215
# Get config
1316
config = configparser.ConfigParser()
1417
config.read(os.path.expanduser("~/.config/miniplayer/config"))
1518

1619
if "player" not in config.sections():
17-
config["player"] = {"music_directory": "~/Music",
18-
"font_width": 11,
20+
config["player"] = {"font_width": 11,
1921
"font_height": 24,
20-
"image_method": "pixcat",
2122
"album_art_only": False,
2223
"volume_step": 5,
2324
"auto_close": False,
2425
"show_playlist": True,
2526
}
2627

28+
if "art" not in config.sections():
29+
config["art"] = {"music_directory": "~/Music",
30+
"image_method": "pixcat",
31+
}
32+
2733
if "mpd" not in config.sections():
2834
config["mpd"] = {"host": "localhost",
2935
"port": "6600",
@@ -46,6 +52,23 @@ default_bindings = {">": "next_track",
4652
if "keybindings" not in config.sections():
4753
config["keybindings"] = default_bindings
4854

55+
# Ensure compatibility with older configs
56+
deprecated_field_notice = ("The config option `{field}` under the `player` "
57+
"section is deprecated and will be removed in the "
58+
"future. Use the config option `{field}` under the "
59+
"`art` section instead.")
60+
deprecated_fields_present = False
61+
for field in ["music_directory", "image_method"]:
62+
if config.has_option("player", field):
63+
deprecated_fields_present = True
64+
print(deprecated_field_notice.format(field=field))
65+
66+
if not config.has_option("art", field):
67+
config["art"][field] = config["player"][field]
68+
69+
if deprecated_fields_present:
70+
input("(Press <Enter> to continue) ...")
71+
4972
# Load configured keybindings
5073
keybindings = config["keybindings"]
5174

@@ -59,6 +82,7 @@ for key, action in default_bindings.items():
5982
keybindings[key] = action
6083

6184
player_config = config["player"]
85+
art_config = config["art"]
6286
mpd_config = config["mpd"]
6387

6488

@@ -71,17 +95,13 @@ IMAGERATIO = (player_config.getint("font_width", 11),
7195
player_config.getint("font_height", 24)
7296
)
7397

74-
# Music directory
75-
MUSICDIR = player_config.get("music_directory", "~/Music")
76-
MUSICDIR = os.path.expanduser(MUSICDIR)
77-
7898
# MPD config
7999
MPDHOST = mpd_config.get("host", "localhost")
80100
MPDPORT = mpd_config.getint("port", 6600)
81101
MPDPASS = mpd_config.get("pass", False)
82102

83103
# What to use to draw images
84-
IMAGEMETHOD = player_config.get("image_method", "pixcat")
104+
IMAGEMETHOD = art_config.get("image_method", "pixcat")
85105

86106
# Volume step
87107
VOLUMESTEP = player_config.getint("volume_step", 5)
@@ -141,6 +161,11 @@ class Player:
141161

142162
self.last_song = None
143163

164+
# Album art HTTP server
165+
166+
if art_config.get("http_base_url"):
167+
self.art_http_session = requests.Session()
168+
144169
# Album art only flag
145170
self.album_art_only = player_config.getboolean("album_art_only", False)
146171

@@ -314,14 +339,57 @@ class Player:
314339

315340
self.screen_height, self.screen_width = window_height, window_width
316341

317-
318342
def getAlbumArt(self, song_file):
343+
"""
344+
A function that fetches the album art and saves
345+
it to self.album_art_loc
346+
"""
347+
http_base_url = art_config.get("http_base_url")
348+
349+
if http_base_url:
350+
self._getAlbumArtFromHttpServer(http_base_url, song_file)
351+
else:
352+
self._getAlbumArtFromFile(song_file)
353+
354+
355+
356+
def _getAlbumArtFromHttpServer(self, base_url, song_file):
357+
"""
358+
A function that fetches the album art from the configured
359+
HTTP server, and saves it to self.album_art_loc
360+
"""
361+
362+
album = os.path.dirname(song_file)
363+
364+
for cover_filename in art_config.get("http_cover_filenames", "cover.jpg").split():
365+
album_art_url = posixpath.join(base_url, album, cover_filename)
366+
367+
try:
368+
album_art_resp = self.art_http_session.get(album_art_url)
369+
except requests.RequestException:
370+
# If any exception occurs, simply give up and show default art.
371+
self.drawDefaultAlbumArt()
372+
break
373+
374+
if album_art_resp.ok:
375+
with open(self.album_art_loc, "wb") as f:
376+
f.write(album_art_resp.content)
377+
break
378+
elif album_art_resp.status_code == 404:
379+
continue
380+
else:
381+
self.drawDefaultAlbumArt()
382+
383+
384+
def _getAlbumArtFromFile(self, song_file):
319385
"""
320386
A function that extracts the album art from song_file and
321387
saves it to self.album_art_loc
322388
"""
389+
music_dir = os.path.expanduser(
390+
art_config.get("music_directory", "~/Music"))
323391

324-
song_file_abs = os.path.join(MUSICDIR, song_file)
392+
song_file_abs = os.path.join(music_dir, song_file)
325393

326394
process = (
327395
ffmpeg
@@ -332,30 +400,34 @@ class Player:
332400
try:
333401
process.run(quiet=True, overwrite_output=True)
334402
except ffmpeg._run.Error:
335-
foregroundCol = "#D8DEE9"
336-
backgroundCol = "#262A33"
403+
self.drawDefaultAlbumArt()
404+
337405

338-
size = 512*4
406+
def drawDefaultAlbumArt(self):
407+
foregroundCol = "#D8DEE9"
408+
backgroundCol = "#262A33"
339409

340-
art = Image.new("RGB", (size, size), color=backgroundCol)
341-
d = ImageDraw.Draw(art)
410+
size = 512*4
342411

343-
for i in range(4):
344-
offset = (i - 2) * 70
412+
art = Image.new("RGB", (size, size), color=backgroundCol)
413+
d = ImageDraw.Draw(art)
345414

346-
external = size/3
415+
for i in range(4):
416+
offset = (i - 2) * 70
347417

348-
x0 = round(external) - offset
349-
y0 = round(external) + offset
350-
x1 = round(external*2) - offset
351-
y1 = round(external*2) + offset
418+
external = size/3
352419

353-
externalyx = [(x0, y0), (x1, y1)]
420+
x0 = round(external) - offset
421+
y0 = round(external) + offset
422+
x1 = round(external*2) - offset
423+
y1 = round(external*2) + offset
354424

355-
d.rectangle(externalyx, outline=foregroundCol, width=40)
425+
externalyx = [(x0, y0), (x1, y1)]
356426

357-
art.resize((512, 512))
358-
art.save(self.album_art_loc, "PNG")
427+
d.rectangle(externalyx, outline=foregroundCol, width=40)
428+
429+
art.resize((512, 512))
430+
art.save(self.album_art_loc, "PNG")
359431

360432

361433
def getSongInfo(self, song):
@@ -413,8 +485,6 @@ class Player:
413485
self.selected_song = int(song["pos"])
414486

415487
self.album, self.artist, self.title = self.getSongInfo(song)
416-
self.last_song = song
417-
418488
self.getAlbumArt(song["file"])
419489
self.last_song = song
420490

config.example

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
[player]
2-
music_directory = ~/Music
32
font_width = 11
43
font_height = 24
5-
image_method = pixcat
64
volume_step = 5
75
auto_close = false
86
album_art_only = false
97
show_playlist = true
108

9+
[art]
10+
image_method = pixcat
11+
music_directory = ~/Music
12+
# http_base_url = http://localhost:6667/cover-art
13+
# http_cover_filenames = cover.jpg cover.png folder.jpg folder.png art.jpg art.png artwork.jpg artwork.png
1114

1215
[mpd]
1316
host = localhost

setup.cfg

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[metadata]
22
name = miniplayer
3-
version = 1.3.2
3+
version = 1.4.0
44
description = An mpd client with album art and basic functionality.
55
long_description = file: README.md
66
long_description_content_type = text/markdown
@@ -22,5 +22,6 @@ install_requires =
2222
ffmpeg-python
2323
pixcat
2424
pillow
25+
requests
2526
ueberzug
2627

0 commit comments

Comments
 (0)