From 3f0738d8746a30611c97d422b588b6dad07ea29f Mon Sep 17 00:00:00 2001 From: Dmitriy Yefremov Date: Mon, 23 Apr 2018 14:42:41 +0300 Subject: [PATCH] skeleton of satellites downloader --- app/{picons => tools}/__init__.py | 0 app/{picons => tools}/picons.py | 4 +- app/tools/satellites.py | 75 +++++++++++ app/ui/dialogs.glade | 2 +- app/ui/lang/ru/LC_MESSAGES/demon-editor.mo | Bin 10726 -> 10806 bytes app/ui/main_app_window.py | 8 +- app/ui/main_window.glade | 29 ++++- app/ui/{picons_dialog.glade => tools.glade} | 121 ++++++++++++++++++ app/ui/tools/__init__.py | 0 .../picons_downloader.py} | 10 +- app/ui/tools/satellites_downloader.py | 24 ++++ build-deb.sh | 2 +- .../locale/ru/LC_MESSAGES/demon-editor.mo | Bin 10726 -> 10806 bytes po/ru/demon-editor.mo | Bin 10726 -> 10806 bytes po/ru/demon-editor.po | 5 +- 15 files changed, 265 insertions(+), 15 deletions(-) rename app/{picons => tools}/__init__.py (100%) rename app/{picons => tools}/picons.py (100%) create mode 100644 app/tools/satellites.py rename app/ui/{picons_dialog.glade => tools.glade} (88%) create mode 100644 app/ui/tools/__init__.py rename app/ui/{picons_dialog.py => tools/picons_downloader.py} (97%) create mode 100644 app/ui/tools/satellites_downloader.py diff --git a/app/picons/__init__.py b/app/tools/__init__.py similarity index 100% rename from app/picons/__init__.py rename to app/tools/__init__.py diff --git a/app/picons/picons.py b/app/tools/picons.py similarity index 100% rename from app/picons/picons.py rename to app/tools/picons.py index 342a017f..3e37a7f7 100644 --- a/app/picons/picons.py +++ b/app/tools/picons.py @@ -1,11 +1,11 @@ import glob import os +import re import shutil + from collections import namedtuple from html.parser import HTMLParser -import re - from app.commons import log, run_task from app.properties import Profile diff --git a/app/tools/satellites.py b/app/tools/satellites.py new file mode 100644 index 00000000..687fd514 --- /dev/null +++ b/app/tools/satellites.py @@ -0,0 +1,75 @@ +""" Module for download satellites from internet ("flysat.com") + for replace or update current satellites.xml file. +""" +import requests + +from html.parser import HTMLParser + + +class SatellitesParser(HTMLParser): + """ Parser for satellite html page. (https://www.lyngsat.com/*sat-name*.html) """ + + _HEADERS = {"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:45.0) Gecko/20100101 Firefox/59.02"} + + def __init__(self, url, entities=False, separator=' '): + + HTMLParser.__init__(self) + + self._parse_html_entities = entities + self._separator = separator + self._is_td = False + self._is_th = False + self._is_provider = False + self._current_row = [] + self._current_cell = [] + self._rows = [] + self._url = url + + def handle_starttag(self, tag, attrs): + if tag == 'td': + self._is_td = True + if tag == 'tr': + self._is_th = True + if tag == "a": + self._current_row.append(attrs[0][1]) + + def handle_data(self, data): + """ Save content to a cell """ + if self._is_td or self._is_th: + self._current_cell.append(data.strip()) + + def handle_endtag(self, tag): + if tag == 'td': + self._is_td = False + elif tag == 'tr': + self._is_th = False + + if tag in ('td', 'th'): + final_cell = self._separator.join(self._current_cell).strip() + self._current_row.append(final_cell) + self._current_cell = [] + elif tag == 'tr': + row = self._current_row + self._rows.append(row) + self._current_row = [] + + def error(self, message): + pass + + def get_satellites(self): + self.reset() + request = requests.get(url=self._url, headers=self._HEADERS) + reason = request.reason + if reason == "OK": + print(reason) + self.feed(request.text) + if self._rows: + for num, sat in enumerate(filter(lambda x: all(x) and len(x) == 5, self._rows)): + print(num + 1, sat) + else: + print(reason) + + +if __name__ == "__main__": + parser = SatellitesParser(url="https://www.flysat.com/satlist.php") + parser.get_satellites() diff --git a/app/ui/dialogs.glade b/app/ui/dialogs.glade index 839b60ad..080a8627 100644 --- a/app/ui/dialogs.glade +++ b/app/ui/dialogs.glade @@ -9,7 +9,7 @@ system-help normal DemonEditor - 0.3.1 Pre-alpha + 0.3.2 Pre-alpha 2018 Dmitriy Yefremov Enigma2 channel and satellites list editor for GNU/Linux diff --git a/app/ui/lang/ru/LC_MESSAGES/demon-editor.mo b/app/ui/lang/ru/LC_MESSAGES/demon-editor.mo index 5475f0979f9c79e17b850212dca9b8ec087b7dda..08157d3efa82793efd079c676ac458f015cc48eb 100644 GIT binary patch delta 2918 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 gtk-save-as + + True + False + gtk-goto-bottom + True False @@ -794,8 +799,24 @@ - - Picons loader + + Satellites downloader + True + False + image10 + False + + + + + + True + False + + + + + Picons downloader True False True @@ -805,7 +826,7 @@ - + True False @@ -2469,7 +2490,7 @@ True False - Ver. 0.3.1 Pre-alpha + Ver. 0.3.2 Pre-alpha 0.94999998807907104 diff --git a/app/ui/picons_dialog.glade b/app/ui/tools.glade similarity index 88% rename from app/ui/picons_dialog.glade rename to app/ui/tools.glade index ea187745..adcf444b 100644 --- a/app/ui/picons_dialog.glade +++ b/app/ui/tools.glade @@ -839,4 +839,125 @@ + + + + False + Satellites download tool + True + True + dialog + True + + + 320 + False + vertical + 2 + + + False + end + + + + + + + + + False + False + 0 + + + + + True + False + vertical + + + True + False + Not implemented yet! + + + False + True + 0 + + + + + True + False + + + True + False + Source: + + + False + True + 0 + + + + + True + False + source_urls_list_store + + + False + True + 1 + + + + + False + True + 1 + + + + + 100 + True + True + satellites_list_store + + + + + + False + True + 2 + + + + + True + False + + + False + True + 4 + + + + + False + True + 1 + + + + + diff --git a/app/ui/tools/__init__.py b/app/ui/tools/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/app/ui/picons_dialog.py b/app/ui/tools/picons_downloader.py similarity index 97% rename from app/ui/picons_dialog.py rename to app/ui/tools/picons_downloader.py index eb57185b..45b5440e 100644 --- a/app/ui/picons_dialog.py +++ b/app/ui/tools/picons_downloader.py @@ -7,11 +7,11 @@ from gi.repository import GLib, GdkPixbuf from app.commons import run_idle, run_task from app.ftp import upload_data, DownloadDataType -from app.picons.picons import PiconsParser, parse_providers, Provider, convert_to +from app.tools.picons import PiconsParser, parse_providers, Provider, convert_to from app.properties import Profile -from .uicommons import Gtk, Gdk, UI_RESOURCES_PATH, TEXT_DOMAIN -from .dialogs import show_dialog, DialogType, get_message -from .main_helper import update_entry_data +from app.ui.uicommons import Gtk, Gdk, UI_RESOURCES_PATH, TEXT_DOMAIN +from app.ui.dialogs import show_dialog, DialogType, get_message +from app.ui.main_helper import update_entry_data class PiconsDialog: @@ -38,7 +38,7 @@ class PiconsDialog: builder = Gtk.Builder() builder.set_translation_domain(TEXT_DOMAIN) - builder.add_objects_from_file(UI_RESOURCES_PATH + "picons_dialog.glade", + builder.add_objects_from_file(UI_RESOURCES_PATH + "tools.glade", ("picons_dialog", "receive_image", "providers_list_store")) builder.connect_signals(handlers) self._dialog = builder.get_object("picons_dialog") diff --git a/app/ui/tools/satellites_downloader.py b/app/ui/tools/satellites_downloader.py new file mode 100644 index 00000000..17f3d503 --- /dev/null +++ b/app/ui/tools/satellites_downloader.py @@ -0,0 +1,24 @@ +from app.ui.uicommons import Gtk, UI_RESOURCES_PATH, TEXT_DOMAIN + + +class SatellitesDownloaderDialog: + def __init__(self, transient, options): + + handlers = {} + + builder = Gtk.Builder() + builder.set_translation_domain(TEXT_DOMAIN) + builder.add_objects_from_file(UI_RESOURCES_PATH + "tools.glade", + ("satellites_dialog", "source_urls_list_store", "satellites_list_store")) + builder.connect_signals(handlers) + self._dialog = builder.get_object("satellites_dialog") + self._dialog.set_transient_for(transient) + self._satellites_tree_view = builder.get_object("satellites_tree_view") + + def show(self): + self._dialog.run() + self._dialog.destroy() + + +if __name__ == "__main__": + pass diff --git a/build-deb.sh b/build-deb.sh index d0d7a67d..5f6bb155 100755 --- a/build-deb.sh +++ b/build-deb.sh @@ -1,5 +1,5 @@ #!/bin/bash -VER="0.3.1_Pre-alpha" +VER="0.3.2_Pre-alpha" B_PATH="dist/DemonEditor" DEB_PATH="$B_PATH/usr/share/demoneditor" diff --git a/deb/usr/share/locale/ru/LC_MESSAGES/demon-editor.mo b/deb/usr/share/locale/ru/LC_MESSAGES/demon-editor.mo index 5475f0979f9c79e17b850212dca9b8ec087b7dda..08157d3efa82793efd079c676ac458f015cc48eb 100644 GIT binary patch delta 2918 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