예제 #1
0
 def update_title(self):
     title = "{} [{}]"
     if self._s_type is SettingsType.ENIGMA_2:
         self._dialog.set_title(
             title.format(get_message("Options"),
                          self._enigma_radio_button.get_label()))
     elif self._s_type is SettingsType.NEUTRINO_MP:
         self._dialog.set_title(
             title.format(get_message("Options"),
                          self._neutrino_radio_button.get_label()))
예제 #2
0
    def __init__(self, transient, s_type, m3_path, app):
        super().__init__(transient, s_type)

        self._app = app
        self._picons = app.picons
        self._pic_path = app._settings.profile_picons_path
        self._services = None
        self._url_count = 0
        self._errors_count = 0
        self._max_count = 0
        self._is_download = False
        self._cancellable = Gio.Cancellable()
        self._dialog.set_title(get_message("Playlist import"))
        self._dialog.connect("delete-event", self.on_close)
        self._apply_button.set_label(get_message("Import"))
        # Progress
        self._progress_bar = Gtk.ProgressBar(visible=False, valign="center")
        self._spinner = Gtk.Spinner(active=False)
        self._info_label = Gtk.Label(visible=True,
                                     ellipsize="end",
                                     max_width_chars=30)
        load_label = Gtk.Label(label=get_message("Loading data..."))
        self._spinner.bind_property("active", self._spinner, "visible")
        self._spinner.bind_property("visible", load_label, "visible")
        self._spinner.bind_property("active", self._start_values_grid,
                                    "sensitive", 4)

        progress_box = Gtk.HBox(visible=True, spacing=2)
        progress_box.add(self._progress_bar)
        progress_box.pack_end(self._spinner, False, False, 0)
        progress_box.pack_start(load_label, False, False, 0)
        # Picons
        self._picons_switch = Gtk.Switch(visible=True)
        self._picon_box = Gtk.HBox(visible=True, sensitive=False, spacing=2)
        self._picon_box.pack_end(self._picons_switch, False, False, 0)
        self._picon_box.pack_end(
            Gtk.Label(visible=True, label=get_message("Download picons")),
            False, False, 0)
        # Extra box
        extra_box = Gtk.HBox(visible=True,
                             spacing=2,
                             margin_bottom=5,
                             margin_top=5)
        extra_box.set_center_widget(progress_box)
        extra_box.pack_start(self._info_label, False, False, 5)
        extra_box.pack_end(self._picon_box, True, True, 5)

        frame = Gtk.Frame(visible=True, margin_bottom=5)
        frame.add(extra_box)
        self._data_box.add(frame)

        self.get_m3u(m3_path, s_type)
예제 #3
0
    def on_auto_configuration(self, item):
        """ Simple mapping of services by name. """
        use_cyrillic = locale.getdefaultlocale()[0] in ("ru_RU", "be_BY",
                                                        "uk_UA", "sr_RS")
        tr = None
        if use_cyrillic:
            # may be not entirely correct
            symbols = (u"АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯІÏҐЎЈЂЉЊЋЏTB",
                       u"ABVGDEEJZIJKLMNOPRSTUFHZCSS_Y_EUAIEGUEDLNCJTV")
            tr = {ord(k): ord(v) for k, v in zip(*symbols)}

        source = {}
        for row in self._services_model:
            name = re.sub("\\W+", "", str(row[0])).upper()
            name = name.translate(tr) if use_cyrillic else name
            source[name] = row[1]

        success_count = 0
        not_founded = {}

        for r in self._bouquet_model:
            if r[Column.FAV_TYPE] != BqServiceType.IPTV.value:
                continue
            name = re.sub("\\W+", "", str(r[Column.FAV_SERVICE])).upper()
            if use_cyrillic:
                name = name.translate(tr)
            ref = source.get(
                name, None
            )  # Not [pop], because the list may contain duplicates or similar names!
            if ref:
                self.assign_data(r, ref, True)
                success_count += 1
            else:
                not_founded[name] = r
        # Additional attempt to search in the remaining elements
        for n in not_founded:
            for k in source:
                if k.startswith(n):
                    self.assign_data(not_founded[n], source[k], True)
                    success_count += 1
                    break

        self.update_epg_count()
        self.show_info_message(
            "{} {} {}".format(
                get_message("Done!"),
                get_message("Count of successfully configured services:"),
                success_count), Gtk.MessageType.INFO)
