diff --git a/app/connections.py b/app/connections.py index cad6ba94..acd3cd65 100644 --- a/app/connections.py +++ b/app/connections.py @@ -23,6 +23,7 @@ _DATA_FILES_LIST = ("lamedb", "lamedb5", "services.xml", "blacklist", "whitelist _SAT_XML_FILE = "satellites.xml" _WEBTV_XML_FILE = "webtv.xml" +_PICONS_SUF = (".jpg", ".png") class DownloadType(Enum): @@ -83,6 +84,11 @@ def download_data(*, settings, download_type=DownloadType.ALL, callback=print): download_file(ftp, _SAT_XML_FILE, save_path, callback) if download_type in (DownloadType.ALL, DownloadType.WEBTV) and name.endswith(_WEBTV_XML_FILE): download_file(ftp, _WEBTV_XML_FILE, save_path, callback) + + if download_type is DownloadType.PICONS: + picons_path = settings.picons_local_path + os.makedirs(os.path.dirname(picons_path), exist_ok=True) + download_picons(ftp, settings.picons_path, picons_path, callback) # epg.dat if download_type is DownloadType.EPG: stb_path = settings.services_path @@ -216,6 +222,8 @@ def upload_xml(ftp, data_path, xml_path, xml_file, callback): send_file(xml_file, data_path, ftp, callback) +# ***************** Picons *******************# + def upload_picons(ftp, src, dest, callback): try: ftp.cwd(dest) @@ -223,17 +231,55 @@ def upload_picons(ftp, src, dest, callback): if str(e).startswith("550"): ftp.mkd(dest) # if not exist ftp.cwd(dest) + + delete_picons(ftp, callback) + + for file_name in os.listdir(src): + if file_name.endswith(_PICONS_SUF): + send_file(file_name, src, ftp, callback) + + +def download_picons(ftp, src, dest, callback): + try: + ftp.cwd(src) + except error_perm as e: + callback(str(e)) + return + files = [] ftp.dir(files.append) - picons_suf = (".jpg", ".png") + for file in files: name = str(file).strip() - if name.endswith(picons_suf): + if name.endswith(_PICONS_SUF): name = name.split()[-1] - ftp.delete(name) - for file_name in os.listdir(src): - if file_name.endswith(picons_suf): - send_file(file_name, src, ftp, callback) + download_file(ftp, name, dest, callback) + + +def delete_picons(ftp, callback, dest=None): + if dest: + try: + ftp.cwd(dest) + except error_perm as e: + callback(str(e)) + return + + files = [] + ftp.dir(files.append) + for file in files: + name = str(file).strip() + if name.endswith(_PICONS_SUF): + name = name.split()[-1] + callback("Delete file: {}. Status: {}\n".format(name, ftp.delete(name))) + + +def remove_picons(*, settings, callback, done_callback=None): + with FTP(host=settings.host, user=settings.user, passwd=settings.password) as ftp: + ftp.encoding = "utf-8" + callback("FTP OK.\n") + delete_picons(ftp, callback, settings.picons_path) + if done_callback: + done_callback() def download_file(ftp, name, save_path, callback): diff --git a/app/ui/picons_dialog.glade b/app/ui/picons_dialog.glade index 77da4ce2..be299a79 100644 --- a/app/ui/picons_dialog.glade +++ b/app/ui/picons_dialog.glade @@ -153,6 +153,17 @@ Author: Dmitriy Yefremov 0 + + + True + False + + + False + True + 1 + + True @@ -171,17 +182,6 @@ Author: Dmitriy Yefremov - - False - True - 1 - - - - - True - False - False True @@ -210,6 +210,59 @@ Author: Dmitriy Yefremov 3 + + + True + False + + + False + True + 4 + + + + + True + True + True + Download picons from the receiver + + + + True + False + gtk-go-down + + + + + False + True + 5 + + + + + True + True + True + Remove picons from the receiver + + + + True + False + gtk-delete + + + + + False + True + 6 + + 6 diff --git a/app/ui/picons_downloader.py b/app/ui/picons_downloader.py index 6a343d61..44a73279 100644 --- a/app/ui/picons_downloader.py +++ b/app/ui/picons_downloader.py @@ -7,13 +7,13 @@ import tempfile from gi.repository import GLib, GdkPixbuf from app.commons import run_idle, run_task -from app.connections import upload_data, DownloadType -from app.tools.picons import PiconsParser, parse_providers, Provider, convert_to +from app.connections import upload_data, DownloadType, download_data, remove_picons from app.settings import SettingsType +from app.tools.picons import PiconsParser, parse_providers, Provider, convert_to from app.tools.satellites import SatellitesParser, SatelliteSource -from .uicommons import Gtk, Gdk, UI_RESOURCES_PATH, TEXT_DOMAIN, TV_ICON from .dialogs import show_dialog, DialogType, get_message from .main_helper import update_entry_data, append_text_to_tview, scroll_to, on_popup_menu +from .uicommons import Gtk, Gdk, UI_RESOURCES_PATH, TEXT_DOMAIN, TV_ICON class PiconsDialog: @@ -32,6 +32,8 @@ class PiconsDialog: "on_cancel": self.on_cancel, "on_close": self.on_close, "on_send": self.on_send, + "on_download": self.on_download, + "on_remove": self.on_remove, "on_info_bar_close": self.on_info_bar_close, "on_picons_dir_open": self.on_picons_dir_open, "on_selected_toggled": self.on_selected_toggled, @@ -77,9 +79,11 @@ class PiconsDialog: self._resize_220_132_radio_button = builder.get_object("resize_220_132_radio_button") self._resize_100_60_radio_button = builder.get_object("resize_100_60_radio_button") self._satellite_label = builder.get_object("satellite_label") + self._header_download_box = builder.get_object("header_download_box") self._satellite_label.bind_property("visible", builder.get_object("loading_data_label"), "visible", 4) self._satellite_label.bind_property("visible", builder.get_object("loading_data_spinner"), "visible", 4) - self._cancel_button.bind_property("visible", builder.get_object("header_download_box"), "visible", 4) + self._cancel_button.bind_property("visible", self._header_download_box, "visible", 4) + self._convert_button.bind_property("visible", self._header_download_box, "visible", 4) # style self._style_provider = Gtk.CssProvider() self._style_provider.load_from_path(UI_RESOURCES_PATH + "style.css") @@ -92,6 +96,10 @@ class PiconsDialog: self._picons_path = self._settings.picons_local_path self._picons_dir_entry.set_text(self._picons_path) + window_size = self._settings.get("picons_downloader_window_size") + if window_size: + self._dialog.resize(*window_size) + if not len(self._picon_ids) and self._s_type is SettingsType.ENIGMA_2: message = get_message("To automatically set the identifiers for picons,\n" "first load the required services list into the main application window.") @@ -135,14 +143,19 @@ class PiconsDialog: self._cancel_button.show() url = self._url_entry.get_text() - self._current_process = subprocess.Popen(["wget", "-pkP", self._TMP_DIR, url], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - universal_newlines=True) - GLib.io_add_watch(self._current_process.stderr, GLib.IO_IN, self.write_to_buffer) - model = self._providers_tree_view.get_model() - model.clear() - self.append_providers(url, model) + try: + self._current_process = subprocess.Popen(["wget", "-pkP", self._TMP_DIR, url], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + universal_newlines=True) + except FileNotFoundError as e: + self._cancel_button.hide() + self.show_info_message(str(e), Gtk.MessageType.ERROR) + else: + GLib.io_add_watch(self._current_process.stderr, GLib.IO_IN, self.write_to_buffer) + model = self._providers_tree_view.get_model() + model.clear() + self.append_providers(url, model) @run_task def append_providers(self, url, model): @@ -253,9 +266,16 @@ class PiconsDialog: if self.on_cancel(): return True + self.save_window_size(window) self.clean_data() GLib.idle_add(self._dialog.destroy) + def save_window_size(self, window): + t, _ = self._text_view.get_allocated_size() + b, _ = self._info_bar.get_allocated_size() + size = window.get_size() + self._settings.add("picons_downloader_window_size", (size.width, size.height - t.height - b.height)) + @run_task def clean_data(self): path = self._TMP_DIR + "www.lyngsat.com" @@ -267,22 +287,38 @@ class PiconsDialog: return self.show_info_message(get_message("Please, wait..."), Gtk.MessageType.INFO) - self.upload_picons() + self.run_func(lambda: upload_data(settings=self._settings, + download_type=DownloadType.PICONS, + callback=self.append_output, + done_callback=lambda: self.show_info_message(get_message("Done!"), + Gtk.MessageType.INFO))) - @run_task - def upload_picons(self): - if self.is_task_running(): - self.show_dialog("The task is already running!", DialogType.ERROR) + def on_download(self, item): + if show_dialog(DialogType.QUESTION, self._dialog) == Gtk.ResponseType.CANCEL: return + self.run_func(lambda: download_data(settings=self._settings, + download_type=DownloadType.PICONS, + callback=self.append_output)) + + def on_remove(self, item): + if show_dialog(DialogType.QUESTION, self._dialog) == Gtk.ResponseType.CANCEL: + return + + self.run_func(lambda: remove_picons(settings=self._settings, + callback=self.append_output, + done_callback=lambda: self.show_info_message(get_message("Done!"), + Gtk.MessageType.INFO))) + + @run_task + def run_func(self, func): try: GLib.idle_add(self._expander.set_expanded, True) - upload_data(settings=self._settings, - download_type=DownloadType.PICONS, - callback=self.append_output, - done_callback=lambda: self.show_info_message(get_message("Done!"), Gtk.MessageType.INFO)) + GLib.idle_add(self._header_download_box.set_sensitive, False) + func() except OSError as e: self.show_info_message(str(e), Gtk.MessageType.ERROR) + GLib.idle_add(self._header_download_box.set_sensitive, True) def on_info_bar_close(self, bar=None, resp=None): self._info_bar.set_visible(False) @@ -323,10 +359,7 @@ class PiconsDialog: @run_idle def on_notebook_switch_page(self, nb, box, tab_num): - self._load_providers_button.set_visible(not tab_num) - self._receive_button.set_visible(not tab_num) self._convert_button.set_visible(tab_num) - self._send_button.set_visible(not tab_num) @run_idle def on_convert(self, item):