1# Copyright (c) 2017-2021 Cedric Bellegarde <cedric.bellegarde@adishatz.org>
2# This program is free software: you can redistribute it and/or modify
3# it under the terms of the GNU General Public License as published by
4# the Free Software Foundation, either version 3 of the License, or
5# (at your option) any later version.
6# This program is distributed in the hope that it will be useful,
7# but WITHOUT ANY WARRANTY; without even the implied warranty of
8# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9# GNU General Public License for more details.
10# You should have received a copy of the GNU General Public License
11# along with this program. If not, see <http://www.gnu.org/licenses/>.
12
13from gi.repository import GObject, GLib, Gio, Gtk
14
15from time import time
16
17from eolie.define import App
18from eolie.utils import emit_signal
19
20
21class DownloadManager(GObject.GObject):
22    """
23        Downloads Manager
24    """
25    __gsignals__ = {
26        "download-start": (GObject.SignalFlags.RUN_FIRST, None, (str,)),
27        "download-finish": (GObject.SignalFlags.RUN_FIRST, None, ())
28    }
29
30    def __init__(self):
31        """
32            Init download manager
33        """
34        GObject.GObject.__init__(self)
35        self.__downloads = []
36        self.__finished = []
37
38    def add(self, download, filename=None):
39        """
40            Add a download
41            @param download as WebKit2.Download
42            @param filename as str/None
43        """
44        if download not in self.__downloads:
45            self.__downloads.append(download)
46            download.connect('finished', self.__on_finished)
47            download.connect('failed', self.__on_failed)
48            download.connect('decide-destination',
49                             self.__on_decide_destination, filename)
50
51    def remove(self, download):
52        """
53            Remove download
54            @param download as WebKit2.Download
55        """
56        if download in self.__downloads:
57            self.__downloads.remove(download)
58        if download in self.__finished:
59            self.__finished.remove(download)
60
61    def get(self):
62        """
63            Get running downloads
64            @return [WebKit2.Download]
65        """
66        return self.__downloads
67
68    def get_finished(self):
69        """
70            Get finished download
71            @return [WebKit2.Download]
72        """
73        return self.__finished
74
75    def cancel(self):
76        """
77            Cancel all downloads
78        """
79        for download in self.__downloads:
80            download.cancel()
81
82    @property
83    def active(self):
84        """
85            Is download active
86            @return bool
87        """
88        for download in self.__downloads:
89            if download.get_estimated_progress() != 1.0:
90                return True
91
92#######################
93# PRIVATE             #
94#######################
95    def __on_decide_destination(self, download, filename, wanted_filename):
96        """
97            Modify destination if needed
98            @param download as WebKit2.Download
99            @param filename as str
100            @param wanted_filename as str
101        """
102        filename = filename.replace("/", "_")
103        extension = filename.split(".")[-1]
104        if wanted_filename:
105            # FIXME We should find a way to pass good extension,
106            # fallback to avi
107            if extension == filename:
108                extension = "avi"
109            filename = wanted_filename + "." + extension
110        directory_uri = App().settings.get_value('download-uri').get_string()
111        if not directory_uri:
112            directory = GLib.get_user_special_dir(
113                GLib.UserDirectory.DIRECTORY_DOWNLOAD)
114            directory_uri = GLib.filename_to_uri(directory, None)
115        destination_uri = "%s/%s" % (directory_uri,
116                                     GLib.uri_escape_string(filename,
117                                                            None,
118                                                            False))
119        not_ok = True
120        i = 1
121        try:
122            while not_ok:
123                f = Gio.File.new_for_uri(destination_uri)
124                if f.query_exists():
125                    extension_less = filename.replace(".%s" % extension, "")
126                    new_filename = "%s_%s.%s" % (extension_less, i, extension)
127                    destination_uri = "%s/%s" % (directory_uri,
128                                                 GLib.uri_escape_string(
129                                                     new_filename,
130                                                     None,
131                                                     False))
132                else:
133                    not_ok = False
134                i += 1
135        except:
136            # Fallback to be sure
137            destination_uri = "%s/@@%s" % (directory_uri,
138                                           GLib.uri_escape_string(
139                                               filename,
140                                               None,
141                                               False))
142
143        webkit_uri = GLib.uri_unescape_string(destination_uri, None)
144        download.set_destination(webkit_uri)
145        emit_signal(self, "download-start", str(download))
146        # Notify user about download
147        window = App().active_window
148        if window is not None:
149            window.toolbar.end.show_download(download)
150
151    def __on_finished(self, download):
152        """
153            @param download as WebKit2.Download
154        """
155        self.remove(download)
156        self.__finished.append(download)
157        emit_signal(self, "download-finish")
158        if App().settings.get_value("open-downloads"):
159            destination = download.get_destination()
160            f = Gio.File.new_for_uri(destination)
161            if f.query_exists():
162                Gtk.show_uri(None, destination, int(time()))
163
164    def __on_failed(self, download, error):
165        """
166            @param download as WebKit2.Download
167            @param error as GLib.Error
168        """
169        self.remove(download)
170        self.__finished.append(download)
171