예제 #4
0
 def update_source_count_info(self):
     source_count = len(self._services_model)
     self._source_count_label.set_text(str(source_count))
     if self._enable_dat_filter and source_count == 0:
         msg = get_message(
             "Current epg.dat file does not contains references for the services of this bouquet!"
         )
         self.show_info_message(msg, Gtk.MessageType.WARNING)
예제 #5
0
파일: epg.py 프로젝트: audi06/DemonEditor
 def on_drag_data_get(self, view, drag_context, data, info, time):
     model, paths = view.get_selection().get_selected_rows()
     if paths:
         s_data = model[paths][:]
         if all(s_data):
             data.set_text("::::".join(s_data), -1)
         else:
             self.show_info_message(get_message("Source error!"),
                                    Gtk.MessageType.ERROR)
예제 #6
0
    def on_import(self, item):
        if not any(r[-1] for r in self._main_model):
            self.show_info_message(get_message("No selected item!"),
                                   Gtk.MessageType.ERROR)
            return

        if not self._bouquets or show_dialog(
                DialogType.QUESTION,
                self._dialog_window) == Gtk.ResponseType.CANCEL:
            return

        self.import_data()
예제 #7
0
    def set_yt_url(self, entry, video_id):
        try:
            if not self._yt_dl:

                def callback(message, error=True):
                    msg_type = Gtk.MessageType.ERROR if error else Gtk.MessageType.INFO
                    self.show_info_message(message, msg_type)

                self._yt_dl = YouTube.get_instance(self._settings,
                                                   callback=callback)
                yield True
            links, title = self._yt_dl.get_yt_link(video_id, entry.get_text())
            yield True
        except urllib.error.URLError as e:
            self.show_info_message(
                get_message("Getting link error:") + (str(e)),
                Gtk.MessageType.ERROR)
            return
        except YouTubeException as e:
            self.show_info_message((str(e)), Gtk.MessageType.ERROR)
            return
        else:
            if self._action is Action.ADD:
                self._name_entry.set_text(title)

            if links:
                if len(links) > 1:
                    self._yt_quality_box.set_visible(True)
                entry.set_text(links[sorted(links,
                                            key=lambda x: int(x.rstrip("p")),
                                            reverse=True)[0]])
                self._yt_links = links
            else:
                msg = get_message("Getting link error:"
                                  ) + " No link received for id: {}".format(
                                      video_id)
                self.show_info_message(msg, Gtk.MessageType.ERROR)
        finally:
            entry.set_sensitive(True)
        yield True
예제 #8
0
 def get_m3u(self, path, s_type):
     try:
         GLib.idle_add(self._spinner.set_property, "active", True)
         self._services = parse_m3u(path, s_type)
         for s in self._services:
             if s.picon:
                 GLib.idle_add(self._picon_box.set_sensitive, True)
                 break
     finally:
         msg = "{} {}.".format(get_message("Streams detected:"),
                               len(self._services) if self._services else 0)
         GLib.idle_add(self._info_label.set_text, msg)
         GLib.idle_add(self._spinner.set_property, "active", False)
예제 #9
0
    def update_progress(self):
        self._url_count -= 1
        frac = 1 - self._url_count / self._max_count
        self._progress_bar.set_fraction(frac)

        if self._url_count == 0:
            self._progress_bar.set_visible(False)
            self._progress_bar.set_fraction(0.0)
            self._apply_button.set_sensitive(True)
            self._info_label.set_text("{} {}.".format(get_message("Errors:"),
                                                      self._errors_count))
            self._is_download = False

            gen = self.update_fav_model()
            GLib.idle_add(lambda: next(gen, False), priority=GLib.PRIORITY_LOW)
