def init(self): """ Initializes dict with values: download_id -> perm link and provider data. """ if self._perm_links: return self._HEADER["Referer"] = self._PERM_URL with requests.get(url=self._PERM_URL, headers=self._HEADER, stream=True) as request: if request.reason == "OK": logo_map = self.get_logos_map() name_map = self.get_name_map() for line in request.iter_lines(): data = line.decode(encoding="utf-8", errors="ignore").split(maxsplit=1) if len(data) != 2: continue l_id, perm_link = data self._perm_links[str(l_id)] = str(perm_link) data = re.match(self._LINK_PATTERN, perm_link) if data: sat_pos = data.group(3) # Logo url. logo = logo_map.get(data.group(2), None) l_name = name_map.get(sat_pos, None) or sat_pos.replace(".", "") logo_url = f"{self._BASE_LOGO_URL}{logo}/{l_name}.png" if logo else None prv = Provider(None, data.group(1), sat_pos, self._BASE_URL + l_id, l_id, logo_url, None, False) if sat_pos in self._providers: self._providers[sat_pos].append(prv) else: self._providers[sat_pos] = [prv] else: log(f"{self.__class__.__name__} [get permalinks] error: {request.reason}") raise PiconsError(request.reason)
def handle_data(self, data): if self._is_script: data = data.lstrip() if data.startswith(self._scr_start): data = data.split(";")[0] for s in self._scr_start: data = data.lstrip(s) try: resp = json.loads(data) except JSONDecodeError as e: log("{}: Parsing data error: {}".format(__class__.__name__, e)) else: sb = resp.get("sidebar", None) if sb: for t in [t["runs"][0] for t in flat("title", sb) if "runs" in t]: txt = t.get("text", None) if txt: self._header = txt break ct = resp.get("contents", None) if ct: for d in [(d.get("title", {}).get("runs", [{}])[0].get("text", ""), d.get("videoId", "")) for d in flat("playlistVideoRenderer", ct)]: self._playlist.append(d) self._is_script = False
def parse_v4(path): """ Parsing version 4 """ with open(path + _FILE_NAME, "r", encoding="utf-8", errors="replace") as file: try: data = str(file.read()) except UnicodeDecodeError as e: log("lamedb parse error: " + str(e)) else: transponders, sep, services = data.partition( "transponders") # 1 step pattern = re.compile("/[34]/$") match = re.search(pattern, transponders) if not match: msg = "lamedb parsing error: unsupported format." log(msg) raise SyntaxError(msg) transponders, sep, services = services.partition( "services") # 2 step services, sep, _ = services.partition("\nend") # 3 step if match.group() == "/3/": return parse_v3(services.split("\n"), parse_transponders(transponders.split("/")), path) return parse_services(services.split("\n"), parse_transponders(transponders.split("/")), path)
def on_end(event): event = event.get("event", {}) if event.get("reason", mpv.MpvEventEndFile.ERROR ) == mpv.MpvEventEndFile.ERROR: log("Stream playback error: {}".format( event.get("error", mpv.ErrorCode.GENERIC))) error_cb()
def get_window_handle(self, widget): """ Returns the identifier [pointer] for the window. Based on gtkvlc.py[get_window_pointer] example from here: https://github.com/oaubert/python-vlc/tree/master/examples """ if sys.platform == "linux": return widget.get_window().get_xid() else: is_darwin = sys.platform == "darwin" try: import ctypes libgdk = ctypes.CDLL( "libgdk-3.0.dylib" if is_darwin else "libgdk-3-0.dll") except OSError as e: log("{}: Load library error: {}".format(__class__.__name__, e)) else: # https://gitlab.gnome.org/GNOME/pygobject/-/issues/112 ctypes.pythonapi.PyCapsule_GetPointer.restype = ctypes.c_void_p ctypes.pythonapi.PyCapsule_GetPointer.argtypes = [ ctypes.py_object ] gpointer = ctypes.pythonapi.PyCapsule_GetPointer( widget.get_window().__gpointer__, None) get_pointer = libgdk.gdk_quartz_window_get_nsview if is_darwin else libgdk.gdk_win32_window_get_handle get_pointer.restype = ctypes.c_void_p get_pointer.argtypes = [ctypes.c_void_p] return get_pointer(gpointer)
def download(self, download, d_type): """ Download/upload data from/to receiver """ GLib.idle_add(self._expander.set_expanded, True) self.clear_output() backup, backup_src, data_path = self._settings.backup_before_downloading, None, None try: if download: if backup and d_type is not DownloadType.SATELLITES: data_path = self._settings.data_local_path or self._data_path_entry.get_text() os.makedirs(os.path.dirname(data_path), exist_ok=True) backup_path = self._settings.backup_local_path or data_path + "backup/" backup_src = backup_data(data_path, backup_path, d_type is DownloadType.ALL) download_data(settings=self._settings, download_type=d_type, callback=self.append_output) else: self.show_info_message(get_message("Please, wait..."), Gtk.MessageType.INFO) upload_data(settings=self._settings, download_type=d_type, remove_unused=self._remove_unused_check_button.get_active(), callback=self.append_output, done_callback=lambda: self.show_info_message(get_message("Done!"), Gtk.MessageType.INFO), use_http=self._use_http_switch.get_active()) except Exception as e: msg = "Downloading data error: {}" log(msg.format(e), debug=self._settings.debug_mode, fmt_message=msg) self.show_info_message(str(e), Gtk.MessageType.ERROR) if all((download, backup, data_path)): restore_data(backup_src, data_path) else: if download and d_type is not DownloadType.SATELLITES: GLib.idle_add(self._open_data_callback)
def __init__(self, mode, widget, buf_cb, position_cb, error_cb, playing_cb): try: from app.tools import mpv self._player = mpv.MPV(wid=str( self.get_window_handle(self.get_video_widget(widget), )), input_default_bindings=False, input_cursor=False, cursor_autohide="no") except OSError as e: log("{}: Load library error: {}".format(__class__.__name__, e)) raise ImportError( "No libmpv is found. Check that it is installed!") else: self._mode = mode self._is_playing = False @self._player.event_callback(mpv.MpvEventID.FILE_LOADED) def on_open(event): log("Starting playback...") playing_cb() @self._player.event_callback(mpv.MpvEventID.END_FILE) def on_end(event): event = event.get("event", {}) if event.get("reason", mpv.MpvEventEndFile.ERROR ) == mpv.MpvEventEndFile.ERROR: log("Stream playback error: {}".format( event.get("error", mpv.ErrorCode.GENERIC))) error_cb()
def init_callback(self, info): if info: version = info.get("e2webifversion", "").upper() self._is_owif = "OWIF" in version version_info = "Web Interface version: {}".format( version) if version else "" log("HTTP API initialized... {}".format(version_info))
def copy_to_pc(self, uris): cur_path = self._file_model.get_value( self._file_model.get_iter_first(), self.Column.ATTR) + "/" try: GLib.idle_add(self._app.wait_dialog.show) if len(uris) == 1: uris = uris[0].split( self.URI_SEP if self._settings.is_darwin else "\n") for uri in uris: name, sep, attr = unquote(Path(uri).name).partition(":") if not attr: return True if attr[0] == "d": self._ftp.download_dir(name, cur_path, self.update_ftp_info) else: self._ftp.download_file(name, cur_path, self.update_ftp_info) except OSError as e: log(e) finally: GLib.idle_add(self._app.wait_dialog.hide) self.init_file_data(cur_path)
def delete_dir(self, path, callback=None): files = [] self.dir(path, files.append) for f in files: f_data = self.get_file_data(f) f_path = f"{path}/{f_data[8]}" if f_data[0][0] == "d": self.delete_dir(f_path, callback) else: self.delete_file(f_path, callback) msg = "Remove directory {}. Status: {}\n" try: resp = self.rmd(path) except Error as e: msg = msg.format(path, e) log(msg) return "500" else: msg = msg.format(path, resp) log(msg.rstrip()) if callback: callback(msg) return resp
def init_dl(self): try: import youtube_dl except ModuleNotFoundError as e: log(f"YouTubeDLHelper error: {e}") raise YouTubeException(e) except ImportError as e: log(f"YouTubeDLHelper error: {e}") else: if self._path not in youtube_dl.__file__: msg = "Another version of youtube-dl was found on your system!" log(msg) raise YouTubeException(msg) if self._update: if hasattr(youtube_dl.version, "__version__"): l_ver = self.get_last_release_id() cur_ver = youtube_dl.version.__version__ if l_ver and youtube_dl.version.__version__ < l_ver: msg = f"youtube-dl has new release!\nCurrent: {cur_ver}. Last: {l_ver}." show_notification(msg) log(msg) self._callback(msg, False) self.get_latest_release() self._DownloadError = youtube_dl.utils.DownloadError self._dl = youtube_dl.YoutubeDL(self._OPTIONS) msg = "youtube-dl initialized..." show_notification(msg) log(msg)
def get_yt_link_by_id(video_id): """ Getting link to YouTube video by id. Returns tuple from the video links dict and title. """ info = InnerTube().player(video_id) det = info.get("videoDetails", None) title = det.get("title", None) if det else None streaming_data = info.get("streamingData", None) fmts = streaming_data.get("formats", None) if streaming_data else None if fmts: links = { Quality[i["itag"]]: i["url"] for i in filter(lambda i: i.get("itag", -1) in Quality, fmts) if "url" in i } if links and title: return links, title.replace("+", " ") cause = None status = info.get("playabilityStatus", None) if status: cause = f"[{status.get('status', '')}] {status.get('reason', '')}" log(f"{__class__.__name__}: Getting link to video with id '{video_id}' filed! Cause: {cause}" ) return None, cause
def init_themes(self): self._dark_mode_switch.set_active(self._ext_settings.dark_mode) t_support = self._ext_settings.is_themes_support self._themes_support_switch.set_active(t_support) if t_support: # GTK try: for t in os.listdir(self._ext_settings.themes_path): self._theme_combo_box.append(t, t) self._theme_combo_box.set_active_id(self._ext_settings.theme) self.set_theme_thumbnail_image(self._ext_settings.theme) except FileNotFoundError: pass except PermissionError as e: log("{}".format(e)) # Icons try: for t in os.listdir(self._ext_settings.icon_themes_path): self._icon_theme_combo_box.append(t, t) self._icon_theme_combo_box.set_active_id( self._ext_settings.icon_theme) except FileNotFoundError: pass except PermissionError as e: log("{}".format(e))
def init_data(self, path): self._main_model.clear() self._services_model.clear() try: if not self._bouquets: log("Import [init data]: getting bouquets...") self._bouquets = get_bouquets(path, self._profile) for bqs in self._bouquets: for bq in bqs.bouquets: self._main_model.append((bq.name, bq.type, True)) self._bq_services[(bq.name, bq.type)] = bq.services if self._profile is SettingsType.ENIGMA_2: services = get_services(path, self._profile, 5 if self._settings.v5_support else 4) elif self._profile is SettingsType.NEUTRINO_MP: services = get_services(path, self._profile, 0) else: self.show_info_message("Setting format not supported!", Gtk.MessageType.ERROR) return for srv in services: self._services[srv.fav_id] = srv except FileNotFoundError as e: log("Import error [init data]: {}".format(e)) self.show_info_message(str(e), Gtk.MessageType.ERROR)
def parse_v5(self): """ Parsing version 5. """ with open(self._path + "lamedb5", "r", encoding="utf-8", errors="replace") as file: lns = file.readlines() if lns and not lns[0].endswith("/5/\n"): raise SyntaxError( "lamedb ver.5 parsing error: unsupported format.") trs, srvs = {}, [""] for line in lns: if line.startswith("s:"): srv_data = line.strip("s:").split(",", 2) srv_data[1] = srv_data[1].strip("\"\n") data_len = len(srv_data) if data_len == 3: srv_data[2] = srv_data[2].strip() elif data_len == 2: srv_data.append("p:") srvs.extend(srv_data) elif line.startswith("t:"): data = line.split(",") len_data = len(data) if len_data > 1: tr, srv = data[0].strip("t:"), data[1].strip().replace( ":", " ", 1) trs[tr] = srv else: log(f"Error while parsing transponder data [ver. 5] for line: {line}" ) return self.parse_services(srvs, trs)
def parse(open_path, picons_path, tmp_path, provider, picon_ids, s_type=SettingsType.ENIGMA_2): if not os.path.isfile(open_path): log("PiconsParser error [parse]. No such file or directory: {}".format(open_path)) return with open(open_path, encoding="utf-8", errors="replace") as f: on_id, pos, ssid, single = provider.on_id, provider.pos, provider.ssid, provider.single neg_pos = pos.endswith("W") pos = int("".join(c for c in pos if c.isdigit())) # For negative (West) positions 3600 - numeric position value!!! if neg_pos: pos = 3600 - pos parser = PiconsParser(single=single) parser.reset() parser.feed(f.read()) picons = parser.picons if picons: os.makedirs(picons_path, exist_ok=True) for p in picons: try: if single: on_id, freq = on_id.strip().split("::") namespace = "{:X}{:X}".format(int(pos), int(freq)) else: namespace = "{:X}0000".format(int(pos)) name = PiconsParser.format(ssid if single else p.ssid, on_id, namespace, picon_ids, s_type) p_name = picons_path + (name if name else os.path.basename(p.ref)) shutil.copyfile(tmp_path + "www.lyngsat.com/" + p.ref.lstrip("."), p_name) except (TypeError, ValueError) as e: msg = "Picons format parse error: {}".format(p) + "\n" + str(e) log(msg)
def download_picons(self, picons): self._is_download = True os.makedirs(os.path.dirname(self._pic_path), exist_ok=True) GLib.idle_add(self._apply_button.set_sensitive, False) GLib.idle_add(self._progress_bar.set_visible, True) self._errors_count = 0 self._url_count = len(picons) self._max_count = self._url_count self._cancellable.reset() for p in filter(None, picons): if not self._is_download: return f = Gio.File.new_for_uri(p) try: GdkPixbuf.Pixbuf.new_from_stream_at_scale_async( f.read(cancellable=self._cancellable), 220, 132, False, self._cancellable, self.on_picon_load_done, picons.get(p, None)) except GLib.GError as e: self.update_progress() self._errors_count += 1 if e.code != Gio.IOErrorEnum.CANCELLED: log(str("Picon download error: {} [{}]").format(p, e))
def get_transponders(self, sat_url): """ Getting transponders(sorted by frequency). """ self._rows.clear() trs = [] url = sat_url if self._source is SatelliteSource.FLYSAT: url = "https://www.flysat.com/" + sat_url elif self._source is SatelliteSource.KINGOFSAT: url = "https://en.kingofsat.net/" + sat_url try: request = requests.get(url=url, headers=_HEADERS) except requests.exceptions.ConnectionError as e: log("Getting transponders error: {}".format(e)) else: if request.status_code == 200: self.feed(request.text) if self._source is SatelliteSource.FLYSAT: self.get_transponders_for_fly_sat(trs) elif self._source is SatelliteSource.LYNGSAT: self.get_transponders_for_lyng_sat(trs) elif self._source is SatelliteSource.KINGOFSAT: self.get_transponders_for_king_of_sat(trs) else: log("SatellitesParser [get transponders] error: {} {}".format( url, request.reason)) return sorted(trs, key=lambda x: int(x.frequency))
def retrlines(self, cmd, callback=None): """ Small modification of the original method. It is used to retrieve data in line mode and skip errors related to reading file names in encoding other than UTF-8 or Latin-1. Decode errors are ignored [UnicodeDecodeError, etc]. """ if callback is None: callback = log self.sendcmd("TYPE A") with self.transfercmd(cmd) as conn, conn.makefile("r", encoding=self.encoding, errors="ignore") as fp: while 1: line = fp.readline(self.maxline + 1) if len(line) > self.maxline: msg = "UtfFTP [retrlines] error: got more than {} bytes".format(self.maxline) log(msg) raise Error(msg) if self.debugging > 2: log('UtfFTP [retrlines] *retr* {}'.format(repr(line))) if not line: break if line[-2:] == CRLF: line = line[:-2] elif line[-1:] == "\n": line = line[:-1] callback(line) return self.voidresp()
def get_response(req_type, url, data=None): try: with urlopen(Request(url, data=data), timeout=10) as f: if req_type is HttpAPI.Request.STREAM or req_type is HttpAPI.Request.STREAM_CURRENT: return {"m3u": f.read().decode("utf-8")} elif req_type is HttpAPI.Request.GRUB: return {"img_data": f.read()} elif req_type is HttpAPI.Request.CURRENT: for el in ETree.fromstring(f.read().decode("utf-8")).iter("e2event"): return {el.tag: el.text for el in el.iter()} # return first[current] event from the list elif req_type is HttpAPI.Request.PLAYER_LIST: return [{el.tag: el.text for el in el.iter()} for el in ETree.fromstring(f.read().decode("utf-8")).iter("e2file")] elif req_type is HttpAPI.Request.EPG: return {"event_list": [{el.tag: el.text for el in el.iter()} for el in ETree.fromstring(f.read().decode("utf-8")).iter("e2event")]} elif req_type is HttpAPI.Request.TIMER_LIST: return {"timer_list": [{el.tag: el.text for el in el.iter()} for el in ETree.fromstring(f.read().decode("utf-8")).iter("e2timer")]} else: return {el.tag: el.text for el in ETree.fromstring(f.read().decode("utf-8")).iter()} except HTTPError as e: if req_type is HttpAPI.Request.TEST: raise e return {"error_code": e.code} except (URLError, RemoteDisconnected, ConnectionResetError) as e: if req_type is HttpAPI.Request.TEST: raise e except ETree.ParseError as e: log("Parsing response error: {}".format(e)) return {"error_code": -1}
def __init__(self, rewind_callback, position_callback, error_callback, playing_callback): try: from app.tools import vlc from app.tools.vlc import EventType except OSError as e: log("{}: Load library error: {}".format(__class__.__name__, e)) raise ImportError else: self._is_playing = False args = "--quiet {}".format("" if sys.platform == "darwin" else "--no-xlib") self._player = vlc.Instance(args).media_player_new() ev_mgr = self._player.event_manager() if rewind_callback: # TODO look other EventType options ev_mgr.event_attach( EventType.MediaPlayerBuffering, lambda et, p: rewind_callback(p.get_media().get_duration() ), self._player) if position_callback: ev_mgr.event_attach( EventType.MediaPlayerTimeChanged, lambda et, p: position_callback(p.get_time()), self._player) if error_callback: ev_mgr.event_attach(EventType.MediaPlayerEncounteredError, lambda et, p: error_callback(), self._player) if playing_callback: ev_mgr.event_attach(EventType.MediaPlayerPlaying, lambda et, p: playing_callback(), self._player)
def delete_dir(self, path, callback=None): files = [] self.dir(path, files.append) for f in files: f_data = f.split() name = " ".join(f_data[8:]) f_path = path + "/" + name if f_data[0][0] == "d": self.delete_dir(f_path, callback) else: self.delete_file(f_path, callback) msg = "Remove directory {}. Status: {}\n" try: resp = self.rmd(path) except Error as e: msg = msg.format(path, e) log(msg) return "500" else: msg = msg.format(path, resp) log(msg.rstrip()) if callback: callback(msg) return resp
def append_file_data(self, path: Path): self._file_model.clear() self._file_model.append( File(None, self.ROOT, None, None, str(path), "0")) try: dirs = [p for p in path.iterdir()] except OSError as e: log(e) else: for p in dirs: is_dir = p.is_dir() st = p.stat() size = str(st.st_size) date = datetime.fromtimestamp( st.st_mtime).strftime("%d-%m-%y %H:%M") icon = None if is_dir: r_size = self.FOLDER icon = self._folder_icon elif p.is_symlink(): r_size = self.LINK icon = self._link_icon else: r_size = self.get_size_from_bytes(size) self._file_model.append( File(icon, p.name, r_size, date, str(p.resolve()), size))
def on_file_drag_data_received(self, view, context, x, y, data, info, time): cur_path = self._file_model.get_value( self._file_model.get_iter_first(), self.Column.ATTR) + "/" try: GLib.idle_add(self._app._wait_dialog.show) uris = data.get_uris() if self._settings.is_darwin and len(uris) == 1: uris = uris[0].split(self.URI_SEP) for uri in uris: name, sep, attr = unquote(Path(uri).name).partition(":") if not attr: return True if attr[0] == "d": self._ftp.download_dir(name, cur_path, self.update_ftp_info) else: self._ftp.download_file(name, cur_path, self.update_ftp_info) except OSError as e: log(e) finally: GLib.idle_add(self._app._wait_dialog.hide) self.init_file_data(cur_path) Gtk.drag_finish(context, True, False, time) return True
def get_transponders_links(self, sat_url): """ Returns transponder links. """ try: if self._source is SatelliteSource.KINGOFSAT: sat_url = "https://en.kingofsat.net/" + sat_url self.init_data(sat_url) except ValueError as e: log(e) else: if self._source is SatelliteSource.LYNGSAT: url = "https://www.lyngsat.com/muxes/" return [ row[0] for row in filter( lambda x: x and len(x) > 8 and x[0].url and x[0].url. startswith(url), self._rows) ] elif self._source is SatelliteSource.KINGOFSAT: trs = [] for r in self._rows: if len(r) == 13 and SatellitesParser.POS_PAT.match( r[0].text): t_cell = r[4] if t_cell.url and t_cell.url.startswith("tp.php?tp="): t_cell.url = f"https://en.kingofsat.net/{t_cell.url}" t_cell.text = f"{r[2].text} {r[3].text} {r[6].text} {r[8].text}" trs.append(t_cell) return trs return []
def get_transponders(self, sat_url): """ Getting transponders(sorted by frequency). """ self._rows.clear() trs = [] if self._source is SatelliteSource.KINGOFSAT: sat_url = "https://en.kingofsat.net/" + sat_url try: request = requests.get(url=sat_url, headers=_HEADERS, timeout=_TIMEOUT) except requests.exceptions.RequestException as e: log(f"Getting transponders error: {e}") else: if request.status_code == 200: self.feed(request.text) if self._source is SatelliteSource.FLYSAT: self.get_transponders_for_fly_sat(trs) elif self._source is SatelliteSource.LYNGSAT: self.get_transponders_for_lyng_sat(trs) elif self._source is SatelliteSource.KINGOFSAT: self.get_transponders_for_king_of_sat(trs) else: log(f"SatellitesParser [get transponders] error: {sat_url} {request.reason}" ) return sorted(trs, key=lambda x: int(x.frequency))
def get_satellites_list(self, source): """ Getting complete list of satellites. """ self.reset() self._rows.clear() self._source = source for src in SatelliteSource.get_sources(self._source): try: resp = requests.get(url=src, headers=_HEADERS, timeout=_TIMEOUT) except requests.exceptions.RequestException as e: log(f"Getting satellite list error: {repr(e)}") else: reason = resp.reason if reason == "OK": self.feed(resp.text) else: log(f"Getting satellite list error: {reason} -> {resp.url}" ) if self._rows: if self._source is SatelliteSource.FLYSAT: return self.get_satellites_for_fly_sat() elif self._source is SatelliteSource.LYNGSAT: return self.get_satellites_for_lyng_sat() elif source is SatelliteSource.KINGOFSAT: return self.get_satellites_for_king_of_sat() return []
def import_data(self): """ Importing data into models. """ if not self._bouquets: return log("Importing data...") services = set() to_delete = set() for row in self._main_model: bq = (row[0], row[1]) if row[-1]: for bq_srv in self._bq_services.get(bq, []): srv = self._services.get(bq_srv.data, None) if srv: services.add(srv) else: to_delete.add(bq) bqs_to_delete = [] for bqs in self._bouquets: for bq in bqs.bouquets: if (bq.name, bq.type) in to_delete: bqs_to_delete.append(bq) for bqs in self._bouquets: bq = bqs.bouquets for b in bqs_to_delete: with suppress(ValueError): bq.remove(b) self._append( self._bouquets, list(filter(lambda s: s.fav_id not in self._service_ids, services))) self._dialog_window.destroy()
def on_edit(self): """ Edit current service. """ fav_id, data_id = self.get_srv_data() # Transponder transponder = self._old_service.transponder if self._tr_edit_switch.get_active(): try: if self._tr_type is TrType.Satellite: transponder = self.get_satellite_transponder_data() elif self._tr_type is TrType.Terrestrial: transponder = self.get_terrestrial_transponder_data() elif self._tr_type is TrType.Cable: transponder = self.get_cable_transponder_data() elif self._tr_type is TrType.ATSC: transponder = self.get_atsc_transponder_data() except Exception as e: log("Edit service error: {}".format(e)) show_dialog(DialogType.ERROR, transient=self._dialog, text="Error getting transponder parameters!") else: if self._transponder_services_iters: self.update_transponder_services(transponder, self.get_sat_position()) # Service service = self.get_service(fav_id, data_id, transponder) old_fav_id = self._old_service.fav_id if old_fav_id != fav_id: if fav_id in self._services: msg = "{}\n\n\t{}".format( "A similar service is already in this list!", "Are you sure?") if show_dialog(DialogType.QUESTION, transient=self._dialog, text=msg) != Gtk.ResponseType.OK: return False self.update_bouquets(fav_id, old_fav_id) self._services[fav_id] = service if self._old_service.picon_id != service.picon_id: self.update_picon_name(self._old_service.picon_id, service.picon_id) flags = service.flags_cas extra_data = {Column.SRV_TOOLTIP: None, Column.SRV_BACKGROUND: None} if self._s_type is SettingsType.ENIGMA_2 and flags: f_flags = list( filter(lambda x: x.startswith("f:"), flags.split(","))) if f_flags and Flag.is_new(int(f_flags[0][2:])): extra_data[Column.SRV_BACKGROUND] = self._new_color self._current_model.set(self._current_itr, extra_data) self._current_model.set(self._current_itr, {i: v for i, v in enumerate(service)}) self.update_fav_view(self._old_service, service) self._old_service = service return True
def get_bouquet(path, bq_name, bq_type, prefix="userbouquet"): """ Parsing services ids from bouquet file. """ with open(path + "{}.{}.{}".format(prefix, bq_name, bq_type), encoding="utf-8", errors="replace") as file: chs_list = file.read() services = [] srvs = list(filter(None, chs_list.split("\n#SERVICE"))) # filtering [''] # May come across empty[wrong] files! if not srvs: log("Bouquet file 'userbouquet.{}.{}' is empty or wrong!". format(bq_name, bq_type)) return "{} [empty]".format(bq_name), services bq_name = srvs.pop(0) for num, srv in enumerate(srvs, start=1): srv_data = srv.strip().split(":") s_type = srv_data[1] if s_type == "64": m_data, sep, desc = srv.partition("#DESCRIPTION") services.append( BouquetService(desc.strip() if desc else "", BqServiceType.MARKER, srv, num)) elif s_type == "832": m_data, sep, desc = srv.partition("#DESCRIPTION") services.append( BouquetService(desc.strip() if desc else "", BqServiceType.SPACE, srv, num)) elif s_type == "134": alt = re.match(BouquetsReader._ALT_PAT, srv) if alt: alt_name, alt_type = alt.group(1), alt.group(2) alt_bq_name, alt_srvs = BouquetsReader.get_bouquet( path, alt_name, alt_type, "alternatives") services.append( BouquetService(alt_bq_name, BqServiceType.ALT, alt_name, tuple(alt_srvs))) elif srv_data[0].strip( ) in BouquetsReader._STREAM_TYPES or srv_data[10].startswith( ("http", "rtsp")): stream_data, sep, desc = srv.partition("#DESCRIPTION") desc = desc.lstrip( ":").strip() if desc else srv_data[-1].strip() services.append( BouquetService(desc, BqServiceType.IPTV, srv, num)) else: fav_id = "{}:{}:{}:{}".format(srv_data[3], srv_data[4], srv_data[5], srv_data[6]) name = None if len(srv_data) == 12: name, sep, desc = str( srv_data[-1]).partition("\n#DESCRIPTION") services.append( BouquetService(name, BqServiceType.DEFAULT, fav_id.upper(), num)) return bq_name.lstrip("#NAME").strip(), services