added extra dialog for searching unavailable iptv streams

This commit is contained in:
DYefremov
2018-07-03 19:30:45 +03:00
parent 249a49aff5
commit 78c07f3934
4 changed files with 319 additions and 40 deletions

View File

@@ -1,7 +1,37 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.18.3 -->
<!-- Generated with glade 3.22.1
The MIT License (MIT)
Copyright (c) 2018 Dmitriy Yefremov
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
Author: Dmitriy Yefremov
-->
<interface>
<requires lib="gtk+" version="3.12"/>
<requires lib="gtk+" version="3.14"/>
<!-- interface-license-type mit -->
<!-- interface-name DemonEditor -->
<!-- interface-copyright 2018 Dmitriy Yefremov -->
<!-- interface-authors Dmitriy Yefremov -->
<object class="GtkAboutDialog" id="about_dialog">
<property name="can_focus">False</property>
<property name="modal">True</property>
@@ -21,6 +51,9 @@
<property name="logo_icon_name">accessories-text-editor</property>
<property name="wrap_license">True</property>
<property name="license_type">mit-x11</property>
<child>
<placeholder/>
</child>
<child internal-child="vbox">
<object class="GtkBox" id="aboutdialog_vbox">
<property name="can_focus">False</property>
@@ -50,6 +83,9 @@
<property name="destroy_with_parent">True</property>
<property name="icon_name">mail-send-receive</property>
<property name="type_hint">dialog</property>
<child>
<placeholder/>
</child>
<child internal-child="vbox">
<object class="GtkBox" id="download_dialog_vbox">
<property name="width_request">320</property>
@@ -92,11 +128,14 @@
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Receive</property>
<property name="column_spacing">1</property>
<property name="margin_left">2</property>
<property name="margin_right">2</property>
<property name="column_spacing">2</property>
<child>
<object class="GtkLabel" id="label9">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_left">5</property>
<property name="label" translatable="yes">Receiver IP:</property>
<property name="xalign">0</property>
</object>
@@ -124,6 +163,7 @@
<object class="GtkLabel" id="label11">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_left">5</property>
<property name="label" translatable="yes">Current data path:</property>
<property name="xalign">0</property>
</object>
@@ -156,6 +196,9 @@
<object class="GtkBox" id="download_dialogbox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_left">5</property>
<property name="margin_top">2</property>
<property name="margin_bottom">2</property>
<property name="spacing">5</property>
<child>
<object class="GtkLabel" id="label10">
@@ -176,7 +219,6 @@
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="xalign">0</property>
<property name="active">True</property>
<property name="draw_indicator">True</property>
<property name="group">satellites_radio_button</property>
@@ -193,7 +235,6 @@
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="xalign">0</property>
<property name="draw_indicator">True</property>
<property name="group">satellites_radio_button</property>
</object>
@@ -209,7 +250,6 @@
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="xalign">0</property>
<property name="draw_indicator">True</property>
<property name="group">all_radio_button</property>
</object>
@@ -224,8 +264,6 @@
<property name="label" translatable="yes">WebTV</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="xalign">0</property>
<property name="yalign">0.52999997138977051</property>
<property name="active">True</property>
<property name="draw_indicator">True</property>
<property name="group">all_radio_button</property>
@@ -298,7 +336,7 @@
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="xalign">0</property>
<property name="margin_left">2</property>
<property name="active">True</property>
<property name="draw_indicator">True</property>
</object>
@@ -409,6 +447,9 @@
<property name="type_hint">dialog</property>
<property name="message_type">error</property>
<property name="buttons">ok</property>
<child>
<placeholder/>
</child>
<child internal-child="vbox">
<object class="GtkBox" id="error_dialog_vbox">
<property name="can_focus">False</property>
@@ -437,6 +478,9 @@
<property name="destroy_with_parent">True</property>
<property name="icon_name">gtk-edit</property>
<property name="type_hint">dialog</property>
<child>
<placeholder/>
</child>
<child internal-child="vbox">
<object class="GtkBox" id="input_dialog_vbox">
<property name="width_request">320</property>
@@ -529,6 +573,9 @@
<property name="type_hint">dialog</property>
<property name="action">select-folder</property>
<property name="do_overwrite_confirmation">True</property>
<child>
<placeholder/>
</child>
<child internal-child="vbox">
<object class="GtkBox" id="filechooser_dialog_vbox">
<property name="can_focus">False</property>
@@ -559,7 +606,6 @@
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
<property name="yalign">0.55000001192092896</property>
</object>
<packing>
<property name="expand">True</property>
@@ -593,6 +639,9 @@
<property name="message_type">question</property>
<property name="buttons">ok-cancel</property>
<property name="text" translatable="yes">Are you sure?</property>
<child>
<placeholder/>
</child>
<child internal-child="vbox">
<object class="GtkBox" id="question_dialog_vbox">
<property name="can_focus">False</property>
@@ -613,6 +662,151 @@
</object>
</child>
</object>
<object class="GtkDialog" id="search_unavailable_streams_dialog">
<property name="width_request">320</property>
<property name="can_focus">False</property>
<property name="title" translatable="yes"> </property>
<property name="modal">True</property>
<property name="window_position">center</property>
<property name="destroy_with_parent">True</property>
<property name="type_hint">dialog</property>
<property name="skip_taskbar_hint">True</property>
<property name="skip_pager_hint">True</property>
<property name="gravity">center</property>
<signal name="delete-event" handler="on_search_unavailable_close" swapped="no"/>
<child type="titlebar">
<placeholder/>
</child>
<child internal-child="vbox">
<object class="GtkBox">
<property name="can_focus">False</property>
<property name="margin_left">5</property>
<property name="margin_right">5</property>
<property name="margin_top">5</property>
<property name="orientation">vertical</property>
<property name="spacing">2</property>
<child internal-child="action_area">
<object class="GtkButtonBox">
<property name="can_focus">False</property>
<property name="layout_style">end</property>
<child>
<object class="GtkButton" id="button6">
<property name="label">gtk-cancel</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
<signal name="clicked" handler="on_search_unavailable_close" swapped="no"/>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">4</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Please wait, streams testing in progress.</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLevelBar" id="unavailable_streams_level_bar">
<property name="height_request">10</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="inverted">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">center</property>
<property name="margin_top">10</property>
<property name="spacing">2</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Found</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="streams_rows_counter_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">0</property>
<attributes>
<attribute name="weight" value="bold"/>
</attributes>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">unavailable streams</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkSeparator">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="padding">2</property>
<property name="position">4</property>
</packing>
</child>
</object>
</child>
<action-widgets>
<action-widget response="-6">button6</action-widget>
</action-widgets>
</object>
<object class="GtkListStore" id="stream_type_liststore">
<columns>
<!-- column-name stream_type -->
@@ -637,6 +831,9 @@
<property name="type_hint">dialog</property>
<property name="skip_taskbar_hint">True</property>
<property name="skip_pager_hint">True</property>
<child>
<placeholder/>
</child>
<child internal-child="vbox">
<object class="GtkBox" id="iptv_dialog_vbox">
<property name="can_focus">False</property>
@@ -1102,6 +1299,9 @@
<property name="modal">True</property>
<property name="icon_name">preferences-desktop</property>
<property name="type_hint">dialog</property>
<child>
<placeholder/>
</child>
<child internal-child="vbox">
<object class="GtkBox" id="dialog-vbox3">
<property name="can_focus">False</property>
@@ -1584,7 +1784,6 @@
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="xalign">0</property>
<property name="active">True</property>
<property name="draw_indicator">True</property>
<property name="group">neutrino_radio_button</property>
@@ -1603,7 +1802,6 @@
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="xalign">0</property>
<property name="draw_indicator">True</property>
</object>
<packing>
@@ -1631,7 +1829,6 @@
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="xalign">0</property>
<property name="active">True</property>
<property name="draw_indicator">True</property>
<property name="group">enigma_radio_button</property>
@@ -1805,6 +2002,9 @@
<property name="skip_taskbar_hint">True</property>
<property name="skip_pager_hint">True</property>
<property name="decorated">False</property>
<child>
<placeholder/>
</child>
<child internal-child="vbox">
<object class="GtkBox" id="dialog-vbox4">
<property name="width_request">118</property>

