diff --git a/app/eparser/iptv.py b/app/eparser/iptv.py
index 5be1d431..42573d9a 100644
--- a/app/eparser/iptv.py
+++ b/app/eparser/iptv.py
@@ -1,4 +1,5 @@
""" Module for IPTV and streams support """
+import re
import urllib.request
from enum import Enum
@@ -53,5 +54,24 @@ def parse_m3u(path, profile):
return services
+def export_to_m3u(path, bouquet):
+ pattern = re.compile(".*:(http.*):.*")
+ lines = ["#EXTM3U\n"]
+
+ for s in bouquet.services:
+ bq_type = s.type
+ if bq_type is BqServiceType.IPTV:
+ res = re.match(pattern, s.data)
+ if not res:
+ continue
+ data = res.group(1)
+ lines.append("#EXTINF:-1,{}\n{}\n".format(s.name, urllib.request.unquote(data.strip())))
+ elif bq_type is BqServiceType.MARKER:
+ pass
+
+ with open(path + "{}.m3u".format(bouquet.name), "w", encoding="utf-8") as file:
+ file.writelines(lines)
+
+
if __name__ == "__main__":
pass
diff --git a/app/ui/main_app_window.py b/app/ui/main_app_window.py
index 4d021b4a..e827ee90 100644
--- a/app/ui/main_app_window.py
+++ b/app/ui/main_app_window.py
@@ -11,8 +11,9 @@ from app.connections import http_request, HttpRequestType, download_data, Downlo
TestException
from app.eparser import get_blacklist, write_blacklist, parse_m3u
from app.eparser import get_services, get_bouquets, write_bouquets, write_services, Bouquets, Bouquet, Service
-from app.eparser.ecommons import CAS, Flag
+from app.eparser.ecommons import CAS, Flag, BouquetService
from app.eparser.enigma.bouquets import BqServiceType
+from app.eparser.iptv import export_to_m3u
from app.eparser.neutrino.bouquets import BqType
from app.properties import get_config, write_config, Profile
from app.tools.media import Player
@@ -113,6 +114,7 @@ class Application(Gtk.Application):
"on_locked": self.on_locked,
"on_model_changed": self.on_model_changed,
"on_import_m3u": self.on_import_m3u,
+ "on_export_to_m3u": self.on_export_to_m3u,
"on_import_bouquet": self.on_import_bouquet,
"on_import_bouquets": self.on_import_bouquets,
"on_backup_tool_show": self.on_backup_tool_show,
@@ -1362,6 +1364,25 @@ class Application(Gtk.Application):
bq_services.append(ch.fav_id)
next(self.update_bouquet_services(self._fav_model, None, self._bq_selected), False)
+ @run_idle
+ def on_export_to_m3u(self, item):
+ i_types = (BqServiceType.IPTV.value, BqServiceType.MARKER.value)
+ bq_services = [BouquetService(r[Column.FAV_SERVICE],
+ BqServiceType(r[Column.FAV_TYPE]),
+ r[Column.FAV_ID],
+ r[Column.FAV_NUM]) for r in self._fav_model if r[Column.FAV_TYPE] in i_types]
+
+ if not bq_services:
+ self.show_error_dialog("No data to save!")
+ return
+
+ if not any(s.type is BqServiceType.IPTV for s in bq_services):
+ self.show_error_dialog("This list does not contains IPTV streams!")
+ return
+
+ path = self._options.get(self._profile).get("data_dir_path", "")
+ export_to_m3u(path, Bouquet(self._current_bq_name, None, bq_services, None, None))
+
def on_import_bouquet(self, item):
profile = Profile(self._profile)
model, paths = self._bouquets_view.get_selection().get_selected_rows()
diff --git a/app/ui/main_window.glade b/app/ui/main_window.glade
index 69dc3598..fae5df0d 100644
--- a/app/ui/main_window.glade
+++ b/app/ui/main_window.glade
@@ -82,6 +82,11 @@ Author: Dmitriy Yefremov
False
gtk-revert-to-saved
+
-
-
-
-
-
+
+
+
-
-
-
-
-