art_radio.py 7.63 KB
Newer Older
1
# Copyright (c) 2014-2020 Cedric Bellegarde <cedric.bellegarde@adishatz.org>
Cédric Bellegarde's avatar
Cédric Bellegarde committed
2 3 4 5 6 7 8 9 10 11 12
# 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/>.

13
from gi.repository import GLib, GdkPixbuf, Gio
Cédric Bellegarde's avatar
Cédric Bellegarde committed
14 15 16

import re

Cédric Bellegarde's avatar
Cédric Bellegarde committed
17
from lollypop.helper_task import TaskHelper
Cédric Bellegarde's avatar
Cédric Bellegarde committed
18
from lollypop.logger import Logger
19
from lollypop.define import ArtBehaviour, CACHE_PATH
Cédric Bellegarde's avatar
Cédric Bellegarde committed
20
from lollypop.utils import escape, emit_signal
21
from lollypop.utils_file import create_dir
Cédric Bellegarde's avatar
Cédric Bellegarde committed
22 23


Cédric Bellegarde's avatar
Cédric Bellegarde committed
24
class RadioArt:
Cédric Bellegarde's avatar
Cédric Bellegarde committed
25
    """
Cédric Bellegarde's avatar
Cédric Bellegarde committed
26
        Manage radio artwork
Cédric Bellegarde's avatar
Cédric Bellegarde committed
27
    """
28
    _RADIOS_PATH = GLib.get_user_data_dir() + "/lollypop/radios"
Cédric Bellegarde's avatar
Cédric Bellegarde committed
29

Cédric Bellegarde's avatar
Cédric Bellegarde committed
30
    def __init__(self):
Cédric Bellegarde's avatar
Cédric Bellegarde committed
31 32
        """
            Init radio art
Cédric Bellegarde's avatar
Cédric Bellegarde committed
33
            Should be inherited by a BaseArt
Cédric Bellegarde's avatar
Cédric Bellegarde committed
34
        """
35
        create_dir(self._RADIOS_PATH)
Cédric Bellegarde's avatar
Cédric Bellegarde committed
36

37
    def get_radio_cache_path(self, name, width, height):
Cédric Bellegarde's avatar
Cédric Bellegarde committed
38
        """
39
            get cover cache path for radio
40
            @param name as str
41 42
            @param width as int
            @param height as int
Cédric Bellegarde's avatar
Cédric Bellegarde committed
43 44
            @return cover path as string or None if no cover
        """
Cédric Bellegarde's avatar
Cédric Bellegarde committed
45
        filename = ""
Cédric Bellegarde's avatar
Cédric Bellegarde committed
46
        try:
47
            filename = self.__get_radio_cache_name(name)
48
            cache_path_png = "%s/%s_%s_%s.png" % (CACHE_PATH,
49 50 51
                                                  filename,
                                                  width,
                                                  height)
52
            f = Gio.File.new_for_path(cache_path_png)
53
            if f.query_exists():
54
                return cache_path_png
Cédric Bellegarde's avatar
Cédric Bellegarde committed
55
            else:
56
                self.get_radio_artwork(name, width, height, 1)
57
                if f.query_exists():
58 59
                    return cache_path_png
        except Exception as e:
Cédric Bellegarde's avatar
Cédric Bellegarde committed
60 61
            Logger.error("RadioArt::get_radio_cache_path(): %s, %s" %
                         (e, ascii(filename)))
62 63
            return None

64 65 66
    def get_radio_artwork(self, name, width, height, scale_factor,
                          behaviour=ArtBehaviour.CACHE |
                          ArtBehaviour.CROP_SQUARE):
67 68
        """
            Return a cairo surface for radio name
69
            @param name as string
70 71
            @param width as int
            @param height as int
72 73
            @param scale_factor as int
            @param behaviour as ArtBehaviour
74
            @return GdkPixbuf.Pixbuf
75
        """
76 77
        width *= scale_factor
        height *= scale_factor
78
        filename = self.__get_radio_cache_name(name)
79
        cache_path_png = "%s/%s_%s_%s.png" % (CACHE_PATH, filename,
80
                                              width, height)
81 82 83
        pixbuf = None
        try:
            # Look in cache
84
            f = Gio.File.new_for_path(cache_path_png)
85
            if not behaviour & ArtBehaviour.NO_CACHE and f.query_exists():
86
                pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(cache_path_png,
87 88
                                                                width,
                                                                height)
89
            else:
90 91 92
                filepath = self.__get_radio_art_path(name)
                f = Gio.File.new_for_path(filepath)
                if f.query_exists():
93
                    pixbuf = GdkPixbuf.Pixbuf.new_from_file(filepath)
94 95
                    pixbuf = self.load_behaviour(pixbuf, cache_path_png,
                                                 width, height, behaviour)
Cédric Bellegarde's avatar
Cédric Bellegarde committed
96
        except Exception as e:
Cédric Bellegarde's avatar
Cédric Bellegarde committed
97
            Logger.error("RadioArt::get_radio_artwork(): %s" % e)
98
        return pixbuf
Cédric Bellegarde's avatar
Cédric Bellegarde committed
99

100
    def cache_radio_uri(self, uri, name):
Cédric Bellegarde's avatar
Cédric Bellegarde committed
101 102
        """
            Copy uri to cache at size
Cédric Bellegarde's avatar
Cédric Bellegarde committed
103 104
            @param uri as str
            @param name as str
Cédric Bellegarde's avatar
Cédric Bellegarde committed
105
        """
Cédric Bellegarde's avatar
Cédric Bellegarde committed
106 107 108 109
        helper = TaskHelper()
        helper.load_uri_content(uri,
                                None,
                                self.__on_uri_content,
110
                                name)