View File

@@ -1,12 +1,15 @@
import re
from urllib.parse import urlparse
from urllib.request import Request, urlopen
from app.commons import run_idle, run_task
from app.eparser.ecommons import BqServiceType, Service
from app.eparser.iptv import NEUTRINO_FAV_ID_FORMAT, StreamType, ENIGMA2_FAV_ID_FORMAT
from app.properties import Profile
from .uicommons import Gtk, Gdk, TEXT_DOMAIN, UI_RESOURCES_PATH, IPTV_ICON
from .dialogs import Action, show_dialog, DialogType
from .main_helper import get_base_model
from .main_helper import get_base_model, get_iptv_url
class IptvDialog:
@@ -182,5 +185,79 @@ class IptvDialog:
return True
class SearchUnavailableDialog:
def __init__(self, transient, model, fav_bouquet, iptv_rows, profile):
handlers = {"on_search_unavailable_close": self.on_close}
builder = Gtk.Builder()
builder.set_translation_domain(TEXT_DOMAIN)
builder.add_objects_from_file(UI_RESOURCES_PATH + "dialogs.glade", ("search_unavailable_streams_dialog",))
builder.connect_signals(handlers)
self._dialog = builder.get_object("search_unavailable_streams_dialog")
self._dialog.set_transient_for(transient)
self._model = model
self._counter_label = builder.get_object("streams_rows_counter_label")
self._level_bar = builder.get_object("unavailable_streams_level_bar")
self._bouquet = fav_bouquet
self._profile = profile
self._iptv_rows = iptv_rows
self._counter = -1
self._max_rows = len(self._iptv_rows)
self._level_bar.set_max_value(self._max_rows)
self._download_task = True
self._to_delete = []
self.update_process()
self.do_search()
@run_task
def do_search(self):
import concurrent.futures
with concurrent.futures.ThreadPoolExecutor(max_workers=4) as executor:
futures = {executor.submit(self.get_unavailable, row): row for row in self._iptv_rows}
for future in concurrent.futures.as_completed(futures):
if not self._download_task:
executor.shutdown()
return
future.result()
self._download_task = False
self._dialog.destroy()
def get_unavailable(self, row):
if not self._download_task:
return
req = Request(get_iptv_url(row, self._profile))
try:
self.update_bar()
urlopen(req, timeout=2)
except Exception:
self._to_delete.append(self._model.get_iter(row.path))
self.update_process()
@run_idle
def update_bar(self):
self._max_rows -= 1
self._level_bar.set_value(self._max_rows)
@run_idle
def update_process(self):
self._counter += 1
self._counter_label.set_text(str(self._counter))
def show(self):
response = self._dialog.run()
self._dialog.destroy()
return self._to_delete if response not in (Gtk.ResponseType.CANCEL, Gtk.ResponseType.DELETE_EVENT) else False
def on_close(self, item, event=None):
if self._download_task and show_dialog(DialogType.QUESTION, self._dialog) == Gtk.ResponseType.CANCEL:
return
self._download_task = False
self._dialog.destroy()
if __name__ == "__main__":
pass

