write bouquets impl

This commit is contained in:
DYefremov
2017-10-26 01:23:05 +03:00
parent 7dae744ac4
commit 9168adfb63
10 changed files with 141 additions and 45 deletions

17
main/commons.py Normal file
View File

@@ -0,0 +1,17 @@
from functools import wraps
from threading import Thread
def run_task(func):
""" Runs function in separate thread """
@wraps(func)
def wrapper(*args, **kwargs):
task = Thread(target=func(*args, **kwargs))
task.start()
return wrapper
if __name__ == "__main__":
pass

View File

@@ -1,11 +1,6 @@
""" This module only for common constants """
from collections import namedtuple
from enum import Enum
Channel = namedtuple("Channel", ["service", "package", "service_type",
"ssid", "freq", "rate", "pol", "fec",
"system", "pos", "data_id", "fav_id"])
class Type(Enum):
""" Types of DVB transponders """

View File

@@ -1,5 +1,5 @@
from .lamedb import get_channels, write_channels
from .bouquets import get_bouquets, get_bouquet, write_bouquet
from .bouquets import get_bouquets, write_bouquets, Bouquet, Bouquets
from .satxml import get_satellites, write_satellites, Satellite, Transponder

View File

@@ -1,18 +1,37 @@
""" Module for parsing bouquets """
from collections import namedtuple
__BOUQUETS_PATH = "../data/"
_BOUQUETS_PATH = "../data/"
_TV_ROOT_FILE_NAME = "bouquets.tv"
_RADIO_ROOT_FILE_NAME = "bouquets.radio"
Bouquet = namedtuple("Bouquet", ["name", "type", "services"])
Bouquets = namedtuple("Bouquets", ["name", "bouquets"])
Bouquets = namedtuple("Bouquets", ["name", "type", "bouquets"])
def get_bouquets(path):
return parse_bouquets(path, "bouquets.tv", "tv"), parse_bouquets(path, "bouquets.radio", "radio")
def write_bouquets(path, bouquets, bouquets_services):
srv_line = '#SERVICE 1:7:1:0:0:0:0:0:0:0:FROM BOUQUET "userbouquet.{}.{}" ORDER BY bouquet\n'
line = []
for bqs in bouquets:
line.clear()
line.append("#NAME {}\n".format(bqs.name))
for bq in bqs.bouquets:
line.append(srv_line.format(bq.name, bq.type))
write_bouquet(path, bq.name, bq.services)
with open(path + "bouquets.{}".format(bqs.type), "w") as file:
file.writelines(line)
def write_bouquet(path, name, channels):
bouquet = ["#NAME {}\n".format(name)]
for ch in channels:
data_type = int(ch.data_id.split(":")[-2])
if data_type == 22:
@@ -20,6 +39,7 @@ def write_bouquet(path, name, channels):
elif data_type == 25:
data_type = 19
bouquet.append("#SERVICE {}:0:{}:{}:0:0:0:\n".format(1, data_type, ch.fav_id))
with open(path + "_userbouquet.{}.tv".format(name), "w") as file:
file.writelines(bouquet)
@@ -32,6 +52,7 @@ def get_bouquet(path, name, bq_type):
for ch in chs_list.split("#SERVICE")[1:]:
ch_data = ch.strip().split(":")
ids.append("{}:{}:{}:{}".format(ch_data[3], ch_data[4], ch_data[5], ch_data[6]))
return ids
@@ -40,13 +61,15 @@ def parse_bouquets(path, bq_name, bq_type):
lines = file.readlines()
bouquets = None
nm_sep = "#NAME"
for line in lines:
if nm_sep in line:
_, _, name = line.partition(nm_sep)
bouquets = Bouquets(name.strip(), [])
bouquets = Bouquets(name.strip(), bq_type, [])
if bouquets and "#SERVICE" in line:
name = line.split(".")[1]
bouquets[1].append(Bouquet(name=name, type=bq_type, services=get_bouquet(path, name, bq_type)))
bouquets[2].append(Bouquet(name=name, type=bq_type, services=get_bouquet(path, name, bq_type)))
return bouquets

View File

