# MusicDB, a music manager with web-bases UI that focus on music.
# Copyright (C) 2017 - 2022 Ralf Stemmer <ralf.stemmer@gmx.net>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
import logging
from musicdb.lib.filesystem import Filesystem
from PIL import Image
[docs]class ArtworkCache(object):
"""
This class handles the artwork cache.
Its main job is to scale an image if a special resolution is requested.
Args:
artworkdir: Absolute path to the artwork root directory
"""
def __init__(self, artworkdir):
self.artworkroot = Filesystem(artworkdir)
[docs] def GetArtwork(self, artworkname, resolution):
"""
This method returns a valid path to an artwork with the specified resolution.
The final path will consist of the *artworkdir* given as class parameter, the *resolution* as subdirectory and the *artworkname* as filename. (``{artworkdir}/{resolution}/{artworkname}``)
If the artwork does not exist for this resolution it will be generated.
If the directory for that scale does not exist, it will be created.
Its permission will be ``musicdb:musicdb drwxrwxr-x``
In case an error occurs, an exception gets raised.
The resolution is given as string in the format ``{X}x{Y}`` (For example: ``100x100``).
*X* and *Y* must have the same value.
This method expects an aspect ratio of 1:1.
Beside scaling the JPEG, it will be made progressive.
Args:
artworkname (str): filename of the source artwork (Usually ``$Artist - $Album.jpg``)
resolution (str): resolution of the requested artwork
Returns:
Relative path to the artwork in the specified resolution.
``None`` on error.
Raises:
ValueError: When the source file does not exist
Example:
.. code-block:: python
cache = ArtworkCache("/data/artwork")
path = cache.GetArtwork("example.jpg", "150x150")
# returned path: "150x150/example.jpg"
# absolute path: "/data/artwork/150x150/example.jpg"
"""
logging.debug("GetArtwork(%s, %s)", artworkname, resolution)
# Check if source exists
if not self.artworkroot.Exists(artworkname):
logging.error("Source file %s does not exist in the artwork root directory!", artworkname)
raise ValueError("Source file %s does not exist in the artwork root directory!",
artworkname)
# Check if already scaled. If yes, our job is done
scaledfile = os.path.join(resolution, artworkname)
if self.artworkroot.Exists(scaledfile):
return scaledfile
success = self.RebuildArtwork(artworkname, resolution)
if not success:
return None
return scaledfile
[docs] def RebuildArtwork(self, artworkname, resolution):
"""
This method rebuilds an artwork with the specified resolution.
If the artwork does not exist for this resolution it will be generated.
If the directory for that scale does not exist, it will be created.
Its permission will be ``musicdb:musicdb drwxrwxr-x``
In case an error occurs, an exception gets raised.
The resolution is given as string in the format ``{X}x{Y}`` (For example: ``100x100``).
*X* and *Y* must have the same value.
This method expects an aspect ratio of 1:1.
Beside scaling the JPEG, it will be made progressive.
Args:
artworkname (str): filename of the source artwork (Usually ``$Artist - $Album.jpg``)
resolution (str): resolution of the requested artwork
Returns:
``True`` on success
Example:
.. code-block:: python
cache = ArtworkCache("/data/artwork")
if not cache.RebuildArtwork("example.jpg", "150x150"):
print("creating a 150x150 thumbnail failed")
"""
logging.debug("RebuildArtwork(%s, %s)", artworkname, resolution)
# Check if the scale-directory already exist. If not, create one
if not self.artworkroot.IsDirectory(resolution):
logging.debug("Creating subdirectory: %s", resolution)
try:
self.artworkroot.CreateSubdirectory(resolution)
self.artworkroot.SetAccessPermissions(resolution, "rwxrwxr-x")
except Exception as e:
logging.exception("Creating scaled artwork directory %s failed with error: %s.", resolution, str(e))
return False
# Scale image
logging.debug("Converting image to %s", resolution)
scaledfile = os.path.join(resolution, artworkname)
abssrcpath = self.artworkroot.AbsolutePath(artworkname)
absdstpath = self.artworkroot.AbsolutePath(scaledfile)
# "10x10" -> (10, 10)
length = int(resolution.split("x")[0])
size = (length, length)
im = Image.open(abssrcpath)
im.thumbnail(size, Image.BICUBIC)
im.save(absdstpath, "JPEG", optimize=True, progressive=True)
return True
# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4