View File

@@ -12,14 +12,14 @@ from app.eparser.enigma.bouquets import BqServiceType
from app.eparser.neutrino.bouquets import BqType
from app.properties import get_config, write_config, Profile
from app.tools.media import Player
from .iptv import IptvDialog
from .iptv import IptvDialog, SearchUnavailableDialog
from .search import SearchProvider
from .uicommons import Gtk, Gdk, UI_RESOURCES_PATH, LOCKED_ICON, HIDE_ICON, IPTV_ICON, MOVE_KEYS
from .dialogs import show_dialog, DialogType, get_chooser_dialog, WaitDialog, get_message
from .download_dialog import show_download_dialog
from .main_helper import edit_marker, insert_marker, move_items, rename, ViewTarget, set_flags, locate_in_services, \
scroll_to, get_base_model, update_picons, copy_picon_reference, assign_picon, remove_picon, \
is_only_one_item_selected, gen_bouquets, BqGenType
is_only_one_item_selected, gen_bouquets, BqGenType, get_iptv_url
from .picons_downloader import PiconsDialog
from .satellites_dialog import show_satellites_dialog
from .settings_dialog import show_settings_dialog
@@ -324,6 +324,7 @@ class MainAppWindow:
return rows
@run_idle
def remove_favs(self, fav_bouquet, itrs, model):
""" Deleting bouquet services """
if fav_bouquet:
@@ -595,7 +596,7 @@ class MainAppWindow:
except Exception as e:
print(e)
log("Append services error: " + str(e))
show_dialog(DialogType.ERROR, self._main_window, "Reading data error!")
show_dialog(DialogType.ERROR, self._main_window, "Reading data error!\n" + e)
else:
if services:
for srv in services:
@@ -954,7 +955,7 @@ class MainAppWindow:
if path:
row = self._fav_model[path][:]
if row[5] == BqServiceType.IPTV.value:
url = self.get_iptv_url(row)
url = get_iptv_url(row, Profile(self._profile))
if not url:
return
@@ -973,32 +974,25 @@ class MainAppWindow:
self._is_played = True
self._player.play()
def get_iptv_url(self, row):
profile = Profile(self._profile)
data = row[7].split(":" if profile is Profile.ENIGMA_2 else "::")
url = data[-3 if profile is Profile.ENIGMA_2 else 0]
return url.replace("%3a", ":") if profile is Profile.ENIGMA_2 else url
@run_idle
def on_remove_all_unavailable(self, item):
from urllib.request import Request, urlopen
from urllib.error import URLError
to_delete = []
for row in self._fav_model:
if row[5] == BqServiceType.IPTV.value:
url = self.get_iptv_url(row)
req = Request(url)
try:
urlopen(req)
except URLError as e:
to_delete.append(self._fav_model.get_iter(row.path))
iptv_rows = list(filter(lambda r: r[5] == BqServiceType.IPTV.value, self._fav_model))
if not iptv_rows:
show_dialog(DialogType.ERROR, self._main_window, "This list does not contains iptv streams!")
return
bq_selected = self.get_selected_bouquet()
if bq_selected:
fav_bouquet = self._bouquets.get(bq_selected, None)
self.remove_favs(fav_bouquet, to_delete, self._fav_model)
if not bq_selected:
return
if show_dialog(DialogType.QUESTION, self._main_window) == Gtk.ResponseType.CANCEL:
return
fav_bqt = self._bouquets.get(bq_selected, None)
prf = Profile(self._profile)
response = SearchUnavailableDialog(self._main_window, self._fav_model, fav_bqt, iptv_rows, prf).show()
if response:
self.remove_favs(fav_bqt, response, self._fav_model)
def on_player_stop(self, item):
if self._player:

View File

@@ -533,5 +533,13 @@ def append_text_to_tview(char, view):
view.scroll_to_mark(insert, 0.0, True, 0.0, 1.0)
def get_iptv_url(row, profile):
""" Returns url from iptv type row """
data = row[7].split(":" if profile is Profile.ENIGMA_2 else "::")
url = data[-3 if profile is Profile.ENIGMA_2 else 0]
return url.replace("%3a", ":") if profile is Profile.ENIGMA_2 else url
if __name__ == "__main__":
pass