예제 #10
0
    def assign_data(self, row, ref, show_error=False):
        if row[Column.FAV_TYPE] != BqServiceType.IPTV.value:
            if not show_error:
                self.show_info_message(
                    get_message("Not allowed in this context!"),
                    Gtk.MessageType.ERROR)
            return

        fav_id = row[Column.FAV_ID]
        fav_id_data = fav_id.split(":")
        fav_id_data[3:7] = ref.split(":")
        new_fav_id = ":".join(fav_id_data)
        service = self._services.pop(fav_id, None)
        if service:
            self._services[new_fav_id] = service
            row[Column.FAV_ID] = new_fav_id
            row[Column.FAV_LOCKED] = EPG_ICON
            row[Column.FAV_TOOLTIP] = ":".join(
                fav_id_data[:10]) if self._show_tooltips else None
예제 #11
0
    def on_save(self, item):
        if self._action is Action.ADD:
            self.on_url_changed(self._url_entry)

        if not is_data_correct(self._digit_elems) or self._url_entry.get_name(
        ) == _DIGIT_ENTRY_NAME:
            self.show_info_message(get_message("Error. Verify the data!"),
                                   Gtk.MessageType.ERROR)
            return

        if show_dialog(DialogType.QUESTION,
                       self._dialog) in (Gtk.ResponseType.CANCEL,
                                         Gtk.ResponseType.DELETE_EVENT):
            return

        self.save_enigma2_data(
        ) if self._s_type is SettingsType.ENIGMA_2 else self.save_neutrino_data(
        )
        self._dialog.destroy()
예제 #12
0
    def on_import(self, item):
        self.on_info_bar_close()
        self.update_active_elements(False)
        self._download_task = True

        try:
            with concurrent.futures.ThreadPoolExecutor(
                    max_workers=4) as executor:
                done_links = {}
                rows = list(filter(lambda r: r[2], self._model))
                if not self._yt:
                    self._yt = YouTube.get_instance(self._settings)

                futures = {
                    executor.submit(self._yt.get_yt_link, r[1],
                                    YouTube.VIDEO_LINK.format(r[1]), True): r
                    for r in rows
                }
                size = len(futures)
                counter = 0

                for future in concurrent.futures.as_completed(futures):
                    if not self._download_task:
                        executor.shutdown()
                        return

                    done_links[futures[future]] = future.result()
                    counter += 1
                    self.update_progress_bar(counter / size)
        except YouTubeException as e:
            self.show_info_message(str(e), Gtk.MessageType.ERROR)
        except Exception as e:
            self.show_info_message(str(e), Gtk.MessageType.ERROR)
        else:
            if self._download_task:
                self.show_info_message(get_message("Done!"),
                                       Gtk.MessageType.INFO)
                self.append_services([done_links[r] for r in rows])
        finally:
            self._download_task = False
            self.update_active_elements(True)
예제 #13
0
파일: epg.py 프로젝트: audi06/DemonEditor
    def assign_data(self, row, data, show_error=False):
        if row[Column.FAV_TYPE] != BqServiceType.IPTV.value:
            if not show_error:
                self.show_info_message(
                    get_message("Not allowed in this context!"),
                    Gtk.MessageType.ERROR)
            return

        fav_id = row[Column.FAV_ID]
        fav_id_data = fav_id.split(":")
        fav_id_data[3:7] = data[-1].split(":")
        new_fav_id = ":".join(fav_id_data)
        service = self._services.pop(fav_id, None)
        if service:
            self._services[new_fav_id] = service
            row[Column.FAV_ID] = new_fav_id
            row[Column.FAV_LOCKED] = EPG_ICON
            pos = f"({data[1] if self._refs_source is RefsSource.SERVICES else 'XML'})"
            src = f"{get_message('EPG source')}: {(GLib.markup_escape_text(data[0] or ''))} {pos}"
            row[Column.
                FAV_TOOLTIP] = f"{get_message('Service reference')}: {':'.join(fav_id_data[:10])}\n{src}"
예제 #14
0
    def on_save_to_xml(self, item):
        response = show_dialog(DialogType.CHOOSER,
                               self._dialog,
                               settings=self._settings)
        if response in (Gtk.ResponseType.CANCEL,
                        Gtk.ResponseType.DELETE_EVENT):
            return

        services = []
        iptv_types = (BqServiceType.IPTV.value, BqServiceType.MARKER.value)
        for r in self._bouquet_model:
            srv_type = r[Column.FAV_TYPE]
            if srv_type in iptv_types:
                srv = BouquetService(name=r[Column.FAV_SERVICE],
                                     type=BqServiceType(srv_type),
                                     data=r[Column.FAV_ID],
                                     num=r[Column.FAV_NUM])
                services.append(srv)

        ChannelsParser.write_refs_to_xml(
            "{}{}.xml".format(response, self._bouquet_name), services)
        self.show_info_message(get_message("Done!"), Gtk.MessageType.INFO)