Cédric Bellegarde's avatar
Cédric Bellegarde committed
111

112 113 114
    def rename_radio(self, old_name, new_name):
        """
            Rename artwork
115 116
            @param old_name as str
            @param new_name as str
117
        """
118 119
        old = self.__get_radio_art_path(old_name)
        new = self.__get_radio_art_path(new_name)
120
        try:
121 122
            src = Gio.File.new_for_path(old)
            dst = Gio.File.new_for_path(new)
123 124
            if src.query_exists():
                src.move(dst, Gio.FileCopyFlags.OVERWRITE, None, None)
125
        except Exception as e:
Cédric Bellegarde's avatar
Cédric Bellegarde committed
126
            Logger.error("RadioArt::rename_radio(): %s" % e)
127

128
    def add_radio_artwork(self, name, data):
Cédric Bellegarde's avatar
Cédric Bellegarde committed
129
        """
130 131 132 133
            Add radio artwork to store
            @param name as str
            @param data as bytes
            @thread safe
Cédric Bellegarde's avatar
Cédric Bellegarde committed
134
        """
135 136 137 138 139 140 141 142
        self.uncache_radio_artwork(name)
        filepath = "%s/%s.png" % (self._RADIOS_PATH, escape(name))
        if data is None:
            f = Gio.File.new_for_path(filepath)
            fstream = f.replace(None, False,
                                Gio.FileCreateFlags.REPLACE_DESTINATION, None)
            fstream.close()
        else:
143
            bytes = GLib.Bytes.new(data)
144 145 146 147
            stream = Gio.MemoryInputStream.new_from_bytes(bytes)
            pixbuf = GdkPixbuf.Pixbuf.new_from_stream(stream, None)
            stream.close()
            pixbuf.savev(filepath, "png", [None], [None])
Cédric Bellegarde's avatar
Cédric Bellegarde committed
148
        emit_signal(self, "radio-artwork-changed", name)
Cédric Bellegarde's avatar
Cédric Bellegarde committed
149

150
    def uncache_radio_artwork(self, name):
Cédric Bellegarde's avatar
Cédric Bellegarde committed
151
        """
152
            Remove radio artwork from cache
153
            @param name as string
Cédric Bellegarde's avatar
Cédric Bellegarde committed
154
        """
Cédric Bellegarde's avatar
Cédric Bellegarde committed
155
        cache_name = self.__get_radio_cache_name(name)
Cédric Bellegarde's avatar
Cédric Bellegarde committed
156
        try:
157
            f = Gio.File.new_for_path(CACHE_PATH)
Cédric Bellegarde's avatar
Cédric Bellegarde committed
158
            infos = f.enumerate_children(
Cédric Bellegarde's avatar
Cédric Bellegarde committed
159
                "standard::name",
Cédric Bellegarde's avatar
Cédric Bellegarde committed
160 161 162 163 164
                Gio.FileQueryInfoFlags.NOFOLLOW_SYMLINKS,
                None)
            for info in infos:
                f = infos.get_child(info)
                basename = f.get_basename()
165
                if re.search(r"%s_.*\.png" % re.escape(cache_name), basename):
Cédric Bellegarde's avatar
Cédric Bellegarde committed
166
                    f.delete()
167
            infos.close(None)
Cédric Bellegarde's avatar
Cédric Bellegarde committed
168
        except Exception as e:
Cédric Bellegarde's avatar
Cédric Bellegarde committed
169 170
            Logger.error("RadioArt::clean_radio_cache(): %s, %s" %
                         (e, cache_name))
Cédric Bellegarde's avatar
Cédric Bellegarde committed
171 172 173 174

#######################
# PRIVATE             #
#######################
175
    def __get_radio_art_path(self, name):
Cédric Bellegarde's avatar
Cédric Bellegarde committed
176
        """
177 178 179
            Get radio artwork path
            @param name as str
            @return filepath as str
Cédric Bellegarde's avatar
Cédric Bellegarde committed
180
        """
181
        return "%s/%s.png" % (self._RADIOS_PATH, escape(name))
Cédric Bellegarde's avatar
Cédric Bellegarde committed
182

183
    def __get_radio_cache_name(self, name):
Cédric Bellegarde's avatar
Cédric Bellegarde committed
184 185
        """
            Get a uniq string for radio
186
            @param album_id as int
Cédric Bellegarde's avatar
Cédric Bellegarde committed
187 188
            @param sql as sqlite cursor
        """
189
        return "@@" + escape(name) + "@@radio@@"
Cédric Bellegarde's avatar
Cédric Bellegarde committed
190

191
    def __on_uri_content(self, uri, status, content, name):
Cédric Bellegarde's avatar
Cédric Bellegarde committed
192 193 194 195 196 197 198 199
        """
            Save image
            @param uri as str
            @param status as bool
            @param content as bytes  # The image
            @param name as str
        """
        if status:
200
            cache_path_png = self.__get_radio_art_path(name)
201
            bytes = GLib.Bytes.new(content)
Cédric Bellegarde's avatar
Cédric Bellegarde committed
202 203 204 205
            stream = Gio.MemoryInputStream.new_from_bytes(bytes)
            pixbuf = GdkPixbuf.Pixbuf.new_from_stream(stream, None)
            stream.close()
            pixbuf.savev(cache_path_png, "png", [None], [None])
Cédric Bellegarde's avatar
Cédric Bellegarde committed
206
            del pixbuf
Cédric Bellegarde's avatar
Cédric Bellegarde committed
207
            emit_signal(self, "radio-artwork-changed", name)