@@ -3,12 +3,18 @@
Currently implemented only for satellite channels!!!
Description of format taken from here: http://www.satsupreme.com/showthread.php/194074-Lamedb-format-explained
"""
from main.eparser.__constants import POLARIZATION, SYSTEM, FEC, Channel, SERVICE_TYPE
from collections import namedtuple
from main.eparser.__constants import POLARIZATION, SYSTEM, FEC, SERVICE_TYPE
_HEADER = "eDVB services /4/"
_FILE_PATH = "../data/lamedb"
_SEP = ":" # separator
Channel = namedtuple("Channel", ["service", "package", "service_type",
"ssid", "freq", "rate", "pol", "fec",
"system", "pos", "data_id", "fav_id"])
def get_channels(path):
return parse(path)
@@ -25,6 +31,7 @@ def parse(path):
transponders, sep, services = data.partition("transponders") # 1 step
transponders, sep, services = services.partition("services") # 2 step
services, sep, _ = services.partition("end") # 3 step
return parse_channels(services.split("\n"), transponders.split("/"))
@@ -35,18 +42,19 @@ def parse_transponders(arg):
tr = ar.replace("\n", "").split("\t")
if len(tr) == 2:
transponders[tr[0]] = tr[1]
return transponders
def parse_channels(*args):
""" Parsing channels """
channels = []
transponders = parse_transponders(args[1])
srv = split(args[0], 3)
if srv[0][0] == "": # remove first empty element
srv.remove(srv[0])
channels = []
for ch in srv:
data = str(ch[0]).split(_SEP)
sp = "0"
@@ -73,6 +81,7 @@ def split(itr, size):
if i % size == 0:
srv.append(tuple(tmp))
tmp.clear()
return srv

View File

@@ -16,8 +16,7 @@ from collections import namedtuple
from xml.dom.minidom import parse, Document
from main.eparser.__constants import POLARIZATION, FEC, SYSTEM, MODULATION, PLS_MODE
# temporary
__XML_PATH = "../data/"
__FILE_NAME = "satellites.xml"
Satellite = namedtuple("Satellite", ["name", "flags", "position", "transponders"])
@@ -59,12 +58,14 @@ def write_satellites(satellites, data_path):
doc.appendChild(comment)
root = doc.createElement("satellites")
doc.appendChild(root)
for sat in satellites:
# Create Element
sat_child = doc.createElement("sat")
sat_child.setAttribute("name", sat.name)
sat_child.setAttribute("flags", sat.flags)
sat_child.setAttribute("position", sat.position)
for tr in sat.transponders:
transponder_child = doc.createElement("transponder")
transponder_child.setAttribute("frequency", tr.frequency)
@@ -81,7 +82,7 @@ def write_satellites(satellites, data_path):
transponder_child.setAttribute("is_id", tr.is_id)
sat_child.appendChild(transponder_child)
root.appendChild(sat_child)
doc.writexml(open(data_path + "new_satellites.xml", "w"),
doc.writexml(open(data_path + __FILE_NAME, "w"),
# indent="",
addindent=" ",
newl='\n',
@@ -120,9 +121,11 @@ def parse_satellites(path):
""" Parsing satellites from xml"""
dom = parse(path)
satellites = []
for elem in dom.getElementsByTagName("sat"):
if elem.hasAttributes():
satellites.append(parse_sat(elem))
return satellites
@@ -133,9 +136,4 @@ def get_key_by_value(dictionary, value):
if __name__ == "__main__":
sats = get_satellites(__XML_PATH)
for sat in sats:
trnsp = sat.transponders
for tr in trnsp:
if tr.pls_mode or tr.pls_code or tr.is_id:
print(tr, sat.name)
pass

View File

@@ -13,6 +13,7 @@ def download_data(*, properties):
ftp.cwd(properties["services_path"])
files = []
ftp.dir(files.append)
for file in files:
name = str(file).strip()
if name.endswith(__DATA_FILES_LIST):
@@ -23,19 +24,23 @@ def download_data(*, properties):
ftp.cwd(properties["satellites_xml_path"])
files.clear()
ftp.dir(files.append)
for file in files:
name = str(file).strip()
xml_file = "satellites.xml"
if name.endswith(xml_file):
with open(save_path + xml_file, 'wb') as f:
ftp.retrbinary('RETR ' + xml_file, f.write)
for name in os.listdir(save_path):
print(name)
return ftp.voidcmd("NOOP")
def upload_data(*, properties):
load_path = properties["data_dir_path"]
for file_name in os.listdir(load_path):
print(file_name)
# Open the file for transfer in binary mode

View File

@@ -11,6 +11,7 @@ DATA_PATH = "data/"
def get_config():
os.makedirs(os.path.dirname(CONFIG_PATH), exist_ok=True) # create dir if not exist
os.makedirs(os.path.dirname(DATA_PATH), exist_ok=True)
if not os.path.isfile(CONFIG_FILE) or os.stat(CONFIG_FILE).st_size == 0:
with open(CONFIG_FILE, "w") as default_config_file:
json.dump(get_default_settings(), default_config_file)

View File

@@ -1,7 +1,7 @@
from contextlib import suppress
from threading import Thread
from main.eparser import get_channels, get_bouquets, write_bouquet, write_channels
from main.commons import run_task
from main.eparser import get_channels, get_bouquets, write_bouquets, write_channels, Bouquets, Bouquet
from main.ftp import download_data, upload_data
from main.properties import get_config, write_config
from . import Gtk, Gdk
@@ -98,17 +98,24 @@ def on_paste(view):
selection = view.get_selection()
dest_index = 0
bq_selected = is_bouquet_selected()
if bq_selected:
fav_bouquet = __bouquets[bq_selected]
if not bq_selected:
return
fav_bouquet = __bouquets[bq_selected]
model, paths = selection.get_selected_rows()
if paths:
dest_index = int(paths[0][0])
for row in __rows_buffer:
dest_index += 1
model.insert(dest_index, row)
fav_bouquet.insert(dest_index, row[-1])
if model.get_name() == FAV_LIST_NAME:
update_fav_num_column(model)
__rows_buffer.clear()
@@ -126,11 +133,14 @@ def on_delete(item):
rows = [model.get(in_itr, *[x for x in range(view.get_n_columns())]) for in_itr in itrs]
bq_selected = is_bouquet_selected()
fav_bouquet = None
if bq_selected:
fav_bouquet = __bouquets[bq_selected]
for itr in itrs:
if fav_bouquet and model_name == FAV_LIST_NAME:
del fav_bouquet[int(model.get_path(itr)[0])]
if model_name == BOUQUETS_LIST_NAME:
if model.iter_has_child(itr):
show_message_dialog("This item is not allowed to be removed!")
@@ -138,9 +148,10 @@ def on_delete(item):
else:
__bouquets.pop(bq_selected)
model.remove(itr)
if model_name == FAV_LIST_NAME:
update_fav_num_column(model)
if model_name == SERVICE_LIST_NAME:
elif model_name == SERVICE_LIST_NAME:
for row in rows:
# There are channels with the same parameters except for the name.
# None because it can have duplicates! Need fix
@@ -153,12 +164,14 @@ def on_delete(item):
__fav_model.clear()
if bq_selected:
update_bouquet_channels(__fav_model, None, bq_selected)
return rows
def on_to_fav_move(view):
""" Move items from main to fav list """
selection = get_selection(view)
if selection:
receive_selection(view=__fav_view, drop_info=None, data=selection)
@@ -167,6 +180,7 @@ def get_selection(view):
""" Creates a string from the iterators of the selected rows """
selection = view.get_selection()
model, paths = selection.get_selected_rows()
if len(paths) > 0:
itrs = [model.get_iter(path) for path in paths]
return "{}:{}".format(",".join([model.get_string_from_iter(itr) for itr in itrs]), model.get_name())
@@ -175,20 +189,26 @@ def get_selection(view):
def receive_selection(*, view, drop_info, data):
""" Update fav view after data received """
bq_selected = is_bouquet_selected()
if not bq_selected:
show_message_dialog("Error. No bouquet is selected!")
return
model = view.get_model()
dest_index = 0
if drop_info:
path, position = drop_info
dest_iter = model.get_iter(path)
if dest_iter:
dest_index = model.get_value(dest_iter, 0)
itr_str, sep, source = data.partition(":")
itrs = itr_str.split(",")
try:
fav_bouquet = __bouquets[bq_selected]
if source == SERVICE_LIST_NAME:
ext_model = __services_view.get_model()
ext_itrs = [ext_model.get_iter_from_string(itr) for itr in itrs]
@@ -246,21 +266,24 @@ def on_satellite_editor_show(model):
show_satellites_dialog(__main_window, __options["data_dir_path"])
def data_open(model):
@run_task
def on_data_open(model):
try:
model.clear()
__fav_model.clear()
model_name = model.get_name()
data_path = get_config()["data_dir_path"]
if model_name == SERVICE_LIST_NAME:
for ch in get_channels(data_path + "lamedb"):
# adding channels to dict with fav_id as keys
__channels[ch.fav_id] = ch
model.append(ch)
if model_name == BOUQUETS_LIST_NAME:
bouquets = get_bouquets(data_path)
for bouquet in bouquets:
parent = model.append(None, [bouquet.name, None])
parent = model.append(None, [bouquet.name, bouquet.type])
for bt in bouquet.bouquets:
name, bt_type = bt.name, bt.type
model.append(parent, [name, bt_type])
@@ -269,23 +292,36 @@ def data_open(model):
__status_bar.push(1, getattr(e, "message", repr(e)))
def on_data_open(model):
# Maybe is not necessary? Need testing.
task = Thread(target=data_open(model))
task.start()
@run_task
def on_data_save(*args):
# Perhaps needs a dialog to choose what we need to save!!!
bouquet_selected = is_bouquet_selected()
path = __options["data_dir_path"]
if bouquet_selected and __fav_view.is_focus(): # bouquets
fav_ids = []
__fav_model.foreach(lambda model, p, itr: fav_ids.append(model.get(model.get_iter(p), 4)))
channels = [__channels[fav_id[0]] for fav_id in fav_ids]
write_bouquet(path, bouquet_selected, channels)
elif __services_view.is_focus():
write_channels(path, __channels.values())
bouquets = []
services = []
services_model = __services_view.get_model()
s_n_columns = services_model.get_n_columns()
def parse_bouquets(model, b_path, itr):
if model.iter_has_child(itr):
num_of_children = model.iter_n_children(itr)
bqs = []
for num in range(num_of_children):
bq_itr = model.iter_nth_child(itr, num)
bq_name, bq_type = model.get(bq_itr, 0, 1)
favs = __bouquets["{}:{}".format(bq_name, bq_type)]
bq = Bouquet(bq_name, bq_type, [__channels[f_id] for f_id in favs])
bqs.append(bq)
bqs = Bouquets(*model.get(itr, 0, 1), bqs)
bouquets.append(bqs)
# Getting bouquets
__bouquets_view.get_model().foreach(parse_bouquets)
write_bouquets(path + "tmp/", bouquets, __bouquets)
# Getting services
services_model.foreach(lambda model, s_path, itr:
services.append(model.get(itr, *[item for item in range(s_n_columns)])))
write_channels(path + "tmp/", services)
def on_services_selection(model, path, column):
@@ -298,6 +334,7 @@ def on_fav_selection(model, path, column):
def on_bouquets_selection(model, path, column):
__fav_model.clear()
if len(path) > 1:
delete_selection(__services_view)
update_bouquet_channels(model, path)
@@ -308,8 +345,10 @@ def update_bouquet_channels(model, path, bq_key=None):
tree_iter = None
if path:
tree_iter = model.get_iter(path)
key = bq_key if bq_key else "{}:{}".format(*model.get(tree_iter, 0, 1))
services = __bouquets[key]
for num, ch_id in enumerate(services):
channel = __channels.get(ch_id, None)
if channel:
@@ -323,8 +362,10 @@ def is_bouquet_selected():
"""
selection = __bouquets_view.get_selection()
model, path = selection.get_selected_rows()
if len(path) < 1 or model.iter_has_child(model.get_iter(path)):
return False
return "{}:{}".format(*model.get(model.get_iter(path), 0, 1))