예제 #15
0
    def init_xml_source(self, refs):
        path = self._epg_dat_path_entry.get_text(
        ) if self._use_web_source else self._xml_chooser_button.get_filename()
        if not path:
            self.show_info_message("The path to the xml file is not set!",
                                   Gtk.MessageType.ERROR)
            return

        if self._use_web_source:
            #  Downloading gzipped xml file that contains services names with references from the web.
            self._download_xml_is_active = True
            self.update_active_header_elements(False)
            url = self._url_to_xml_entry.get_text()

            try:
                with urllib.request.urlopen(url, timeout=2) as fp:
                    headers = fp.info()
                    content_type = headers.get("Content-Type", "")

                    if content_type != "application/gzip":
                        self._download_xml_is_active = False
                        raise ValueError("{} {} {}".format(
                            get_message("Download XML file error."),
                            get_message("Unsupported file type:"),
                            content_type))

                    file_name = os.path.basename(url)
                    data_path = self._epg_dat_path_entry.get_text()

                    with open(data_path + file_name, "wb") as tfp:
                        bs = 1024 * 8
                        size = -1
                        read = 0
                        b_num = 0
                        if "content-length" in headers:
                            size = int(headers["Content-Length"])

                        while self._download_xml_is_active:
                            block = fp.read(bs)
                            if not block:
                                break
                            read += len(block)
                            tfp.write(block)
                            b_num += 1
                            self.update_download_progress(b_num * bs / size)
                            yield True

                        path = tfp.name.rstrip(".gz")
            except (HTTPError, URLError) as e:
                raise ValueError("{} {}".format(
                    get_message("Download XML file error."), e))
            else:
                try:
                    with open(path, "wb") as f_out:
                        with gzip.open(tfp.name, "rb") as f:
                            shutil.copyfileobj(f, f_out)
                    os.remove(tfp.name)
                except Exception as e:
                    raise ValueError("{} {}".format(
                        get_message("Unpacking data error."), e))
            finally:
                self._download_xml_is_active = False
                self.update_active_header_elements(True)

        try:
            s_refs, info = ChannelsParser.get_refs_from_xml(path)
            yield True
        except Exception as e:
            raise ValueError("{} {}".format(get_message("XML parsing error:"),
                                            e))
        else:
            if refs:
                s_refs = filter(lambda x: x.num in refs, s_refs)
            list(
                map(lambda s: self._services_model.append((s.name, s.data)),
                    s_refs))
            self.update_source_info(info)
            self.update_source_count_info()
            yield True