View File

@@ -1,3 +1,4 @@
from main.commons import run_task
from main.eparser import get_satellites, write_satellites, Satellite, Transponder
from . import Gtk, Gdk
@@ -19,11 +20,13 @@ def show_satellites_dialog(transient, data_path):
dialog.destroy()
@run_task
def on_satellites_list_load(model):
""" Load satellites data into model """
satellites = get_satellites(__data_path)
model.clear()
aggr = [None for x in range(9)]
for name, flags, pos, transponders in satellites:
parent = model.append(None, [name, *aggr, flags, pos])
for transponder in transponders:
@@ -38,22 +41,26 @@ def on_remove(view):
model.remove(itr)
@run_task
def on_save(view):
model = view.get_model()
satellites = []
model.foreach(parse_data, satellites)
write_satellites(satellites, __data_path)
write_satellites(satellites, __data_path + "tmp/")
def parse_data(model, path, itr, sats):
if model.iter_has_child(itr):
num_of_children = model.iter_n_children(itr)
transponders = []
num_columns = model.get_n_columns()
for num in range(num_of_children):
transponder_itr = model.iter_nth_child(itr, num)
transponder = model.get(transponder_itr, *[item for item in range(model.get_n_columns())])
transponder = model.get(transponder_itr, *[item for item in range(num_columns)])
transponders.append(Transponder(*transponder[1:-2]))
sat = model.get(itr, *[item for item in range(model.get_n_columns())])
sat = model.get(itr, *[item for item in range(num_columns)])
satellite = Satellite(sat[0], sat[-2], sat[-1], transponders)
sats.append(satellite)