예제 #16
0
파일: epg.py 프로젝트: audi06/DemonEditor
    def __init__(self, app, bouquet, bouquet_name):

        handlers = {
            "on_close_dialog": self.on_close_dialog,
            "on_apply": self.on_apply,
            "on_update": self.on_update,
            "on_save_to_xml": self.on_save_to_xml,
            "on_auto_configuration": self.on_auto_configuration,
            "on_filter_toggled": self.on_filter_toggled,
            "on_filter_changed": self.on_filter_changed,
            "on_info_bar_close": self.on_info_bar_close,
            "on_popup_menu": on_popup_menu,
            "on_bouquet_popup_menu": self.on_bouquet_popup_menu,
            "on_copy_ref": self.on_copy_ref,
            "on_assign_ref": self.on_assign_ref,
            "on_reset": self.on_reset,
            "on_list_reset": self.on_list_reset,
            "on_drag_begin": self.on_drag_begin,
            "on_drag_data_get": self.on_drag_data_get,
            "on_drag_data_received": self.on_drag_data_received,
            "on_resize": self.on_resize,
            "on_names_source_changed": self.on_names_source_changed,
            "on_options_save": self.on_options_save,
            "on_use_web_source_switch": self.on_use_web_source_switch,
            "on_enable_filtering_switch": self.on_enable_filtering_switch,
            "on_update_on_start_switch": self.on_update_on_start_switch,
            "on_field_icon_press": self.on_field_icon_press,
            "on_key_press": self.on_key_press,
            "on_bq_cursor_changed": self.on_bq_cursor_changed
        }

        self._app = app
        self._services = {}
        self._ex_services = self._app.current_services
        self._ex_fav_model = self._app.fav_view.get_model()
        self._settings = self._app.app_settings
        self._bouquet = bouquet
        self._bouquet_name = bouquet_name
        self._current_ref = []
        self._enable_dat_filter = False
        self._use_web_source = False
        self._update_epg_data_on_start = False
        self._refs_source = RefsSource.SERVICES
        self._download_xml_is_active = False

        builder = get_builder(UI_RESOURCES_PATH + "epg.glade", handlers)

        self._dialog = builder.get_object("epg_dialog_window")
        self._dialog.set_transient_for(self._app.app_window)
        self._source_view = builder.get_object("source_view")
        self._bouquet_view = builder.get_object("bouquet_view")
        self._bouquet_model = builder.get_object("bouquet_list_store")
        self._services_model = builder.get_object("services_list_store")
        self._info_bar = builder.get_object("info_bar")
        self._message_label = builder.get_object("info_bar_message_label")
        self._assign_ref_popup_item = builder.get_object(
            "bouquet_assign_ref_popup_item")
        self._left_action_box = builder.get_object("left_action_box")
        self._xml_download_progress_bar = builder.get_object(
            "xml_download_progress_bar")
        # Filter
        self._filter_bar = builder.get_object("filter_bar")
        self._filter_entry = builder.get_object("filter_entry")
        self._filter_auto_switch = builder.get_object("filter_auto_switch")
        self._services_filter_model = builder.get_object(
            "services_filter_model")
        self._services_filter_model.set_visible_func(
            self.services_filter_function)
        # Info
        self._source_count_label = builder.get_object("source_count_label")
        self._source_info_label = builder.get_object("source_info_label")
        self._bouquet_count_label = builder.get_object("bouquet_count_label")
        self._bouquet_epg_count_label = builder.get_object(
            "bouquet_epg_count_label")
        # Options
        self._xml_radiobutton = builder.get_object("xml_radiobutton")
        self._xml_chooser_button = builder.get_object("xml_chooser_button")
        self._names_source_box = builder.get_object("names_source_box")
        self._web_source_box = builder.get_object("web_source_box")
        self._use_web_source_switch = builder.get_object(
            "use_web_source_switch")
        self._url_to_xml_entry = builder.get_object("url_to_xml_entry")
        self._enable_filtering_switch = builder.get_object(
            "enable_filtering_switch")
        self._epg_dat_path_entry = builder.get_object("epg_dat_path_entry")
        self._epg_dat_stb_path_entry = builder.get_object(
            "epg_dat_stb_path_entry")
        self._update_on_start_switch = builder.get_object(
            "update_on_start_switch")
        self._epg_dat_source_box = builder.get_object("epg_dat_source_box")

        if IS_GNOME_SESSION:
            header_bar = Gtk.HeaderBar(
                visible=True,
                show_close_button=True,
                title="EPG",
                subtitle=get_message("List configuration"))
            self._dialog.set_titlebar(header_bar)
            builder.get_object("left_action_box").reparent(header_bar)
            right_box = builder.get_object("right_action_box")
            builder.get_object("main_actions_box").remove(right_box)
            header_bar.pack_end(right_box)
            builder.get_object("toolbar_box").set_visible(False)

        self._app.connect("epg-dat-downloaded", self.on_epg_dat_downloaded)

        # Setting the last size of the dialog window
        window_size = self._settings.get("epg_tool_window_size")
        if window_size:
            self._dialog.resize(*window_size)

        self.init_drag_and_drop()
        self.on_update()
예제 #17
0
 def show_info_message(self, text, message_type):
     self._info_bar.set_visible(False)
     self._info_bar.set_message_type(message_type)
     self._message_label.set_text(get_message(text))
     self._info_bar.set_visible(True)