Compare commits

..

240 Commits

Author SHA1 Message Date
DYefremov
3ec5d264a0 Spanish, Portuguese and Dutch translation update 2020-07-27 21:29:07 +03:00
DYefremov
a2882b6589 upd README 2020-07-25 23:34:22 +03:00
DYefremov
31780bbf56 rm dist 2020-07-25 23:13:17 +03:00
DYefremov
286f1ffc3f version update 2020-07-25 13:43:46 +03:00
DYefremov
3bf97e5e0d minor change in dialogs appearance 2020-07-25 13:34:57 +03:00
DYefremov
c7c411c72b update ref fix 2020-07-24 11:00:20 +03:00
DYefremov
6b8a83511a slight appearance change of dialogs 2020-07-24 03:39:14 +03:00
DYefremov
f8e259293a German and Russian translation update 2020-07-22 17:33:36 +03:00
DYefremov
7adbf6b8a9 added keyboard[del] support 2020-07-22 17:32:57 +03:00
DYefremov
b68535e88a loading providers fix 2020-07-22 17:31:10 +03:00
DYefremov
b98ca359df fix display of cas 2020-07-22 17:30:36 +03:00
DYefremov
cbfd1486e1 added lock support for iptv 2020-07-22 17:30:03 +03:00
DYefremov
ad185f1efa German translation update 2020-07-22 17:29:33 +03:00
DYefremov
cea4ed1a66 Russian translation update 2020-07-22 17:28:38 +03:00
DYefremov
853d054a68 added audio codec option 2020-07-22 17:25:01 +03:00
DYefremov
8a1cead2f7 added notifications 2020-07-21 14:30:59 +03:00
DYefremov
37e0a8fdac dist update 2020-07-13 21:44:25 +03:00
DYefremov
29c66142ee minor fix 2020-07-13 21:00:26 +03:00
DYefremov
4fd2a2a600 bouquet import fix 2020-07-12 19:18:11 +03:00
DYefremov
6b360d48c4 added bouquets import via dnd 2020-07-12 16:44:40 +03:00
DYefremov
3a307b277c minor gui fix 2020-07-12 16:33:13 +03:00
DYefremov
9e685058a2 added debug mode option 2020-07-12 16:32:56 +03:00
DYefremov
3f07b09bb5 added sorting of bouquet services 2020-07-12 16:28:18 +03:00
DYefremov
1dca45f18f dist update 2020-07-04 14:02:52 +03:00
DYefremov
8b5ebc132d added download dialog options 2020-07-04 13:41:46 +03:00
DYefremov
b076db23bb auto save profile settings 2020-07-02 17:32:51 +03:00
DYefremov
41d479e18f dist update 2020-06-30 09:07:30 +03:00
DYefremov
cf540e5c9a picons explorer gui changes 2020-06-29 15:58:43 +03:00
DYefremov
3c7c8ebd83 fix lock/hide in filter mode 2020-06-22 19:46:36 +03:00
DYefremov
9b0c173eb8 skip of marker counting 2020-06-22 11:11:21 +03:00
DYefremov
208ce53c48 update *.spec 2020-06-21 10:27:15 +03:00
DYefremov
bb6679eddf fix getting path from uri 2020-06-21 00:52:50 +03:00
DYefremov
57f5e40439 changed filter entry icon 2020-06-15 21:39:13 +03:00
DYefremov
dad02e8e5c changed dnd for picons 2020-06-15 21:32:47 +03:00
DYefremov
844dab10a0 changed callback for screenshots 2020-06-15 16:57:39 +03:00
DYefremov
c1f5fd8006 small yt refactoring 2020-06-13 21:01:14 +03:00
DYefremov
86b974b632 get fav id fix 2020-06-13 19:14:31 +03:00
DYefremov
cf7e3a1b1b added space item to fav elements 2020-06-13 19:12:23 +03:00
DYefremov
bb07eb0a8a small dnd fix 2020-06-12 00:39:46 +03:00
DYefremov
f6de7d0fce version update 2020-06-11 11:48:45 +03:00
DYefremov
647b528899 added frame for info bar 2020-06-11 10:47:27 +03:00
DYefremov
7ed64c76ba added paned style 2020-06-11 10:27:23 +03:00
DYefremov
bcfdb09169 small http api init fix 2020-06-10 18:34:42 +03:00
DYefremov
c0c2ddef34 added basic youtube-dl support 2020-06-10 18:02:47 +03:00
DYefremov
b02eb37f1c corrections after merge 2020-06-10 18:01:23 +03:00
DYefremov
9b9f1d5492 added eserviceuri (8193) stream type 2020-06-10 11:56:01 +03:00
DYefremov
caba789e02 small rework of screenshot mode 2020-06-10 11:55:49 +03:00
DYefremov
5b1bffc078 impl local removing for picons 2020-06-10 11:55:41 +03:00
DYefremov
7e35a081a0 logging extension on data downloading 2020-06-10 11:55:32 +03:00
DYefremov
ccbc7a4315 added dnd for selective download/send 2020-06-10 11:55:21 +03:00
DYefremov
7f3f900725 added selective download/send of picons 2020-06-10 11:53:08 +03:00
DYefremov
921b936db0 added update picons dest view 2020-06-10 11:52:57 +03:00
DYefremov
bc6d372ade improved functionality of the picons explorer 2020-06-10 11:51:51 +03:00
DYefremov
3c28d12579 added youtube-dl options 2020-06-10 11:45:10 +03:00
DYefremov
e9544cc77f added app settings read exception 2020-06-10 11:42:26 +03:00
DYefremov
bd047e5f72 added services filtering from picons manager 2020-06-10 11:42:05 +03:00
DYefremov
adf7262ed6 adding picons to src via dnd 2020-06-10 11:41:23 +03:00
DYefremov
74a1ffea3a added basic screenshots support 2020-06-10 11:40:54 +03:00
DYefremov
6e78a539c3 modified cas values 2020-06-10 11:36:46 +03:00
DYefremov
c3ce3fc82e added space [hidden marker] support 2020-06-10 11:36:32 +03:00
DYefremov
8c61720423 version update 2020-06-10 11:32:54 +03:00
DYefremov
25e0e6939a copy tr *.mo file 2020-06-08 23:55:39 +03:00
audi06_19
e3232e48cf Turkish translation correction (#26) 2020-06-08 23:55:26 +03:00
DYefremov
aaa610852b dist update 2020-06-04 12:47:19 +03:00
DYefremov
04e9179025 added accelerator for input dialog 2020-06-04 11:46:21 +03:00
DYefremov
bce5636eaa added check for unsaved changes 2020-06-04 11:41:38 +03:00
DYefremov
0e10631931 rm unavailable iptv fix 2020-06-03 11:30:26 +03:00
DYefremov
77a3edead2 zap mode fix 2020-06-03 00:07:19 +03:00
DYefremov
8a8b249e14 small bq parsing changes (prevent #12) 2020-06-02 23:58:39 +03:00
DYefremov
4025f0933d copy pl *.mo file 2020-06-02 10:03:31 +03:00
DYefremov
bba4054bff Polish translation correction 2020-06-02 09:36:37 +03:00
Wieslaw Weglowski
e322d36023 Polish translation update(#23) 2020-06-02 09:07:31 +03:00
DYefremov
bb5afb0206 dist update 2020-05-23 01:36:35 +03:00
DYefremov
115f3960a7 drag on icon fix
(cherry picked from commit 0e50f1952d)
2020-05-23 01:22:09 +03:00
DYefremov
6d37da072e German translation update 2020-05-19 14:32:31 +03:00
DYefremov
99c3b1d194 Russian translation update 2020-05-19 14:32:17 +03:00
DYefremov
43afaf77b8 minor log changes 2020-05-19 12:01:11 +03:00
DYefremov
38aabb1b94 Dutch translation update 2020-05-18 16:31:24 +03:00
DYefremov
ef501f1557 small dnd fix 2020-05-18 12:40:21 +03:00
DYefremov
4679f9379c changed dnd for bouquets list 2020-05-17 15:28:44 +03:00
DYefremov
b2ea39f8a6 minor fixes 2020-05-17 14:55:18 +03:00
DYefremov
638be67425 dist update 2020-05-12 21:15:31 +03:00
DYefremov
9ca5a597d5 scaling picons on loading 2020-05-12 21:14:00 +03:00
DYefremov
d95ba7336f copy tr *.mo file 2020-05-12 17:26:12 +03:00
audi06
c78b18ddb7 Turkish translation update (#22) 2020-05-12 17:24:45 +03:00
DYefremov
92984c5fa6 start update 2020-05-12 15:19:47 +03:00
DYefremov
ca65f64a4f changed some dialogs elements 2020-05-12 14:13:01 +03:00
DYefremov
78dcccbd51 minor optimization and fix 2020-05-10 21:39:48 +03:00
DYefremov
f984d10c82 German translation update 2020-05-10 18:50:22 +03:00
DYefremov
c4ea451f52 small fix to prevent (#12) 2020-05-10 18:50:11 +03:00
DYefremov
36ec6d5079 added picons filter by service name 2020-05-10 18:49:59 +03:00
DYefremov
91706c722f Russian translation update 2020-05-10 15:13:06 +03:00
DYefremov
4ef8c4d186 fix to prevent #12 2020-05-08 17:15:34 +03:00
DYefremov
f9e92b28d0 dist update 2020-05-07 15:10:48 +03:00
DYefremov
832bab91a4 reworked settings dialog 2020-05-07 14:19:46 +03:00
DYefremov
951c99338f added skip upload if file not found 2020-05-05 00:04:05 +03:00
DYefremov
ee91eb9413 fix use colors 2020-05-04 22:33:05 +03:00
DYefremov
912c38825b redesigned appearance for most dialogs 2020-05-04 19:36:52 +03:00
DYefremov
de4d012784 fix to prevent (#21) 2020-05-04 19:20:51 +03:00
DYefremov
351ce81e94 minor fixes for yt 2020-05-03 02:05:36 +03:00
DYefremov
3a0f096a6c changed data dir creation 2020-05-03 01:42:28 +03:00
DYefremov
29088ec19e dist update 2020-04-30 14:12:58 +03:00
DYefremov
4c144951f0 reworking of download dialog 2020-04-30 14:09:01 +03:00
DYefremov
dae6ad765a added accelerators and tooltips 2020-04-30 13:55:40 +03:00
DYefremov
b934407d7e added download/upload of [terrestrial, cable].xml 2020-04-30 13:53:15 +03:00
DYefremov
3fb5b82cc6 slight optimization of loading/deleting data 2020-04-30 13:47:24 +03:00
DYefremov
ba3ad9a9ef setting text for wait dialog 2020-04-30 13:45:09 +03:00
DYefremov
7a4620a374 path resolve fix 2020-04-30 13:42:02 +03:00
DYefremov
174634ecbc reworking of picons dialog 2020-04-30 13:36:01 +03:00
DYefremov
73ae57d07b extracting themes with tar 2020-04-23 18:43:22 +03:00
DYefremov
055a700586 small refactoring of base icons init 2020-04-23 15:43:48 +03:00
DYefremov
04203240a7 minor fixes for filter and search 2020-04-23 10:33:56 +03:00
DYefremov
a433e01b65 added group style 2020-04-22 10:02:47 +03:00
DYefremov
8f591a8b9a small refactoring of chooser dialog 2020-04-21 14:45:34 +03:00
DYefremov
dcc217b0de upd README 2020-04-20 20:50:10 +03:00
DYefremov
d06334b0af added picons assignment by drag on icon 2020-04-20 13:55:38 +03:00
DYefremov
6957a960ca added hints support for the main list 2020-04-20 13:51:05 +03:00
DYefremov
9fe328b54e minor refactoring 2020-04-20 13:46:42 +03:00
DYefremov
b3dc9b72c9 version update 2020-04-16 21:42:07 +03:00
DYefremov
b6a4d46227 upd README 2020-04-16 21:41:05 +03:00
audi06
53776bdf62 added Turkish selection (#20) 2020-04-16 21:10:28 +03:00
DYefremov
ba9ba4129f copy tr *.mo file 2020-04-16 21:10:13 +03:00
audi06
a2411ba86e added Turkish translation (#19)
(cherry picked from commit 8d96f02e2e)
2020-04-16 21:10:01 +03:00
DYefremov
a6d8573999 added bouquet file naming option 2020-04-16 17:29:04 +03:00
DYefremov
7510d42fb9 minor fixes 2020-04-13 20:08:22 +03:00
DYefremov
036e666c9b styles decoupling 2020-04-13 20:07:57 +03:00
DYefremov
c9c962e129 added appearance settings 2020-04-13 13:54:54 +03:00
DYefremov
ea71af9462 dist update 2020-04-10 23:22:57 +03:00
DYefremov
0a5b51de6e style changes for some ui elements 2020-04-10 23:09:17 +03:00
DYefremov
8cb413ec92 added basic hints support 2020-04-08 18:40:27 +03:00
DYefremov
5dfb702484 added option for hints 2020-04-08 18:37:10 +03:00
DYefremov
0cab4e1238 epg options fix 2020-04-02 16:53:03 +03:00
DYefremov
85f5c37f28 changed some player args 2020-03-28 20:20:49 +03:00
DYefremov
3df6d7bba0 translations update for dist 2020-03-28 19:56:24 +03:00
DYefremov
e45c56f4cc changed toolbar elements position 2020-03-28 19:31:13 +03:00
DYefremov
7d03631924 basic implementation of the play mode 2020-03-28 18:45:05 +03:00
DYefremov
7b9ec6a4b1 small cleaning 2020-03-28 18:39:13 +03:00
DYefremov
d640210ab0 copy *.mo file 2020-03-24 15:38:35 +03:00
wwns
f7e8283355 Polish translation update (#18) 2020-03-24 15:38:10 +03:00
DYefremov
f93c81de19 wrap m3u data 2020-03-24 15:38:06 +03:00
DYefremov
e1804755d2 added play streams mode options 2020-03-24 15:38:01 +03:00
DYefremov
1cf56639c1 copy .mo file 2020-03-21 16:47:50 +03:00
Víctor Pont
943b4c540f Spanish translation update and corrections (#17) 2020-03-21 16:47:43 +03:00
DYefremov
4602c51c01 added simple telnet client 2020-03-17 14:10:49 +03:00
DYefremov
a84cc7727f minor fix 2020-03-14 09:09:11 +03:00
DYefremov
250e03af5d changed record button update 2020-03-13 14:37:21 +03:00
DYefremov
2c5f8eb0ed toolbar elements changes 2020-03-11 16:47:10 +03:00
DYefremov
6f4ff4c97d added transcoding options 2020-03-11 16:05:13 +03:00
DYefremov
ee29659739 added record of current service 2020-03-11 16:04:41 +03:00
DYefremov
8a1496a84c added new paths settings 2020-03-11 15:57:41 +03:00
DYefremov
23c3035162 fix service status info 2020-03-11 15:56:57 +03:00
DYefremov
a506356547 version update 2020-03-11 15:55:59 +03:00
DYefremov
0c284fb0d9 added picons multiple assignment 2020-03-11 15:50:23 +03:00
DYefremov
b437385325 German translation update
(cherry picked from commit 3d627b57a4)
2020-02-28 00:53:33 +03:00
DYefremov
c60bba5535 upd README 2020-02-24 12:54:29 +03:00
DYefremov
1c2d0ab9ea small fix
(cherry picked from commit 7444db7e21)
2020-02-24 12:51:56 +03:00
DYefremov
f35f7fbc8a update dist 2020-02-21 00:14:10 +03:00
DYefremov
42aaad291f Russian translation update
(cherry picked from commit 7554f40c6a)
2020-02-20 14:16:09 +03:00
DYefremov
9c8c617393 gui changes for send to 2020-02-20 12:11:41 +03:00
DYefremov
98fc963fa1 fix getting sats 2020-02-19 12:03:27 +03:00
DYefremov
fbb5cd0352 added appindicator support 2020-02-19 10:15:01 +03:00
DYefremov
5abe3de3b6 toolbar changes 2020-02-18 00:35:17 +03:00
DYefremov
0b3f26ab84 .mo file update 2020-02-17 09:21:40 +03:00
wwns
2666146b5e Polish translation update (#11)
Polish translation update.
2020-02-17 08:50:32 +03:00
DYefremov
be90b518c9 update of .mo file 2020-02-14 22:55:36 +03:00
wwns
adeae58488 Polish translation update (#10) 2020-02-14 22:20:07 +03:00
DYefremov
b204f042ee update dist 2020-02-12 22:29:50 +03:00
DYefremov
79d0e9d256 added icons path to .spec file 2020-02-12 21:45:14 +03:00
DYefremov
4dcfde8b53 revert of get yt icon 2020-02-12 21:16:47 +03:00
DYefremov
42f687020b moved get yt icon 2020-02-12 20:19:09 +03:00
DYefremov
14bf79dbf9 toolbar changes 2020-02-12 17:35:44 +03:00
DYefremov
f660beef16 update of data path 2020-02-12 13:53:18 +03:00
DYefremov
99d17b36c3 added Polish selection 2020-02-12 12:40:27 +03:00
wwns
3113fadcca added a Polish translation (#5)
* added a Polish translation

* added a Polish translation

* name change
2020-02-11 21:43:53 +03:00
DYefremov
67a394359d fix bq deletion 2020-02-10 19:28:59 +03:00
DYefremov
1acb7fdd81 changing profile on data download 2020-02-10 17:01:48 +03:00
DYefremov
dced81581c fix profile edit 2020-02-10 14:52:30 +03:00
DYefremov
6a52988f1a update dist 2020-02-01 18:55:31 +03:00
DYefremov
4a1d714604 added basic support for keyboard shortcuts 2020-02-01 17:45:36 +03:00
DYefremov
2e12e1ec87 auto rename bouquets with duplicate names 2020-02-01 09:34:45 +03:00
DYefremov
4c6336e75f added checking for bouquet names duplicate 2020-01-29 14:58:32 +03:00
DYefremov
b7d0ba7f4b added controls to the transmitter 2020-01-28 16:37:53 +03:00
DYefremov
405e07bbc4 added player requests 2020-01-28 16:36:08 +03:00
DYefremov
6ded67147b update dist 2020-01-24 20:47:24 +03:00
DYefremov
4a0e2acd9c minor gui changes 2020-01-24 01:06:08 +03:00
DYefremov
5876f70884 upd. README 2020-01-23 19:18:49 +03:00
DYefremov
3cb4f1095d fix picons downloading from bundle 2020-01-23 19:17:54 +03:00
DYefremov
af46c2fb1d minor fixes for player elems 2020-01-23 16:13:09 +03:00
DYefremov
cbcdf19be6 added remove and download to picons 2020-01-23 00:48:57 +03:00
DYefremov
f326a9c723 some corrections 2020-01-19 20:07:59 +03:00
DYefremov
53888a45dc Merge branch 'development' into experimental-mac
# Conflicts:
#	DemonEditor.desktop
#	README.md
#	app/connections.py
#	app/ui/main_app_window.py
#	app/ui/main_window.glade
#	app/ui/uicommons.py
#	build-deb.sh
#	deb/DEBIAN/control
#	deb/DEBIAN/copyright
#	deb/usr/bin/demon-editor
#	deb/usr/share/applications/DemonEditor.desktop
#	start.py
2020-01-18 23:08:45 +03:00
DYefremov
c2d3cb7673 some changes for translation 2019-12-28 23:21:19 +03:00
DYefremov
9d4b507559 Merge remote-tracking branch 'origin/experimental-mac' into experimental-mac 2019-12-21 13:57:37 -08:00
DYefremov
2993fcd7f7 update dist 2019-12-18 03:50:17 -08:00
DYefremov
5bea9887db minor clean 2019-12-18 08:56:41 +03:00
DYefremov
dd0edfc811 minor clean 2019-12-17 12:56:07 +03:00
DYefremov
5bf6500809 added exception 2019-12-17 12:03:15 +03:00
DYefremov
d05da3f44c minor player fix 2019-12-16 15:49:24 +03:00
DYefremov
b251ce8b69 fixes after merge 2019-12-16 10:47:18 +03:00
DYefremov
df36860239 Merge branch 'development' into experimental-mac
# Conflicts:
#	app/properties.py
#	app/tools/media.py
#	app/ui/dialogs.py
#	app/ui/main_app_window.py
#	app/ui/transmitter.py
#	deb/usr/share/locale/es/LC_MESSAGES/demon-editor.mo
2019-12-16 10:36:19 +03:00
DYefremov
6f27040164 upd README 2019-12-14 13:22:22 +03:00
DYefremov
4d488dd224 update dist 2019-12-08 02:38:28 -08:00
DYefremov
c728a59e92 update dist 2019-12-08 02:32:40 -08:00
DYefremov
98341064d3 fix set nso 2019-12-08 01:09:44 -08:00
DYefremov
fc00b25fd2 revert media player view 2019-12-08 01:20:06 +03:00
DYefremov
638f33ac5a update vlc 2019-12-07 21:07:51 +03:00
DYefremov
88167912b3 fix status image show 2019-12-06 15:20:14 +03:00
DYefremov
450d7f4c72 added dist 2019-12-06 08:50:26 +03:00
DYefremov
24729c064c base impl of send to 2019-12-05 10:52:04 -08:00
DYefremov
df3c2a3938 added build support 2019-12-05 10:47:49 -08:00
DYefremov
44bf8b96ff fix set icon after marge 2019-11-26 18:46:57 +03:00
DYefremov
6b86db4aa4 Merge branch 'development' into experimental-mac
# Conflicts:
#	app/connections.py
#	app/ui/main_app_window.py
#	app/ui/main_window.glade
#	deb/DEBIAN/control
2019-11-26 18:41:07 +03:00
DYefremov
bf9ad139e5 added style 2019-11-01 00:24:13 +03:00
DYefremov
20fc199d02 moved toolbar to the top 2019-10-28 11:59:58 +03:00
DYefremov
e0a22f72fc changed setting service info 2019-10-28 11:44:30 +03:00
DYefremov
8cadc47da5 added current service status info 2019-10-28 11:44:12 +03:00
DYefremov
499ca31992 added http-api prototype for vlc 2019-10-27 00:39:32 +03:00
DYefremov
e198f0b1e6 removed separators from toolbar 2019-10-26 15:19:39 +03:00
DYefremov
a43ac0de02 added bottom toolbar 2019-10-26 15:01:23 +03:00
DYefremov
b14e6fac16 added edit and view to the app bar menu 2019-10-25 19:17:31 +03:00
DYefremov
2dcc9a85b5 updated app bar menu 2019-10-23 12:38:23 +03:00
DYefremov
7ce9ba0db2 added prototype of playing current service 2019-10-23 12:24:57 +03:00
DYefremov
fc56b047a1 added prototype of playing current service 2019-10-23 12:20:20 +03:00
DYefremov
78dc62d46e added german translation 2019-10-23 12:19:31 +03:00
DYefremov
20e7ee3478 removing deb 2019-10-20 23:58:10 +03:00
DYefremov
ffa144367f slight refactoring of stream play 2019-10-20 23:48:35 +03:00
DYefremov
237d09a711 updated version 2019-10-20 23:48:28 +03:00
DYefremov
272cbdeb2f changed yt links icon to default 2019-10-19 09:31:51 +03:00
DYefremov
f9191a7465 minor gui changes 2019-10-18 21:07:48 +03:00
DYefremov
f22abe1d87 test nso 2019-10-17 08:11:04 -07:00
DYefremov
b94c08284a new gui test prototype for the player 2019-10-17 15:02:31 +03:00
DYefremov
e303f25f99 updated app bar menu 2019-10-14 22:09:14 +03:00
DYefremov
b80dcb7d74 fix save 2019-10-13 18:53:33 +03:00
DYefremov
63c5df0ef6 Improved functionality of the app menu bar 2019-10-13 14:07:46 +03:00
DYefremov
c69888a72d Merge remote-tracking branch 'origin/experimental-mac' into experimental-mac 2019-10-12 23:32:16 +03:00
DYefremov
07606077e5 added app menu bar prototype 2019-10-12 23:32:01 +03:00
DYefremov
e1f63bfed7 updating of dutch, spanish and portuguese 2019-10-12 23:23:48 +03:00
DYefremov
c0865beb3c Merge branch 'development' into experimental-mac 2019-10-11 15:54:53 +03:00
DYefremov
05eff28b75 upd. README 2019-10-11 14:34:08 +03:00
DYefremov
6d2150b731 changes to start on macos 2019-10-10 14:19:10 -07:00
72 changed files with 7126 additions and 8792 deletions

View File

@@ -1,11 +0,0 @@
[Desktop Entry]
Version=1.0
Name=DemonEditor
Comment=Channels and satellites list editor for Enigma2
Comment[ru]=Редактор списка каналов и спутников для Enigma2
Icon=demon-editor
Exec=bash -c 'cd $(dirname %k) && ./start.py'
Terminal=false
Type=Application
Categories=Utility;Application;
StartupNotify=false

65
DemonEditor.spec Normal file
View File

@@ -0,0 +1,65 @@
import os
import datetime
import distutils.util
EXE_NAME = 'start.py'
DIR_PATH = os.getcwd()
COMPILING_PLATFORM = distutils.util.get_platform()
PATH_EXE = [os.path.join(DIR_PATH, EXE_NAME)]
STRIP = True
BUILD_DATE = datetime.datetime.now().strftime("%Y%m%d")
block_cipher = None
ui_files = [('app/ui/*.glade', 'ui'),
('app/ui/*.css', 'ui'),
('app/ui/*.ui', 'ui'),
('app/ui/lang*', 'share/locale'),
('app/ui/icons*', 'share/icons')
]
a = Analysis([EXE_NAME],
pathex=PATH_EXE,
binaries=None,
datas=ui_files,
hiddenimports=[],
hookspath=[],
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher)
pyz = PYZ(a.pure,
a.zipped_data,
cipher=block_cipher)
exe = EXE(pyz,
a.scripts,
exclude_binaries=True,
name='DemonEditor',
debug=False,
strip=STRIP,
upx=True,
console=False)
coll = COLLECT(exe,
a.binaries,
a.zipfiles,
a.datas,
strip=STRIP,
upx=True,
name='DemonEditor')
app = BUNDLE(coll,
name='DemonEditor.app',
icon='icon.icns',
bundle_identifier=None,
info_plist={
'NSPrincipalClass': 'NSApplication',
'CFBundleName': 'DemonEditor',
'CFBundleDisplayName': 'DemonEditor',
'CFBundleGetInfoString': "Enigma2 channel and satellites editor",
'CFBundleShortVersionString': "1.0.0 Alpha (Build: {})".format(BUILD_DATE),
'NSHumanReadableCopyright': u"Copyright © 2020, Dmitriy Yefremov"
})

124
README.md
View File

@@ -1,12 +1,9 @@
# <img src="app/ui/icons/hicolor/96x96/apps/demon-editor.png" width="32" /> DemonEditor
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE) ![platform](https://img.shields.io/badge/platform-linux%20|%20macos-lightgrey)
### Enigma2 channel and satellites list editor for GNU/Linux.
Experimental support of Neutrino-MP or others on the same basis (BPanther, etc).
Focused on the convenience of working in lists from the keyboard. The mouse is also fully supported (Drag and Drop etc).
![Main app window in macOS Big Sur.](https://user-images.githubusercontent.com/7511379/92320982-9b20c780-f02e-11ea-8a43-fc0c70503573.png)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
## Enigma2 channel and satellites list editor for macOS (experimental).
### The functionality and performance of this version may be different from the Linux version!
## Main features of the program
### Main features of the program:
* Editing bouquets, channels, satellites.
* Import function.
* Backup function.
@@ -15,67 +12,62 @@ Focused on the convenience of working in lists from the keyboard. The mouse is a
* Downloading of picons and updating of satellites (transponders) from the web.
* Import to bouquet(Neutrino WEBTV) from m3u.
* Export of bouquets with IPTV services in m3u.
* Assignment of EPG from DVB or XML for IPTV services (only Enigma2, experimental).
* Assignment of EPGs from DVB or XML for IPTV services (only Enigma2, experimental).
* Preview (playback) of IPTV or other streams directly from the bouquet list (should be installed [VLC](https://www.videolan.org/vlc/)).
#### Keyboard shortcuts
* **Ctrl + X** - only in bouquet list.
* **Ctrl + C** - only in services list.
Clipboard is **"rubber"**. There is an accumulation before the insertion!
* **Ctrl + Insert** - copies the selected channels from the main list to the the bouquet beginning
or inserts (creates) a new bouquet.
* **Ctrl + BackSpace** - copies the selected channels from the main list to the bouquet end.
* **Ctrl + E** - edit.
* **Ctrl + R, F2** - rename.
* **Ctrl + S, T** in Satellites edit tool for create satellite or transponder.
* **Ctrl + L** - parental lock.
* **Ctrl + H** - hide/skip.
* **Ctrl + P** - start play IPTV or other stream in the bouquet list.
* **Ctrl + Z** - switch(**zap**) the channel(works when the HTTP API is enabled, Enigma2 only).
* **Ctrl + W** - switch to the channel and watch in the program.
* **Space** - select/deselect.
* **Left/Right** - remove selection.
* **Ctrl + Up, Down, PageUp, PageDown, Home, End**- move selected items in the list.
* **Ctrl + O** - (re)load user data from current dir.
* **Ctrl + D** - load data from receiver.
* **Ctrl + U/B** - upload data/bouquets to receiver.
* **Ctrl + I** - extra info, details.
* **Ctrl + F** - show/hide search bar.
* **Ctrl + Shift + F** - show/hide filter bar.
For **multiple** selection with the mouse, press and hold the **Ctrl** key!
#### Keyboard shortcuts:
* **&#8984; + X** - only in bouquet list.
* **&#8984; + C** - only in services list.
Clipboard is **"rubber"**. There is an accumulation before the insertion!
* **&#8984; + E** - edit.
* **&#8984; + R, F2** - rename.
* **&#8984; + S, T** in Satellites edit tool for create satellite or transponder.
* **&#8984; + L** - parental lock.
* **&#8984; + H** - hide/skip.
* **&#8984; + P** - start play IPTV or other stream in the bouquet list.
* **&#8984; + Z** - switch(**zap**) the channel(works when the HTTP API is enabled, Enigma2 only).
* **&#8984; + W** - switch to the channel and watch in the program.
* **&#8984; + Up/Down** - move selected items in the list.
* **&#8984; + O** - (re)load user data from current dir.
* **&#8984; + D** - load data from receiver.
* **&#8984; + U/B** - upload data/bouquets to receiver.
* **&#8984; + F** - show/hide search bar.
* **&#8679; + &#8984; + F** - show/hide filter bar.
* **Left/Right** - remove selection.
## Minimum requirements
*Python >= 3.5.2, GTK+ >= 3.16 with PyGObject bindings, python3-requests.*
## Installation and Launch
* ### Linux
To start the program, in most cases it is enough to download the [archive](https://github.com/DYefremov/DemonEditor/archive/master.zip), unpack and run it by
double clicking on DemonEditor.desktop in the root directory, or launching from the console
with the command:
```./start.py```
Extra folders can be deleted, excluding the *app* folder and root files like *DemonEditor.desktop* and *start.py*!
For multiple mouse selection (including Drag and Drop), press and hold the **&#8984;** key!
To create a simple **debian package**, you can use the *build-deb.sh.*
Users of **LTS** versions of [Ubuntu](https://ubuntu.com/) or distributions based on them can use [PPA](https://launchpad.net/~dmitriy-yefremov/+archive/ubuntu/demon-editor) repository.
* ### macOS (experimental)
**This program can also be run on macOS.**
To work in this OS, you must use a [separate branch](https://github.com/DYefremov/DemonEditor/tree/experimental-mac).
**The functionality and performance of this version may be different from the Linux version!**
## Important
The program is tested only with [openATV](https://www.opena.tv/) image and **Formuler F1** receiver in [Linux Mint](https://linuxmint.com/) (MATE 64-bit) distribution!
Terrestrial(DVB-T/T2) and cable(DVB-C) channels are only supported for Enigma2.
### Minimum requirements:
Python >= **3.5**, GTK+ >= **3.16**, pygobject3, adwaita-icon-theme, python3-requests.
#### Installation:
```brew install python3 gtk+3 pygobject3 adwaita-icon-theme```
```pip3 install requests```
#### Optional:
```brew install wget imagemagick```
```pip3 install pyobjc```
#### Launching:
To start the program, just download the archive, unpack and run it from the terminal with the command: ```./start.py```
### Building standalone application:
Install [PyInstaller](https://www.pyinstaller.org/) with the command from the terminal:
```pip3 install pyinstaller```
and in th root dir run command:
```pyinstaller DemonEditor.spec```
### Standalone package:
You can download the ready-made package as a ***.dmg** file from the [releases](https://github.com/DYefremov/DemonEditor/releases) page.
Recommended copy the package to the **Application** directory.
Perhaps in the security settings it will be necessary to allow the launch of this application!
**The package may not contain all the latest changes. Not all features can be supported and tested!**
### Note:
THIS SOFTWARE COMES WITH ABSOLUTELY NO WARRANTY.
AUTHOR IS NOT LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY CONNECTION WITH THIS SOFTWARE.
The package may contain components distributed under the GPL [v3](http://www.gnu.org/licenses/gpl-3.0.html) or lower license.
By downloading and using this package you agree to the terms of this [license](http://www.gnu.org/licenses/gpl-3.0.html) and the possible inconvenience associated with this!
### Important:
Terrestrial(DVB-T/T2) and cable(DVB-C) channels are only supported for Enigma2!
Main supported *lamedb* format is version **4**. Versions **3** and **5** has only **experimental** support!
For version **3** is only read mode available. When saving, version **4** format is used instead.
For version **3** is only read mode available. When saving, version **4** format is used instead!
When using the multiple import feature, from *lamedb* will be taken data **only for channels that are in the selected bouquets!**
If you need full set of the data, including *[satellites, terrestrial, cables].xml* (current files will be overwritten),
just load your data via *"File/Open"* and press *"Save"*. When importing separate bouquet files, only those services
(excluding IPTV) that are in the **current open lamedb** (main list of services) will be imported.
#### Command line arguments:
* **-l** - write logs to file.
* **-d on/off** - turn on/off debug mode. Allows to display more information in the logs.
## License
Licensed under the [MIT](LICENSE) license.
When using the multiple import feature, from *lamedb* will be taken data **only for channels that are in the
selected bouquets!** If you need full set of the data, including *[satellites, terrestrial, cables].xml* (current files will be overwritten),
just load your data via *"File/Open"* and press *"Save"*. When importing separate bouquet files, only those services
(excluding IPTV) that are in the **current open lamedb** (main list of services) will be imported.

View File

@@ -72,7 +72,8 @@ def download_data(*, settings, download_type=DownloadType.ALL, callback=print, f
if download_type is DownloadType.ALL or download_type is DownloadType.BOUQUETS:
ftp.cwd(settings.services_path)
file_list = BQ_FILES_LIST + DATA_FILES_LIST if download_type is DownloadType.ALL else BQ_FILES_LIST
download_files(ftp, save_path, file_list, callback)
for file in filter(lambda f: f.endswith(file_list), ftp.nlst()):
download_file(ftp, file, save_path, callback)
# *.xml and webtv
if download_type in (DownloadType.ALL, DownloadType.SATELLITES):
download_xml(ftp, save_path, settings.satellites_xml_path, STC_XML_FILE, callback)
@@ -92,7 +93,8 @@ def download_data(*, settings, download_type=DownloadType.ALL, callback=print, f
save_path = epg_options.get("epg_dat_path", save_path)
ftp.cwd(stb_path)
download_files(ftp, save_path, "epg.dat", callback)
for file in filter(lambda f: f.endswith("epg.dat"), ftp.nlst()):
download_file(ftp, file, save_path, callback)
callback("\nDone.\n")
@@ -117,8 +119,6 @@ def upload_data(*, settings, download_type=DownloadType.ALL, remove_unused=False
message = "All user data will be reloaded!"
elif download_type is DownloadType.SATELLITES:
message = "Satellites.xml file will be updated!"
elif download_type is DownloadType.PICONS:
message = "Picons will be updated!"
params = urlencode({"text": message, "type": 2, "timeout": 5})
ht.send((url + "message?{}".format(params), "Sending info message... "))
@@ -128,15 +128,14 @@ def upload_data(*, settings, download_type=DownloadType.ALL, remove_unused=False
ht.send((url + "powerstate?newstate=0", "Toggle Standby "))
time.sleep(2)
else:
if download_type is not DownloadType.PICONS:
# telnet
tn = telnet(host=host,
user=settings.telnet_user,
password=settings.telnet_password,
timeout=settings.telnet_timeout)
next(tn)
# terminate enigma or neutrino
tn.send("init 4")
# telnet
tn = telnet(host=host,
user=settings.telnet_user,
password=settings.telnet_password,
timeout=settings.telnet_timeout)
next(tn)
# terminate enigma or neutrino
tn.send("init 4")
with FTP(host=host, user=settings.user, passwd=settings.password) as ftp:
ftp.encoding = "utf-8"
@@ -200,11 +199,7 @@ def upload_files(ftp, data_path, file_list, callback):
def remove_unused_bouquets(ftp, callback):
files = []
ftp.dir(files.append)
bq_files = ("tv", "radio", "bouquets.xml", "ubouquets.xml")
for file in filter(lambda f: f.endswith(bq_files), map(lambda f: f.split()[-1], map(str.rstrip, files))):
for file in filter(lambda f: f.endswith(("tv", "radio", "bouquets.xml", "ubouquets.xml")), ftp.nlst()):
callback("Deleting file: {}. Status: {}\n".format(file, ftp.delete(file)))
@@ -218,7 +213,7 @@ def upload_xml(ftp, data_path, xml_path, xml_files, callback):
def download_xml(ftp, data_path, xml_path, xml_files, callback):
""" Used for download *.xml files. """
ftp.cwd(xml_path)
download_files(ftp, data_path, xml_files, callback)
list(map(lambda f: download_file(ftp, f, data_path, callback), (f for f in ftp.nlst() if f.endswith(xml_files))))
# ***************** Picons *******************#
@@ -242,10 +237,7 @@ def download_picons(ftp, src, dest, callback, files_filter=None):
callback(str(e))
return
files = []
ftp.dir(files.append)
for file in filter(picons_filter_function(files_filter), map(lambda f: f.split()[-1], map(str.rstrip, files))):
for file in filter(picons_filter_function(files_filter), ftp.nlst()):
download_file(ftp, file, dest, callback)
@@ -257,10 +249,7 @@ def delete_picons(ftp, callback, dest=None, files_filter=None):
callback(str(e))
return
files = []
ftp.dir(files.append)
for file in filter(picons_filter_function(files_filter), map(lambda f: f.split()[-1], map(str.rstrip, files))):
for file in filter(picons_filter_function(files_filter), ftp.nlst()):
callback("Delete file: {}. Status: {}\n".format(file, ftp.delete(file)))
@@ -277,15 +266,6 @@ def picons_filter_function(files_filter=None):
return lambda f: f in files_filter if files_filter else f.endswith(PICONS_SUF)
def download_files(ftp, save_path, file_list, callback):
""" Downloads files from the receiver via FTP. """
files = []
ftp.dir(files.append)
for file in map(lambda f: f.split()[-1], filter(lambda s: s.endswith(file_list), map(str.rstrip, files))):
download_file(ftp, file, save_path, callback)
def download_file(ftp, name, save_path, callback):
with open(save_path + name, "wb") as f:
callback("Downloading file: {}. Status: {}\n".format(name, str(ftp.retrbinary("RETR " + name, f.write))))

View File

@@ -612,14 +612,6 @@ class Settings:
# *********** Appearance *********** #
@property
def dark_mode(self):
return self._settings.get("dark_mode", False)
@dark_mode.setter
def dark_mode(self, value):
self._settings["dark_mode"] = value
@property
def is_themes_support(self):
return self._settings.get("is_themes_support", False)
@@ -686,17 +678,6 @@ class Settings:
def debug_mode(self, value):
self._settings["debug_mode"] = value
# **************** Experimental **************** #
@property
def is_enable_experimental(self):
""" Allows experimental functionality. """
return self._settings.get("enable_experimental", False)
@is_enable_experimental.setter
def is_enable_experimental(self, value):
self._settings["enable_experimental"] = value
if __name__ == "__main__":
pass

View File

@@ -2,10 +2,11 @@ import glob
import os
import re
import shutil
from collections import namedtuple
from html.parser import HTMLParser
from app.commons import run_task, log
from app.commons import run_task
from app.settings import SettingsType
_ENIGMA2_PICON_KEY = "{:X}:{:X}:{}"
@@ -32,9 +33,9 @@ class PiconsParser(HTMLParser):
self.picons = []
def handle_starttag(self, tag, attrs):
if tag == "td":
if tag == 'td':
self._is_td = True
if tag == "th":
if tag == 'th':
self._is_th = True
if tag == "img":
self._current_row.append(attrs[0][1])
@@ -45,16 +46,16 @@ class PiconsParser(HTMLParser):
self._current_cell.append(data.strip())
def handle_endtag(self, tag):
if tag == "td":
if tag == 'td':
self._is_td = False
elif tag == "th":
elif tag == 'th':
self._is_th = False
if tag in ("td", "th"):
if tag in ('td', 'th'):
final_cell = self._separator.join(self._current_cell).strip()
self._current_row.append(final_cell)
self._current_cell = []
elif tag == "tr":
elif tag == 'tr':
row = self._current_row
ln = len(row)
@@ -79,10 +80,6 @@ class PiconsParser(HTMLParser):
@staticmethod
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")
@@ -108,7 +105,8 @@ class PiconsParser(HTMLParser):
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)
# log(msg)
print(msg)
@staticmethod
def format(ssid, on_id, namespace, picon_ids, s_type):

View File

@@ -43,10 +43,7 @@ class YouTube:
self._callback = callback
if self._settings.enable_yt_dl:
try:
self._yt_dl = YouTubeDL.get_instance(self._settings, callback=self._callback)
except YouTubeException:
pass # NOP
self._yt_dl = YouTubeDL.get_instance(self._settings, callback=self._callback)
@classmethod
def get_instance(cls, settings, callback=log):
@@ -164,7 +161,7 @@ class PlayListParser(HTMLParser):
ct = resp.get("contents", None)
if ct:
for d in [(d.get("title", {}).get("runs", [{}])[0].get("text", ""),
for d in [(d.get("title", {}).get("simpleText", ""),
d.get("videoId", "")) for d in flat("playlistVideoRenderer", ct)]:
self._playlist.append(d)
self._is_script = False
@@ -248,7 +245,7 @@ class YouTubeDL:
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:
if youtube_dl.version.__version__ < l_ver:
msg = "youtube-dl has new release!\nCurrent: {}. Last: {}.".format(cur_ver, l_ver)
show_notification(msg)
log(msg)
@@ -265,11 +262,8 @@ class YouTubeDL:
def get_last_release_id():
""" Getting last release id. """
url = "https://api.github.com/repos/ytdl-org/youtube-dl/releases/latest"
try:
with urlopen(url, timeout=10) as resp:
return json.loads(resp.read().decode("utf-8")).get("tag_name", "0")
except URLError as e:
log("YouTubeDLHelper error [get last release id]: {}".format(e))
with urlopen(url, timeout=10) as resp:
return json.loads(resp.read().decode("utf-8")).get("tag_name", "0")
def get_latest_release(self):
try:

143
app/ui/app_menu_bar.ui Normal file
View File

@@ -0,0 +1,143 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<menu id="app-menu">
<section>
<item>
<attribute name="label" translatable="yes">About</attribute>
<attribute name="action">app.on_about_app</attribute>
</item>
</section>
<section>
<item>
<attribute name="label" translatable="yes">Settings</attribute>
<attribute name="action">app.on_settings</attribute>
</item>
</section>
<section>
<item>
<attribute name="label" translatable="yes">Exit</attribute>
<attribute name="action">app.on_close_app</attribute>
</item>
</section>
</menu>
<menu id="menu_bar">
<submenu>
<attribute name="label" translatable="yes">File</attribute>
<section>
<submenu>
<attribute name="label" translatable="yes">Import</attribute>
<section>
<item>
<attribute name="label" translatable="yes">Bouquet</attribute>
<attribute name="action">app.on_import_bouquet</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Bouquets and services</attribute>
<attribute name="action">app.on_import_bouquets</attribute>
</item>
</section>
</submenu>
<item>
<attribute name="label" translatable="yes">New empty configuration</attribute>
<attribute name="action">app.on_new_configuration</attribute>
</item>
</section>
<section>
<item>
<attribute name="label" translatable="yes">Open</attribute>
<attribute name="action">app.on_data_open</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Save</attribute>
<attribute name="action">app.on_data_save</attribute>
</item>
</section>
<section>
<item>
<attribute name="label" translatable="yes">FTP-transfer</attribute>
<attribute name="action">app.on_download</attribute>
</item>
</section>
</submenu>
<submenu>
<attribute name="label" translatable="yes">Edit</attribute>
<section>
<item>
<attribute name="label" translatable="yes">Lock</attribute>
<attribute name="action">app.on_locked</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Hide</attribute>
<attribute name="action">app.on_hide</attribute>
</item>
</section>
</submenu>
<submenu>
<attribute name="label" translatable="yes">View</attribute>
<section>
<item>
<attribute name="label" translatable="yes">Search</attribute>
<attribute name="action">win.search</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Filter</attribute>
<attribute name="action">win.filter</attribute>
</item>
</section>
</submenu>
<submenu>
<attribute name="label" translatable="yes">Tools</attribute>
<section>
<item>
<attribute name="label" translatable="yes">Satellites editor</attribute>
<attribute name="action">app.on_satellite_editor_show</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Picons manager</attribute>
<attribute name="action">app.on_picons_manager_show</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Backups</attribute>
<attribute name="action">app.on_backup_tool_show</attribute>
</item>
</section>
<section id="telnet_section">
</section>
</submenu>
<submenu>
<attribute name="label" translatable="yes">IPTV</attribute>
<item>
<attribute name="label" translatable="yes">Add IPTV or stream service</attribute>
<attribute name="action">app.on_iptv</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Import YouTube playlist</attribute>
<attribute name="action">app.on_import_yt_list</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Import m3u</attribute>
<attribute name="action">app.on_import_m3u</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Export to m3u</attribute>
<attribute name="action">app.on_export_to_m3u</attribute>
</item>
<section>
<item>
<attribute name="label" translatable="yes">EPG configuration</attribute>
<attribute name="action">app.on_epg_list_configuration</attribute>
</item>
<item>
<attribute name="label" translatable="yes">List configuration</attribute>
<attribute name="action">app.on_iptv_list_configuration</attribute>
</item>
</section>
<section>
<item>
<attribute name="label" translatable="yes">Remove all unavailable</attribute>
<attribute name="action">app.on_remove_all_unavailable</attribute>
</item>
</section>
</submenu>
</menu>
</interface>

View File

@@ -10,7 +10,7 @@ from app.commons import run_idle
from app.settings import SettingsType
from app.ui.dialogs import show_dialog, DialogType
from app.ui.main_helper import append_text_to_tview
from .uicommons import Gtk, Gdk, UI_RESOURCES_PATH, KeyboardKey
from .uicommons import Gtk, Gdk, UI_RESOURCES_PATH, KeyboardKey, MOD_MASK
class RestoreType(Enum):
@@ -59,13 +59,14 @@ class BackupDialog:
def show(self):
self._dialog_window.show()
@run_idle
def init_data(self):
if os.path.isdir(self._backup_path):
for file in filter(lambda x: x.endswith(".zip"), os.listdir(self._backup_path)):
self._model.append((file.rstrip(".zip"), False))
try:
files = os.listdir(self._backup_path)
except FileNotFoundError as e:
self.show_info_message(str(e), Gtk.MessageType.ERROR)
else:
os.makedirs(os.path.dirname(self._backup_path), exist_ok=True)
for file in filter(lambda x: x.endswith(".zip"), files):
self._model.append((file.rstrip(".zip"), False))
def on_restore_bouquets(self, item):
self.restore(RestoreType.BOUQUETS)
@@ -128,8 +129,6 @@ class BackupDialog:
append_text_to_tview(name + "\n", self._text_view)
except FileNotFoundError as e:
self.show_info_message(str(e), Gtk.MessageType.ERROR)
else:
self._text_view.get_buffer().set_text("")
def restore(self, restore_type):
model, paths = self._main_view.get_selection().get_selected_rows()
@@ -176,7 +175,7 @@ class BackupDialog:
if not KeyboardKey.value_exist(key_code):
return
key = KeyboardKey(key_code)
ctrl = event.state & Gdk.ModifierType.CONTROL_MASK
ctrl = event.state & MOD_MASK
if key is KeyboardKey.DELETE:
self.on_remove(view)

View File

@@ -33,6 +33,12 @@ Author: Dmitriy Yefremov
<!-- interface-description Enigma2 channel and satellites list editor for GNU/Linux. -->
<!-- interface-copyright 2018-2020 Dmitriy Yefremov -->
<!-- interface-authors Dmitriy Yefremov -->
<object class="GtkImage" id="details_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">emblem-important-symbolic</property>
<property name="icon_size">1</property>
</object>
<object class="GtkListStore" id="main_list_store">
<columns>
<!-- column-name date -->
@@ -41,133 +47,89 @@ Author: Dmitriy Yefremov
<column type="gboolean"/>
</columns>
</object>
<object class="GtkMenu" id="popup_menu">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkImageMenuItem" id="restore_bouquets_popup_menu_item">
<property name="label" translatable="yes">Restore bouquets</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="use_stock">False</property>
<signal name="activate" handler="on_restore_bouquets" swapped="no"/>
<accelerator key="r" signal="activate" modifiers="Primary"/>
</object>
</child>
<child>
<object class="GtkImageMenuItem" id="restore_all_popup_menu_item">
<property name="label" translatable="yes">Restore all</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="use_stock">False</property>
<signal name="activate" handler="on_restore_all" swapped="no"/>
<accelerator key="e" signal="activate" modifiers="Primary"/>
</object>
</child>
<child>
<object class="GtkSeparatorMenuItem" id="popup_menu_separator">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
</child>
<child>
<object class="GtkImageMenuItem" id="remove_popup_menu_item">
<property name="label">gtk-remove</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="use_underline">True</property>
<property name="use_stock">True</property>
<signal name="activate" handler="on_remove" swapped="no"/>
<accelerator key="Delete" signal="activate"/>
</object>
</child>
</object>
<object class="GtkImage" id="remove_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">user-trash-symbolic</property>
<property name="icon_size">1</property>
</object>
<object class="GtkImage" id="restore_all_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">edit-select-all-symbolic</property>
<property name="icon_size">1</property>
</object>
<object class="GtkImage" id="restore_bouquets_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">document-revert-symbolic</property>
<property name="icon_size">1</property>
</object>
<object class="GtkWindow" id="dialog_window">
<property name="width_request">560</property>
<property name="height_request">320</property>
<property name="can_focus">False</property>
<property name="title" translatable="yes">Backups</property>
<property name="modal">True</property>
<property name="window_position">center-on-parent</property>
<property name="destroy_with_parent">True</property>
<property name="icon_name">document-revert</property>
<property name="gravity">center</property>
<signal name="check-resize" handler="on_resize" swapped="no"/>
<child type="titlebar">
<object class="GtkHeaderBar" id="header_bar">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="title" translatable="yes">Backups</property>
<property name="spacing">2</property>
<property name="show_close_button">True</property>
<child>
<object class="GtkBox" id="header_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">2</property>
<child>
<object class="GtkButton" id="restore_bouquets_header_button">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Restore bouquets</property>
<signal name="clicked" handler="on_restore_bouquets" swapped="no"/>
<child>
<object class="GtkImage" id="restore_bouquets_header_button_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">document-revert</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="restore_all_header_button">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Restore all</property>
<signal name="clicked" handler="on_restore_all" swapped="no"/>
<child>
<object class="GtkImage" id="restore_all_header_button_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">edit-select-all</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</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="position">2</property>
</packing>
</child>
<child>
<object class="GtkButton" id="remove_header_button">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Remove</property>
<signal name="clicked" handler="on_remove" swapped="no"/>
<child>
<object class="GtkImage" id="remove_button_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">user-trash</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
</object>
</child>
<child>
<object class="GtkCheckButton" id="info_check_button">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="tooltip_text" translatable="yes">Details</property>
<property name="draw_indicator">False</property>
<signal name="toggled" handler="on_info_button_toggled" swapped="no"/>
<child>
<object class="GtkImage" id="info_check_button_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-dialog-info</property>
</object>
</child>
<accelerator key="i" signal="clicked" modifiers="GDK_CONTROL_MASK"/>
</object>
<packing>
<property name="pack_type">end</property>
<property name="position">1</property>
</packing>
</child>
</object>
<child>
<placeholder/>
</child>
<child>
<object class="GtkBox" id="main_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_left">1</property>
<property name="margin_right">1</property>
<property name="margin_top">1</property>
<property name="margin_bottom">1</property>
<property name="orientation">vertical</property>
<property name="spacing">5</property>
<child>
<object class="GtkPaned" id="main_paned">
<property name="visible">True</property>
@@ -251,6 +213,106 @@ Author: Dmitriy Yefremov
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_left">15</property>
<property name="margin_right">15</property>
<child>
<object class="GtkButtonBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="valign">center</property>
<property name="margin_top">10</property>
<property name="margin_bottom">10</property>
<property name="layout_style">expand</property>
<child>
<object class="GtkButton" id="restore_bouquets_header_button">
<property name="label" translatable="yes">Restore bouquets</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="valign">center</property>
<property name="image">restore_bouquets_image</property>
<property name="always_show_image">True</property>
<signal name="clicked" handler="on_restore_bouquets" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="restore_all_header_button">
<property name="label" translatable="yes">Restore all</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="valign">center</property>
<property name="image">restore_all_image</property>
<property name="always_show_image">True</property>
<signal name="clicked" handler="on_restore_all" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkButton" id="remove_header_button">
<property name="label" translatable="yes">Remove</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="valign">center</property>
<property name="image">remove_image</property>
<property name="always_show_image">True</property>
<signal name="clicked" handler="on_remove" swapped="no"/>
<accelerator key="Delete" signal="clicked"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkCheckButton" id="info_check_button">
<property name="label" translatable="yes">Details</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="valign">center</property>
<property name="image">details_image</property>
<property name="always_show_image">True</property>
<property name="draw_indicator">False</property>
<signal name="toggled" handler="on_info_button_toggled" swapped="no"/>
<accelerator key="i" signal="clicked" modifiers="Primary"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack_type">end</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkInfoBar" id="info_bar">
<property name="can_focus">False</property>
@@ -301,57 +363,4 @@ Author: Dmitriy Yefremov
</object>
</child>
</object>
<object class="GtkImage" id="restore_popup_menu_item_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-revert-to-saved</property>
</object>
<object class="GtkImage" id="restore_popup_menu_item_image2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-select-all</property>
</object>
<object class="GtkMenu" id="popup_menu">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkImageMenuItem" id="restore_bouquets_popup_menu_item">
<property name="label" translatable="yes">Restore bouquets</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="image">restore_popup_menu_item_image</property>
<property name="use_stock">False</property>
<signal name="activate" handler="on_restore_bouquets" swapped="no"/>
<accelerator key="r" signal="activate" modifiers="GDK_CONTROL_MASK"/>
</object>
</child>
<child>
<object class="GtkImageMenuItem" id="restore_all_popup_menu_item">
<property name="label" translatable="yes">Restore all</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="image">restore_popup_menu_item_image2</property>
<property name="use_stock">False</property>
<signal name="activate" handler="on_restore_all" swapped="no"/>
<accelerator key="e" signal="activate" modifiers="GDK_CONTROL_MASK"/>
</object>
</child>
<child>
<object class="GtkSeparatorMenuItem" id="popup_menu_separator">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
</child>
<child>
<object class="GtkImageMenuItem" id="remove_popup_menu_item">
<property name="label">gtk-remove</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="use_underline">True</property>
<property name="use_stock">True</property>
<signal name="activate" handler="on_remove" swapped="no"/>
<accelerator key="Delete" signal="activate"/>
</object>
</child>
</object>
</interface>

40
app/ui/default_style.css Normal file
View File

@@ -0,0 +1,40 @@
* {
-GtkDialog-action-area-border: 5em;
}
entry {
min-height: 2em;
}
button {
min-height: 1.5em;
padding: 0.1em;
}
spinbutton {
min-height: 1.5em;
}
toolbutton {
padding: 0.1em;
}
spinner {
padding-left: 1em;
padding-right: 1em;
}
infobar {
min-height: 2em;
}
switch slider {
min-height: 1.5em;
min-width: 1.5em;
}
paned > separator {
background-repeat: no-repeat;
background-position: center;
background-size: 1px 24px;
}

View File

@@ -30,7 +30,7 @@ Author: Dmitriy Yefremov
<requires lib="gtk+" version="3.16"/>
<!-- interface-license-type mit -->
<!-- interface-name DemonEditor -->
<!-- interface-description Enigma2 channel and satellites list editor for GNU/Linux. -->
<!-- interface-description Enigma2 channel and satellites list editor for macOS. -->
<!-- interface-copyright 2018-2020 Dmitriy Yefremov -->
<!-- interface-authors Dmitriy Yefremov -->
<object class="GtkAboutDialog" id="about_dialog">
@@ -40,11 +40,12 @@ Author: Dmitriy Yefremov
<property name="icon_name">system-help</property>
<property name="type_hint">normal</property>
<property name="program_name">DemonEditor</property>
<property name="version">1.0.1 Beta</property>
<property name="version">1.0.0 Alpha</property>
<property name="copyright">2018-2020 Dmitriy Yefremov
</property>
<property name="comments" translatable="yes">Enigma2 channel and satellites list editor for GNU/Linux</property>
<property name="website">https://dyefremov.github.io/DemonEditor/</property>
<property name="comments" translatable="yes">Enigma2 channel and satellites list editor for MacOS.
(Experimental)</property>
<property name="website">https://github.com/DYefremov/DemonEditor/tree/experimental-mac</property>
<property name="license" translatable="yes">Это приложение распространяется без каких-либо гарантий.
Подробнее в &lt;a href="http://opensource.org/licenses/mit-license.php"&gt;The MIT License (MIT)&lt;/a&gt;.</property>
<property name="authors">Dmitriy Yefremov
@@ -65,7 +66,9 @@ Author: Dmitriy Yefremov
<child internal-child="action_area">
<object class="GtkButtonBox" id="aboutdialog_action_area">
<property name="can_focus">False</property>
<property name="layout_style">end</property>
<property name="margin_left">50</property>
<property name="margin_right">50</property>
<property name="layout_style">expand</property>
</object>
<packing>
<property name="expand">False</property>
@@ -90,32 +93,58 @@ Author: Dmitriy Yefremov
<property name="skip_taskbar_hint">True</property>
<property name="skip_pager_hint">True</property>
<property name="gravity">center</property>
<child type="action">
<object class="GtkButton" id="input_dialog_cancel_button">
<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>
<property name="always_show_image">True</property>
</object>
</child>
<child type="action">
<object class="GtkButton" id="input_dialog_ok_button">
<property name="label">gtk-ok</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
<property name="always_show_image">True</property>
<accelerator key="Return" signal="activate"/>
</object>
<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">4</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="valign">center</property>
<property name="layout_style">end</property>
<child>
<object class="GtkButton" id="input_dialog_cancel_button">
<property name="label" translatable="yes">Cancel</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="valign">center</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="input_dialog_ok_button">
<property name="label" translatable="yes">OK</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="valign">center</property>
<accelerator key="Return" signal="activate"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="input_entry">
<property name="visible">True</property>
@@ -124,7 +153,7 @@ Author: Dmitriy Yefremov
<property name="margin_right">2</property>
<property name="margin_top">2</property>
<property name="margin_bottom">2</property>
<property name="primary_icon_stock">gtk-edit</property>
<property name="primary_icon_name">document-edit-symbolic</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
<property name="secondary_icon_sensitive">False</property>
@@ -132,7 +161,7 @@ Author: Dmitriy Yefremov
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
<property name="position">0</property>
</packing>
</child>
</object>
@@ -142,7 +171,7 @@ Author: Dmitriy Yefremov
<action-widget response="ok">input_dialog_ok_button</action-widget>
</action-widgets>
</object>
<object class="GtkDialog" id="wait_dialog">
<object class="GtkWindow" id="wait_dialog">
<property name="can_focus">False</property>
<property name="resizable">False</property>
<property name="modal">True</property>
@@ -152,70 +181,50 @@ Author: Dmitriy Yefremov
<property name="skip_taskbar_hint">True</property>
<property name="skip_pager_hint">True</property>
<property name="decorated">False</property>
<child>
<property name="gravity">center</property>
<child type="titlebar">
<placeholder/>
</child>
<child internal-child="vbox">
<object class="GtkBox" id="wait_dialog_vbox">
<property name="width_request">120</property>
<child>
<object class="GtkBox" id="wait_dialog_box">
<property name="width_request">100</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_top">5</property>
<property name="margin_bottom">5</property>
<property name="orientation">vertical</property>
<child internal-child="action_area">
<object class="GtkButtonBox" id="dialog-action_area4">
<child>
<object class="GtkSpinner" id="spinner">
<property name="width_request">150</property>
<property name="height_request">45</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="opacity">0</property>
<property name="layout_style">end</property>
<property name="active">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkBox" id="box4">
<object class="GtkLabel" id="wait_dialog_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkSpinner" id="spinner">
<property name="width_request">150</property>
<property name="height_request">45</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="active">True</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="wait_dialog_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_left">10</property>
<property name="margin_right">10</property>
<property name="label" translatable="yes">Loading data...</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<property name="margin_left">10</property>
<property name="margin_right">10</property>
<property name="label" translatable="yes">Loading data...</property>
</object>
<packing>
<property name="expand">True</property>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<style>
<class name="app-notification"/>
</style>
</object>
</child>
<style>
<class name="app-notification"/>
</style>
</object>
</interface>

View File

@@ -1,8 +1,7 @@
""" Common module for showing dialogs """
import locale
import gettext
from enum import Enum
from functools import lru_cache
from pathlib import Path
from app.commons import run_idle
from .uicommons import Gtk, UI_RESOURCES_PATH, TEXT_DOMAIN, IS_GNOME_SESSION
@@ -73,13 +72,12 @@ class WaitDialog:
self._dialog.destroy()
def show_dialog(dialog_type, transient, text=None, settings=None, action_type=None, file_filter=None, buttons=None,
title=None):
""" Shows dialogs by name. """
def show_dialog(dialog_type: DialogType, transient, text=None, settings=None, action_type=None, file_filter=None):
""" Shows dialogs by name """
if dialog_type in (DialogType.INFO, DialogType.ERROR):
return get_message_dialog(transient, dialog_type, Gtk.ButtonsType.OK, text)
elif dialog_type is DialogType.CHOOSER and settings:
return get_file_chooser_dialog(transient, text, settings, action_type, file_filter, buttons, title)
return get_file_chooser_dialog(transient, text, settings, action_type, file_filter)
elif dialog_type is DialogType.INPUT:
return get_input_dialog(transient, text)
elif dialog_type is DialogType.QUESTION:
@@ -89,7 +87,7 @@ def show_dialog(dialog_type, transient, text=None, settings=None, action_type=No
return get_about_dialog(transient)
def get_chooser_dialog(transient, settings, name, patterns, title=None):
def get_chooser_dialog(transient, settings, name, patterns):
file_filter = Gtk.FileFilter()
file_filter.set_name(name)
for p in patterns:
@@ -99,30 +97,30 @@ def get_chooser_dialog(transient, settings, name, patterns, title=None):
transient=transient,
settings=settings,
action_type=Gtk.FileChooserAction.OPEN,
file_filter=file_filter,
title=title)
file_filter=file_filter)
def get_file_chooser_dialog(transient, text, settings, action_type, file_filter, buttons=None, title=None):
text = get_message(text) if text else ""
action_type = Gtk.FileChooserAction.SELECT_FOLDER if action_type is None else action_type
buttons = buttons or (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OPEN, Gtk.ResponseType.OK)
dialog = Gtk.FileChooserDialog(text, transient, action_type, buttons, use_header_bar=IS_GNOME_SESSION)
dialog.set_title(get_message(title) if title else "")
def get_file_chooser_dialog(transient, text, settings, action_type, file_filter):
dialog = Gtk.FileChooserNative()
dialog.set_title(get_message(text) if text else "")
dialog.set_transient_for(transient)
dialog.set_action(action_type if action_type is not None else Gtk.FileChooserAction.SELECT_FOLDER)
dialog.set_create_folders(False)
dialog.set_modal(True)
if file_filter is not None:
dialog.add_filter(file_filter)
dialog.set_current_folder(settings.data_local_path)
path = settings.data_local_path
dialog.set_current_folder(path)
response = dialog.run()
if response not in (Gtk.ResponseType.CANCEL, Gtk.ResponseType.DELETE_EVENT):
path = Path(dialog.get_filename() or dialog.get_current_folder())
if path.is_dir():
response = "{}/".format(path.resolve())
elif path.is_file():
response = str(path.resolve())
if response == Gtk.ResponseType.ACCEPT:
if dialog.get_filename():
path = dialog.get_filename()
if action_type is not Gtk.FileChooserAction.OPEN:
path = path + "/"
response = path
dialog.destroy()
return response
@@ -176,7 +174,7 @@ def get_dialog_from_xml(dialog_type, transient, use_header=0, title=""):
def get_message(message):
""" returns translated message """
return locale.dgettext(TEXT_DOMAIN, message)
return gettext.dgettext(TEXT_DOMAIN, message)
@lru_cache(maxsize=5)

479
app/ui/download_dialog.glade Normal file → Executable file
View File

@@ -3,7 +3,7 @@
The MIT License (MIT)
Copyright (c) 2018 Dmitriy Yefremov
Copyright (c) 2018-2020 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
@@ -30,12 +30,25 @@ Author: Dmitriy Yefremov
<requires lib="gtk+" version="3.16"/>
<!-- interface-license-type mit -->
<!-- interface-name DemonEditor -->
<!-- interface-description Enigma2 channel and satellites list editor for GNU/Linux. -->
<!-- interface-copyright 2018 Dmitriy Yefremov -->
<!-- interface-description Enigma2 channel and satellites list editor for macOS. -->
<!-- interface-copyright 2018-2020 Dmitriy Yefremov -->
<!-- interface-authors Dmitriy Yefremov -->
<object class="GtkImage" id="download_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">network-receive-symbolic</property>
<property name="icon_size">1</property>
</object>
<object class="GtkImage" id="send_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">network-transmit-symbolic</property>
<property name="icon_size">1</property>
</object>
<object class="GtkWindow" id="download_dialog_window">
<property name="width_request">500</property>
<property name="can_focus">False</property>
<property name="title" translatable="yes">FTP-transfer</property>
<property name="resizable">False</property>
<property name="modal">True</property>
<property name="window_position">center-on-parent</property>
@@ -43,235 +56,30 @@ Author: Dmitriy Yefremov
<property name="skip_taskbar_hint">True</property>
<property name="skip_pager_hint">True</property>
<property name="gravity">center</property>
<child type="titlebar">
<object class="GtkHeaderBar" id="header_bar">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="title" translatable="yes">FTP-transfer</property>
<property name="spacing">5</property>
<property name="show_close_button">True</property>
<child>
<object class="GtkBox" id="header_left_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">2</property>
<child>
<object class="GtkButton" id="receive_button">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Receive</property>
<signal name="clicked" handler="on_receive" swapped="no"/>
<child>
<object class="GtkImage" id="receive_button_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-goto-bottom</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="send_button">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Send</property>
<signal name="clicked" handler="on_send" swapped="no"/>
<child>
<object class="GtkImage" id="send_button_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-goto-top</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
<child>
<object class="GtkButton" id="options_button">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Options</property>
<signal name="clicked" handler="on_settings" swapped="no"/>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-properties</property>
</object>
</child>
</object>
<packing>
<property name="pack_type">end</property>
<property name="position">1</property>
</packing>
</child>
</object>
<child>
<placeholder/>
</child>
<child>
<object class="GtkBox" id="main_dialog_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_left">1</property>
<property name="margin_right">1</property>
<property name="margin_bottom">1</property>
<property name="orientation">vertical</property>
<property name="spacing">2</property>
<child>
<object class="GtkBox" id="selection_data_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">center</property>
<property name="margin_top">10</property>
<property name="margin_bottom">5</property>
<property name="spacing">5</property>
<child>
<object class="GtkLabel" id="label10">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkRadioButton" id="all_radio_button">
<property name="label" translatable="yes">All</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="draw_indicator">True</property>
<property name="group">satellites_radio_button</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkRadioButton" id="bouquets_radio_button">
<property name="label" translatable="yes">Bouquets</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="draw_indicator">True</property>
<property name="group">satellites_radio_button</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkRadioButton" id="satellites_radio_button">
<property name="label" translatable="yes">Satellites</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="draw_indicator">True</property>
<property name="group">all_radio_button</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
<child>
<object class="GtkRadioButton" id="webtv_radio_button">
<property name="label" translatable="yes">WebTV</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="draw_indicator">True</property>
<property name="group">all_radio_button</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">4</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</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">5</property>
<property name="margin_bottom">5</property>
<property name="spacing">5</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Profile:</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkComboBoxText" id="profile_combo_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="focus_on_click">False</property>
<property name="active">0</property>
<property name="has_frame">False</property>
<signal name="changed" handler="on_profile_changed" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkFrame" id="main_settings_box_frame">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_left">5</property>
<property name="margin_right">5</property>
<property name="margin_left">10</property>
<property name="margin_right">10</property>
<property name="margin_top">10</property>
<property name="margin_bottom">5</property>
<property name="label_xalign">0.019999999552965164</property>
<property name="shadow_type">in</property>
<child>
<object class="GtkBox" id="main_settings_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_left">5</property>
<property name="margin_right">5</property>
<property name="margin_left">10</property>
<property name="margin_right">10</property>
<property name="margin_top">5</property>
<property name="margin_bottom">5</property>
<property name="orientation">vertical</property>
@@ -427,8 +235,8 @@ Author: Dmitriy Yefremov
<object class="GtkFrame" id="settings_frame">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_left">5</property>
<property name="margin_right">5</property>
<property name="margin_left">10</property>
<property name="margin_right">10</property>
<property name="margin_top">5</property>
<property name="margin_bottom">5</property>
<property name="label_xalign">0.019999999552965164</property>
@@ -437,8 +245,9 @@ Author: Dmitriy Yefremov
<object class="GtkGrid" id="settings_grid">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_left">5</property>
<property name="margin_right">5</property>
<property name="margin_left">10</property>
<property name="margin_right">10</property>
<property name="margin_top">5</property>
<property name="margin_bottom">5</property>
<property name="row_spacing">2</property>
<property name="column_spacing">2</property>
@@ -618,6 +427,229 @@ Author: Dmitriy Yefremov
<property name="position">3</property>
</packing>
</child>
<child>
<object class="GtkFrame">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_left">10</property>
<property name="margin_right">10</property>
<property name="label_xalign">0</property>
<property name="shadow_type">in</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkBox" id="selection_data_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">center</property>
<property name="margin_top">10</property>
<property name="margin_bottom">5</property>
<property name="spacing">5</property>
<child>
<object class="GtkLabel" id="label10">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkRadioButton" id="all_radio_button">
<property name="label" translatable="yes">All</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="draw_indicator">True</property>
<property name="group">satellites_radio_button</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkRadioButton" id="bouquets_radio_button">
<property name="label" translatable="yes">Bouquets</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="draw_indicator">True</property>
<property name="group">satellites_radio_button</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkRadioButton" id="satellites_radio_button">
<property name="label" translatable="yes">Satellites</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="draw_indicator">True</property>
<property name="group">all_radio_button</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
<child>
<object class="GtkRadioButton" id="webtv_radio_button">
<property name="label" translatable="yes">WebTV</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="draw_indicator">True</property>
<property name="group">all_radio_button</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">4</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</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">5</property>
<property name="margin_bottom">5</property>
<property name="spacing">5</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Profile:</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkComboBoxText" id="profile_combo_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="focus_on_click">False</property>
<property name="active">0</property>
<property name="has_frame">False</property>
<signal name="changed" handler="on_profile_changed" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkButton" id="options_button">
<property name="label" translatable="yes">Options</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Options</property>
<property name="valign">center</property>
<signal name="clicked" handler="on_settings" swapped="no"/>
</object>
<packing>
<property name="expand">True</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">1</property>
</packing>
</child>
</object>
</child>
<child type="label_item">
<placeholder/>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">4</property>
</packing>
</child>
<child>
<object class="GtkButtonBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="valign">center</property>
<property name="margin_left">20</property>
<property name="margin_right">20</property>
<property name="margin_top">10</property>
<property name="margin_bottom">10</property>
<property name="homogeneous">True</property>
<property name="layout_style">expand</property>
<child>
<object class="GtkButton" id="receive_button">
<property name="label" translatable="yes">Receive</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Receive</property>
<property name="valign">center</property>
<property name="image">download_image</property>
<property name="always_show_image">True</property>
<signal name="clicked" handler="on_receive" swapped="no"/>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="send_button">
<property name="label" translatable="yes">Send</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Send</property>
<property name="valign">center</property>
<property name="image">send_image</property>
<property name="always_show_image">True</property>
<signal name="clicked" handler="on_send" swapped="no"/>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">6</property>
</packing>
</child>
<child>
<object class="GtkExpander" id="expander">
<property name="visible">True</property>
@@ -654,7 +686,7 @@ Author: Dmitriy Yefremov
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">4</property>
<property name="position">7</property>
</packing>
</child>
<child>
@@ -710,12 +742,9 @@ Author: Dmitriy Yefremov
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">5</property>
<property name="position">8</property>
</packing>
</child>
<child>
<placeholder/>
</child>
</object>
</child>
</object>

View File

@@ -33,6 +33,18 @@ Author: Dmitriy Yefremov
<!-- interface-description Enigma2 channel and satellites list editor for GNU/Linux. -->
<!-- interface-copyright 2018-2020 Dmitriy Yefremov -->
<!-- interface-authors Dmitriy Yefremov -->
<object class="GtkImage" id="apply_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">document-save-symbolic</property>
<property name="icon_size">1</property>
</object>
<object class="GtkImage" id="auto_config_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">edit-select-all-symbolic</property>
<property name="icon_size">1</property>
</object>
<object class="GtkListStore" id="bouquet_list_store">
<columns>
<!-- column-name num -->
@@ -75,10 +87,16 @@ Author: Dmitriy Yefremov
<property name="image">copy_image</property>
<property name="use_stock">False</property>
<signal name="activate" handler="on_copy_ref" swapped="no"/>
<accelerator key="c" signal="activate" modifiers="GDK_CONTROL_MASK"/>
<accelerator key="c" signal="activate" modifiers="Primary"/>
</object>
</child>
</object>
<object class="GtkImage" id="filter_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">edit-find-replace-symbolic</property>
<property name="icon_size">1</property>
</object>
<object class="GtkImage" id="insert_link_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
@@ -100,7 +118,7 @@ Author: Dmitriy Yefremov
<property name="image">insert_link_image</property>
<property name="use_stock">False</property>
<signal name="activate" handler="on_assign_ref" swapped="no"/>
<accelerator key="v" signal="activate" modifiers="GDK_CONTROL_MASK"/>
<accelerator key="v" signal="activate" modifiers="Primary"/>
</object>
</child>
<child>
@@ -130,6 +148,12 @@ Author: Dmitriy Yefremov
</object>
</child>
</object>
<object class="GtkImage" id="save_to_xml_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">document-save-as-symbolic</property>
<property name="icon_size">1</property>
</object>
<object class="GtkListStore" id="services_list_store">
<columns>
<!-- column-name service -->
@@ -312,7 +336,7 @@ Author: Dmitriy Yefremov
<object class="GtkEntry" id="url_to_xml_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="primary_icon_stock">gtk-connect</property>
<property name="primary_icon_name">network-transmit-receive-symbolic</property>
<property name="primary_icon_activatable">False</property>
</object>
<packing>
@@ -412,8 +436,8 @@ Author: Dmitriy Yefremov
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="text" translatable="yes">/data/epg/</property>
<property name="primary_icon_stock">gtk-edit</property>
<property name="secondary_icon_stock">gtk-directory</property>
<property name="primary_icon_name">document-edit-symbolic</property>
<property name="secondary_icon_name">folder-open-symbolic</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_tooltip_text" translatable="yes">Select</property>
<signal name="icon-press" handler="on_field_icon_press" swapped="no"/>
@@ -442,7 +466,7 @@ Author: Dmitriy Yefremov
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="text" translatable="yes">/etc/enigma2/</property>
<property name="primary_icon_stock">gtk-edit</property>
<property name="primary_icon_name">document-edit-symbolic</property>
<property name="primary_icon_activatable">False</property>
</object>
<packing>
@@ -559,58 +583,104 @@ Author: Dmitriy Yefremov
</object>
</child>
</object>
<object class="GtkImage" id="update_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">emblem-synchronizing-symbolic</property>
<property name="icon_size">1</property>
</object>
<object class="GtkWindow" id="epg_dialog_window">
<property name="width_request">480</property>
<property name="height_request">320</property>
<property name="can_focus">False</property>
<property name="title" translatable="yes">EPG</property>
<property name="modal">True</property>
<property name="window_position">center-on-parent</property>
<property name="default_width">480</property>
<property name="default_height">240</property>
<property name="default_height">320</property>
<property name="destroy_with_parent">True</property>
<property name="icon_name">gtk-index</property>
<property name="skip_taskbar_hint">True</property>
<property name="skip_pager_hint">True</property>
<property name="gravity">center</property>
<signal name="check-resize" handler="on_resize" swapped="no"/>
<signal name="delete-event" handler="on_close_dialog" swapped="no"/>
<child type="titlebar">
<object class="GtkHeaderBar" id="header_bar">
<child>
<placeholder/>
</child>
<child>
<object class="GtkBox" id="main_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="title" translatable="yes">EPG</property>
<property name="subtitle" translatable="yes">List configuration</property>
<property name="spacing">2</property>
<property name="show_close_button">True</property>
<property name="margin_left">1</property>
<property name="margin_right">1</property>
<property name="margin_bottom">1</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkBox" id="left_header_box">
<object class="GtkBox" id="main_actions_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">2</property>
<property name="margin_left">15</property>
<property name="margin_right">15</property>
<property name="margin_top">10</property>
<property name="margin_bottom">10</property>
<property name="spacing">10</property>
<child>
<object class="GtkButton" id="apply_button">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Apply</property>
<signal name="clicked" handler="on_apply" swapped="no"/>
<child>
<object class="GtkImage" id="apply_button_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-apply</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkSeparator">
<object class="GtkButtonBox" id="left_action_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="layout_style">expand</property>
<child>
<object class="GtkButton" id="apply_button">
<property name="label" translatable="yes">Apply</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Apply</property>
<property name="image">apply_image</property>
<property name="always_show_image">True</property>
<signal name="clicked" handler="on_apply" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="update_button">
<property name="label" translatable="yes">Update</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Update</property>
<property name="image">update_image</property>
<property name="always_show_image">True</property>
<signal name="clicked" handler="on_update" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkToggleButton" id="filter_button">
<property name="label" translatable="yes">Filter</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Filter</property>
<property name="image">filter_image</property>
<property name="always_show_image">True</property>
<signal name="toggled" handler="on_filter_toggled" swapped="no"/>
<accelerator key="f" signal="clicked" modifiers="GDK_SHIFT_MASK | GDK_CONTROL_MASK"/>
</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>
@@ -618,20 +688,11 @@ Author: Dmitriy Yefremov
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkButton" id="update_button">
<child type="center">
<object class="GtkLabel" id="list_label">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Update</property>
<signal name="clicked" handler="on_update" swapped="no"/>
<child>
<object class="GtkImage" id="update_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-refresh</property>
</object>
</child>
<property name="can_focus">False</property>
<property name="label" translatable="yes">List configuration</property>
</object>
<packing>
<property name="expand">False</property>
@@ -640,111 +701,106 @@ Author: Dmitriy Yefremov
</packing>
</child>
<child>
<object class="GtkToggleButton" id="filter_button">
<object class="GtkButtonBox" id="right_action_box">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Filter</property>
<signal name="toggled" handler="on_filter_toggled" swapped="no"/>
<property name="can_focus">False</property>
<property name="layout_style">expand</property>
<child>
<object class="GtkImage" id="filter_button_image">
<object class="GtkButton" id="auto_config_button">
<property name="label" translatable="yes">Auto</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-spell-check</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Auto configuration by service names.</property>
<property name="image">auto_config_image</property>
<property name="always_show_image">True</property>
<signal name="clicked" handler="on_auto_configuration" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<accelerator key="f" signal="clicked" modifiers="GDK_SHIFT_MASK | GDK_CONTROL_MASK"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
</object>
</child>
<child>
<object class="GtkBox" id="right_header_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">2</property>
<child>
<object class="GtkButton" id="auto_config_button">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Auto configuration by service names.</property>
<signal name="clicked" handler="on_auto_configuration" swapped="no"/>
<child>
<object class="GtkImage" id="auto_config_button_image">
<object class="GtkButton" id="save_to_xml_button">
<property name="label" translatable="yes">Save</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-find-and-replace</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Save list to xml.</property>
<property name="image">save_to_xml_image</property>
<property name="always_show_image">True</property>
<signal name="clicked" handler="on_save_to_xml" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkMenuButton" id="options_menu_button">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="direction">none</property>
<property name="popover">options_popover</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">2</property>
<child>
<object class="GtkImage" id="options_button_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Options</property>
<property name="icon_name">applications-system-symbolic</property>
<property name="icon_size">1</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Options</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</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="pack_type">end</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="save_to_xml_button">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Save list to xml.</property>
<signal name="clicked" handler="on_save_to_xml" swapped="no"/>
<child>
<object class="GtkImage" id="save_to_xml_button_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-save-as</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkMenuButton" id="options_menu_button">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="direction">none</property>
<property name="popover">options_popover</property>
<child>
<object class="GtkImage" id="options_button_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Options</property>
<property name="stock">gtk-properties</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
</object>
<packing>
<property name="pack_type">end</property>
<property name="position">1</property>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
</object>
</child>
<child>
<object class="GtkBox" id="main_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkSearchBar" id="filter_bar">
<property name="visible">True</property>
@@ -753,7 +809,7 @@ Author: Dmitriy Yefremov
<object class="GtkSearchEntry" id="filter_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="primary_icon_name">tools-check-spelling</property>
<property name="primary_icon_name">edit-find-replace-symbolic</property>
<property name="primary_icon_activatable">False</property>
<property name="primary_icon_sensitive">False</property>
<signal name="search-changed" handler="on_filter_changed" swapped="no"/>
@@ -862,13 +918,14 @@ Author: Dmitriy Yefremov
<property name="height_request">24</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_left">2</property>
<property name="margin_left">5</property>
<property name="spacing">2</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-properties</property>
<property name="icon_name">document-properties-symbolic</property>
<property name="icon_size">1</property>
</object>
<packing>
<property name="expand">False</property>
@@ -890,6 +947,7 @@ Author: Dmitriy Yefremov
</child>
<child>
<object class="GtkBox" id="source_info_box">
<property name="height_request">26</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">center</property>
@@ -1143,16 +1201,17 @@ Author: Dmitriy Yefremov
</child>
<child>
<object class="GtkBox" id="bouquet_info_bar_box">
<property name="height_request">24</property>
<property name="height_request">26</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_left">2</property>
<property name="margin_left">5</property>
<property name="spacing">2</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-properties</property>
<property name="icon_name">document-properties-symbolic</property>
<property name="icon_size">1</property>
</object>
<packing>
<property name="expand">False</property>
@@ -1189,7 +1248,9 @@ Author: Dmitriy Yefremov
<object class="GtkImage">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_left">2</property>
<property name="stock">gtk-index</property>
<property name="icon_size">1</property>
</object>
<packing>
<property name="expand">False</property>

View File

@@ -15,7 +15,7 @@ from app.eparser.ecommons import BouquetService, BqServiceType
from app.tools.epg import EPG, ChannelsParser
from app.ui.dialogs import get_message, show_dialog, DialogType
from .main_helper import on_popup_menu, update_entry_data
from .uicommons import Gtk, Gdk, UI_RESOURCES_PATH, TEXT_DOMAIN, Column, EPG_ICON, KeyboardKey
from .uicommons import Gtk, Gdk, UI_RESOURCES_PATH, TEXT_DOMAIN, Column, EPG_ICON, KeyboardKey, MOD_MASK
class RefsSource(Enum):
@@ -279,7 +279,7 @@ class EpgDialog:
if not KeyboardKey.value_exist(key_code):
return
key = KeyboardKey(key_code)
ctrl = event.state & Gdk.ModifierType.CONTROL_MASK
ctrl = event.state & MOD_MASK
if ctrl and key is KeyboardKey.C:
self.on_copy_ref()

View File

@@ -26,13 +26,25 @@ THE SOFTWARE.
Author: Dmitriy Yefremov
-->
<interface>
<interface domain="demon-editor">
<requires lib="gtk+" version="3.16"/>
<!-- interface-css-provider-path style.css -->
<!-- interface-license-type mit -->
<!-- interface-name DemonEditor -->
<!-- interface-description Enigma2 channel and satellites list editor for GNU/Linux. -->
<!-- interface-description Enigma2 channel and satellites list editor for macOS. -->
<!-- interface-copyright 2018-2020 Dmitriy Yefremov -->
<!-- interface-authors Dmitriy Yefremov -->
<object class="GtkImage" id="details_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">emblem-important-symbolic</property>
</object>
<object class="GtkImage" id="import_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">document-revert-symbolic-rtl</property>
<property name="icon_size">1</property>
</object>
<object class="GtkListStore" id="main_list_store">
<columns>
<!-- column-name name -->
@@ -82,6 +94,7 @@ Author: Dmitriy Yefremov
</object>
<object class="GtkWindow" id="dialog_window">
<property name="can_focus">False</property>
<property name="title" translatable="yes">Import</property>
<property name="modal">True</property>
<property name="window_position">center-on-parent</property>
<property name="default_width">480</property>
@@ -90,53 +103,8 @@ Author: Dmitriy Yefremov
<property name="type_hint">dialog</property>
<property name="gravity">center</property>
<signal name="check-resize" handler="on_resize" swapped="no"/>
<child type="titlebar">
<object class="GtkHeaderBar" id="header_bar">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="title" translatable="yes">Import</property>
<property name="subtitle" translatable="yes">Bouquets and services</property>
<property name="spacing">2</property>
<property name="show_close_button">True</property>
<child>
<object class="GtkButton" id="import_button">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Import</property>
<signal name="clicked" handler="on_import" swapped="no"/>
<child>
<object class="GtkImage" id="import_button_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-revert-to-saved</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkCheckButton" id="info_check_button">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="tooltip_text" translatable="yes">Details</property>
<property name="draw_indicator">False</property>
<signal name="toggled" handler="on_info_button_toggled" swapped="no"/>
<child>
<object class="GtkImage" id="info_check_button_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-dialog-info</property>
</object>
</child>
<accelerator key="i" signal="clicked" modifiers="GDK_CONTROL_MASK"/>
</object>
<packing>
<property name="pack_type">end</property>
<property name="position">1</property>
</packing>
</child>
</object>
<child>
<placeholder/>
</child>
<child>
<object class="GtkBox" id="main_box">
@@ -161,8 +129,8 @@ Author: Dmitriy Yefremov
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_top">2</property>
<property name="margin_bottom">2</property>
<property name="margin_top">5</property>
<property name="margin_bottom">5</property>
<property name="label" translatable="yes">Bouquets</property>
</object>
<packing>
@@ -260,8 +228,8 @@ Author: Dmitriy Yefremov
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_top">2</property>
<property name="margin_bottom">2</property>
<property name="margin_top">5</property>
<property name="margin_bottom">5</property>
<property name="label" translatable="yes">Bouquet details</property>
</object>
<packing>
@@ -337,6 +305,62 @@ Author: Dmitriy Yefremov
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButtonBox" id="actions_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="valign">center</property>
<property name="margin_left">15</property>
<property name="margin_right">15</property>
<property name="margin_top">5</property>
<property name="margin_bottom">5</property>
<property name="layout_style">start</property>
<child>
<object class="GtkButton" id="import_button">
<property name="label" translatable="yes">Import</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Bouquets and services</property>
<property name="valign">center</property>
<property name="image">import_image</property>
<property name="always_show_image">True</property>
<signal name="clicked" handler="on_import" swapped="no"/>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkCheckButton" id="info_check_button">
<property name="label" translatable="yes">Details</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="tooltip_text" translatable="yes">Details</property>
<property name="valign">center</property>
<property name="image">details_image</property>
<property name="always_show_image">True</property>
<property name="draw_indicator">False</property>
<signal name="toggled" handler="on_info_button_toggled" swapped="no"/>
<accelerator key="i" signal="clicked"/>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
<property name="secondary">True</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkInfoBar" id="info_bar">
<property name="can_focus">False</property>
@@ -382,7 +406,7 @@ Author: Dmitriy Yefremov
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
<property name="position">2</property>
</packing>
</child>
</object>

View File

@@ -1,7 +1,7 @@
from contextlib import suppress
from pathlib import Path
from app.commons import run_idle, log
from app.commons import run_idle
from app.eparser import get_bouquets, get_services
from app.eparser.ecommons import BqType, BqServiceType, Bouquet
from app.eparser.enigma.bouquets import get_bouquet
@@ -21,7 +21,7 @@ def import_bouquet(transient, model, path, settings, services, appender, file_pa
if profile is SettingsType.ENIGMA_2:
pattern = ".{}".format(bq_type.value)
f_pattern = "userbouquet.*{}".format(pattern)
f_pattern = "*" + pattern if settings.is_darwin else "userbouquet.*{}".format(pattern)
elif profile is SettingsType.NEUTRINO_MP:
pattern = "webtv.xml" if bq_type is BqType.WEBTV else "bouquets.xml"
f_pattern = "bouquets.xml"
@@ -34,11 +34,15 @@ def import_bouquet(transient, model, path, settings, services, appender, file_pa
if file_path == Gtk.ResponseType.CANCEL:
return
if not str(file_path).endswith(pattern):
if not file_path.endswith(pattern):
show_dialog(DialogType.ERROR, transient, text="No bouquet file is selected!")
return
if profile is SettingsType.ENIGMA_2:
if settings.is_darwin and file_path.rfind("userbouquet.") < 0:
show_dialog(DialogType.ERROR, transient, text="No bouquet file is selected!")
return
bq = get_enigma2_bouquet(file_path)
imported = list(filter(lambda x: x.data in services or x.type is BqServiceType.IPTV, bq.services))
@@ -119,7 +123,6 @@ class ImportDialog:
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:
@@ -130,7 +133,6 @@ class ImportDialog:
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 on_import(self, item):
@@ -141,17 +143,9 @@ class ImportDialog:
if not self._bouquets or show_dialog(DialogType.QUESTION, self._dialog_window) == Gtk.ResponseType.CANCEL:
return
self.import_data()
@run_idle
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]:
@@ -161,16 +155,19 @@ class ImportDialog:
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()

File diff suppressed because it is too large Load Diff

View File

@@ -586,7 +586,8 @@ class YtListImportDialog:
builder.set_translation_domain(TEXT_DOMAIN)
builder.add_objects_from_string(get_dialogs_string(_UI_PATH).format(use_header=IS_GNOME_SESSION),
("yt_import_dialog_window", "yt_liststore", "yt_quality_liststore",
"yt_popup_menu", "remove_selection_image"))
"yt_popup_menu", "remove_selection_image", "yt_receive_image",
"yt_import_image"))
builder.connect_signals(handlers)
self._dialog = builder.get_object("yt_import_dialog_window")

View File

@@ -4,7 +4,6 @@ from contextlib import suppress
from datetime import datetime
from functools import lru_cache
from itertools import chain
from urllib.parse import urlparse, unquote
from gi.repository import GLib, Gio
@@ -60,110 +59,108 @@ class Application(Gtk.Application):
"fav_epg_configuration_popup_item")
_BOUQUET_ELEMENTS = ("bouquets_new_popup_item", "bouquets_edit_popup_item", "bouquets_cut_popup_item",
"bouquets_copy_popup_item", "bouquets_paste_popup_item", "new_header_button",
"bouquet_import_popup_item")
"bouquets_copy_popup_item", "bouquets_paste_popup_item", "bouquet_import_popup_item",
"add_bouquet_tool_button")
_COMMONS_ELEMENTS = ("bouquets_remove_popup_item", "fav_remove_popup_item", "import_bq_menu_button")
_COMMONS_ELEMENTS = ("bouquets_remove_popup_item", "fav_remove_popup_item")
_FAV_ENIGMA_ELEMENTS = ("fav_insert_marker_popup_item", "fav_epg_configuration_popup_item",
"epg_configuration_header_button")
_FAV_ENIGMA_ELEMENTS = ("fav_insert_marker_popup_item", "fav_epg_configuration_popup_item")
_FAV_IPTV_ELEMENTS = ("fav_iptv_popup_item", "import_m3u_header_button", "export_to_m3u_header_button",
"epg_configuration_header_button")
_FAV_IPTV_ELEMENTS = ("fav_iptv_popup_item",)
_LOCK_HIDE_ELEMENTS = ("locked_tool_button", "hide_tool_button")
_LOCK_HIDE_ELEMENTS = ()
def __init__(self, **kwargs):
super().__init__(flags=Gio.ApplicationFlags.HANDLES_COMMAND_LINE, **kwargs)
# Adding command line options
self.add_main_option("log", ord("l"), GLib.OptionFlags.NONE, GLib.OptionArg.NONE, "", None)
self.add_main_option("record", ord("r"), GLib.OptionFlags.NONE, GLib.OptionArg.NONE, "", None)
self.add_main_option("telnet", ord("t"), GLib.OptionFlags.NONE, GLib.OptionArg.STRING, "", None)
self.add_main_option("debug", ord("d"), GLib.OptionFlags.NONE, GLib.OptionArg.STRING, "", None)
handlers = {"on_close_app": self.on_close_app,
"on_resize": self.on_resize,
"on_about_app": self.on_about_app,
"on_settings": self.on_settings,
"on_profile_changed": self.on_profile_changed,
"on_new_configuration": self.on_new_configuration,
"on_tree_view_key_press": self.on_tree_view_key_press,
"on_tree_view_key_release": self.on_tree_view_key_release,
"on_bouquets_selection": self.on_bouquets_selection,
"on_satellite_editor_show": self.on_satellite_editor_show,
"on_services_selection": self.on_services_selection,
"on_fav_cut": self.on_fav_cut,
"on_bouquets_cut": self.on_bouquets_cut,
"on_services_copy": self.on_services_copy,
"on_fav_copy": self.on_fav_copy,
"on_bouquets_copy": self.on_bouquets_copy,
"on_fav_paste": self.on_fav_paste,
"on_bouquets_paste": self.on_bouquets_paste,
"on_rename_for_bouquet": self.on_rename_for_bouquet,
"on_set_default_name_for_bouquet": self.on_set_default_name_for_bouquet,
"on_services_add_new": self.on_services_add_new,
"on_delete": self.on_delete,
"on_edit": self.on_edit,
"on_to_fav_copy": self.on_to_fav_copy,
"on_to_fav_end_copy": self.on_to_fav_end_copy,
"on_fav_sort": self.on_fav_sort,
"on_fav_view_query_tooltip": self.on_fav_view_query_tooltip,
"on_services_view_query_tooltip": self.on_services_view_query_tooltip,
"on_view_drag_begin": self.on_view_drag_begin,
"on_view_drag_end": self.on_view_drag_end,
"on_view_drag_data_get": self.on_view_drag_data_get,
"on_services_view_drag_drop": self.on_services_view_drag_drop,
"on_services_view_drag_data_received": self.on_services_view_drag_data_received,
"on_view_drag_data_received": self.on_view_drag_data_received,
"on_bq_view_drag_data_received": self.on_bq_view_drag_data_received,
"on_view_press": self.on_view_press,
"on_view_release": self.on_view_release,
"on_view_popup_menu": self.on_view_popup_menu,
"on_view_focus": self.on_view_focus,
"on_model_changed": self.on_model_changed,
"on_import_yt_list": self.on_import_yt_list,
"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,
"on_insert_marker": self.on_insert_marker,
"on_insert_space": self.on_insert_space,
"on_fav_press": self.on_fav_press,
"on_locate_in_services": self.on_locate_in_services,
"on_picons_manager_show": self.on_picons_manager_show,
"on_filter_changed": self.on_filter_changed,
"on_assign_picon": self.on_assign_picon,
"on_remove_picon": self.on_remove_picon,
"on_reference_picon": self.on_reference_picon,
"on_remove_unused_picons": self.on_remove_unused_picons,
"on_search_down": self.on_search_down,
"on_search_up": self.on_search_up,
"on_search": self.on_search,
"on_iptv": self.on_iptv,
"on_epg_list_configuration": self.on_epg_list_configuration,
"on_iptv_list_configuration": self.on_iptv_list_configuration,
"on_play_stream": self.on_play_stream,
"on_watch": self.on_watch,
"on_player_play": self.on_player_play,
"on_player_stop": self.on_player_stop,
"on_player_previous": self.on_player_previous,
"on_player_next": self.on_player_next,
"on_player_rewind": self.on_player_rewind,
"on_player_close": self.on_player_close,
"on_player_press": self.on_player_press,
"on_full_screen": self.on_full_screen,
"on_drawing_area_realize": self.on_drawing_area_realize,
"on_player_drawing_area_draw": self.on_player_drawing_area_draw,
"on_main_window_state": self.on_main_window_state,
"on_record": self.on_record,
"on_remove_all_unavailable": self.on_remove_all_unavailable,
"on_new_bouquet": self.on_new_bouquet,
"on_create_bouquet_for_current_satellite": self.on_create_bouquet_for_current_satellite,
"on_create_bouquet_for_each_satellite": self.on_create_bouquet_for_each_satellite,
"on_create_bouquet_for_current_package": self.on_create_bouquet_for_current_package,
"on_create_bouquet_for_each_package": self.on_create_bouquet_for_each_package,
"on_create_bouquet_for_current_type": self.on_create_bouquet_for_current_type,
"on_create_bouquet_for_each_type": self.on_create_bouquet_for_each_type}
self._handlers = {"on_close_app": self.on_close_app,
"on_resize": self.on_resize,
"on_about_app": self.on_about_app,
"on_settings": self.on_settings,
"on_profile_changed": self.on_profile_changed,
"on_download": self.on_download,
"on_data_open": self.on_data_open,
"on_new_configuration": self.on_new_configuration,
"on_tree_view_key_press": self.on_tree_view_key_press,
"on_tree_view_key_release": self.on_tree_view_key_release,
"on_bouquets_selection": self.on_bouquets_selection,
"on_satellite_editor_show": self.on_satellite_editor_show,
"on_services_selection": self.on_services_selection,
"on_fav_cut": self.on_fav_cut,
"on_bouquets_cut": self.on_bouquets_cut,
"on_services_copy": self.on_services_copy,
"on_fav_copy": self.on_fav_copy,
"on_bouquets_copy": self.on_bouquets_copy,
"on_fav_paste": self.on_fav_paste,
"on_bouquets_paste": self.on_bouquets_paste,
"on_rename_for_bouquet": self.on_rename_for_bouquet,
"on_set_default_name_for_bouquet": self.on_set_default_name_for_bouquet,
"on_services_add_new": self.on_services_add_new,
"on_edit": self.on_edit,
"on_delete": self.on_delete,
"on_to_fav_copy": self.on_to_fav_copy,
"on_to_fav_end_copy": self.on_to_fav_end_copy,
"on_fav_sort": self.on_fav_sort,
"on_fav_view_query_tooltip": self.on_fav_view_query_tooltip,
"on_services_view_query_tooltip": self.on_services_view_query_tooltip,
"on_view_drag_begin": self.on_view_drag_begin,
"on_view_drag_data_get": self.on_view_drag_data_get,
"on_services_view_drag_drop": self.on_services_view_drag_drop,
"on_services_view_drag_data_received": self.on_services_view_drag_data_received,
"on_view_drag_data_received": self.on_view_drag_data_received,
"on_bq_view_drag_data_received": self.on_bq_view_drag_data_received,
"on_view_press": self.on_view_press,
"on_view_popup_menu": self.on_view_popup_menu,
"on_view_focus": self.on_view_focus,
"on_model_changed": self.on_model_changed,
"on_import_yt_list": self.on_import_yt_list,
"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,
"on_insert_marker": self.on_insert_marker,
"on_insert_space": self.on_insert_space,
"on_fav_press": self.on_fav_press,
"on_locate_in_services": self.on_locate_in_services,
"on_picons_manager_show": self.on_picons_manager_show,
"on_filter_changed": self.on_filter_changed,
"on_assign_picon": self.on_assign_picon,
"on_remove_picon": self.on_remove_picon,
"on_reference_picon": self.on_reference_picon,
"on_remove_unused_picons": self.on_remove_unused_picons,
"on_search_down": self.on_search_down,
"on_search_up": self.on_search_up,
"on_search": self.on_search,
"on_iptv": self.on_iptv,
"on_epg_list_configuration": self.on_epg_list_configuration,
"on_iptv_list_configuration": self.on_iptv_list_configuration,
"on_play_stream": self.on_play_stream,
"on_watch": self.on_watch,
"on_player_play": self.on_player_play,
"on_player_stop": self.on_player_stop,
"on_player_previous": self.on_player_previous,
"on_player_next": self.on_player_next,
"on_player_rewind": self.on_player_rewind,
"on_player_close": self.on_player_close,
"on_player_press": self.on_player_press,
"on_full_screen": self.on_full_screen,
"on_drawing_area_realize": self.on_drawing_area_realize,
"on_player_drawing_area_draw": self.on_player_drawing_area_draw,
"on_record": self.on_record,
"on_remove_all_unavailable": self.on_remove_all_unavailable,
"on_new_bouquet": self.on_new_bouquet,
"on_create_bouquet_for_current_satellite": self.on_create_bouquet_for_current_satellite,
"on_create_bouquet_for_each_satellite": self.on_create_bouquet_for_each_satellite,
"on_create_bouquet_for_current_package": self.on_create_bouquet_for_current_package,
"on_create_bouquet_for_each_package": self.on_create_bouquet_for_each_package,
"on_create_bouquet_for_current_type": self.on_create_bouquet_for_current_type,
"on_create_bouquet_for_each_type": self.on_create_bouquet_for_each_type}
self._settings = Settings.get_instance()
self._s_type = self._settings.setting_type
@@ -181,7 +178,6 @@ class Application(Gtk.Application):
self._blacklist = set()
self._current_bq_name = None
self._bq_selected = "" # Current selected bouquet
self._select_enabled = True # Multiple selection
# Current satellite positions in the services list
self._sat_positions = []
self._marker_types = {BqServiceType.MARKER.name, BqServiceType.SPACE.name}
@@ -202,7 +198,7 @@ class Application(Gtk.Application):
builder = Gtk.Builder()
builder.add_from_file(UI_RESOURCES_PATH + "main_window.glade")
builder.connect_signals(handlers)
builder.connect_signals(self._handlers)
self._main_window = builder.get_object("main_window")
main_window_size = self._settings.get("window_size")
# Setting the last size of the window if it was saved
@@ -220,11 +216,15 @@ class Application(Gtk.Application):
self._bouquets_main_box = builder.get_object("bouquets_main_box")
self._header_bar = builder.get_object("header_bar")
self._bq_name_label = builder.get_object("bq_name_label")
tool_bar = builder.get_object("top_toolbar")
self._main_data_box.bind_property("visible", tool_bar, "visible")
self._telnet_tool_button = builder.get_object("telnet_tool_button")
# App info
self._app_info_box = builder.get_object("app_info_box")
self._app_info_box.bind_property("visible", builder.get_object("main_paned"), "visible", 4)
self._app_info_box.bind_property("visible", builder.get_object("right_header_box"), "visible", 4)
self._app_info_box.bind_property("visible", builder.get_object("left_header_box"), "visible", 4)
self._app_info_box.bind_property("visible", builder.get_object("toolbar_extra_box"), "visible", 4)
self._app_info_box.bind_property("visible", builder.get_object("toolbar_tools_box"), "visible", 4)
self._app_info_box.bind_property("visible", builder.get_object("save_tool_button"), "visible", 4)
# Status bar
self._profile_combo_box = builder.get_object("profile_combo_box")
self._receiver_info_box = builder.get_object("receiver_info_box")
@@ -241,9 +241,6 @@ class Application(Gtk.Application):
self._tv_count_label = builder.get_object("tv_count_label")
self._radio_count_label = builder.get_object("radio_count_label")
self._data_count_label = builder.get_object("data_count_label")
self._save_header_button = builder.get_object("save_header_button")
self._app_info_box.bind_property("visible", self._save_header_button, "visible", 4)
self._save_header_button.bind_property("visible", builder.get_object("save_menu_button"), "visible")
self._signal_level_bar.bind_property("visible", builder.get_object("play_current_service_button"), "visible")
self._signal_level_bar.bind_property("visible", builder.get_object("record_button"), "visible")
self._receiver_info_box.bind_property("visible", self._http_status_image, "visible", 4)
@@ -279,15 +276,12 @@ class Application(Gtk.Application):
self._player_tool_bar = builder.get_object("player_tool_bar")
self._player_prev_button = builder.get_object("player_prev_button")
self._player_next_button = builder.get_object("player_next_button")
self._player_box.bind_property("visible", tool_bar, "visible", 4)
self._player_box.bind_property("visible", self._services_main_box, "visible", 4)
self._player_box.bind_property("visible", self._bouquets_main_box, "visible", 4)
self._player_box.bind_property("visible", builder.get_object("close_player_menu_button"), "visible")
self._player_box.bind_property("visible", builder.get_object("left_header_box"), "visible", 4)
self._player_box.bind_property("visible", builder.get_object("right_header_box"), "visible", 4)
self._player_box.bind_property("visible", builder.get_object("main_popover_menu_box"), "visible", 4)
self._player_box.bind_property("visible", builder.get_object("main_header_box"), "visible", 4)
self._player_box.bind_property("visible", builder.get_object("left_header_separator"), "visible", 4)
self._player_box.bind_property("visible", self._profile_combo_box, "visible", 4)
self._player_box.bind_property("visible", builder.get_object("fav_pos_column"), "visible", 4)
self._player_box.bind_property("visible", builder.get_object("fav_pos_column"), "visible", 4)
self._player_box.bind_property("visible", self._profile_combo_box, "sensitive", 4)
self._fav_view.bind_property("sensitive", self._player_prev_button, "sensitive")
self._fav_view.bind_property("sensitive", self._player_next_button, "sensitive")
# Record
@@ -318,6 +312,16 @@ class Application(Gtk.Application):
self.init_keys()
self.set_accels()
builder = Gtk.Builder()
builder.set_translation_domain("demon-editor")
builder.add_from_file(UI_RESOURCES_PATH + "app_menu_bar.ui")
self.set_menubar(builder.get_object("menu_bar"))
self.set_app_menu(builder.get_object("app-menu"))
if self._settings.get("telnet"):
self.init_telnet(builder)
self.update_profile_label()
self.init_drag_and_drop()
self.init_colors()
@@ -331,7 +335,22 @@ class Application(Gtk.Application):
gen = self.init_http_api()
GLib.idle_add(lambda: next(gen, False), priority=GLib.PRIORITY_LOW)
def init_telnet(self, builder):
t_section = builder.get_object("telnet_section")
t_section.append_item(Gio.MenuItem.new("Telnet", "app.on_telnet_client_show"))
ac = Gio.SimpleAction.new("on_telnet_client_show", None)
ac.connect("activate", self.on_telnet_client_show)
self.add_action(ac)
self.set_accels_for_action("app.on_telnet_client_show", ["<primary>t"])
self._telnet_tool_button.set_visible(True)
def init_keys(self):
main_handlers = ("on_new_configuration", "on_data_open", "on_download", "on_settings",
"on_close_app", "on_import_bouquet", "on_import_bouquets", "on_satellite_editor_show",
"on_picons_manager_show", "on_backup_tool_show", "on_about_app")
iptv_handlers = ("on_iptv", "on_import_yt_list", "on_import_m3u", "on_export_to_m3u",
"on_epg_list_configuration", "on_iptv_list_configuration", "on_remove_all_unavailable")
def set_action(n, fun, enabled=True):
ac = Gio.SimpleAction.new(n, None)
ac.connect("activate", fun)
@@ -339,21 +358,29 @@ class Application(Gtk.Application):
self.add_action(ac)
return ac
set_action("on_close_app", self.on_close_app)
set_action("on_data_save", self.on_data_save)
set_action("on_download", self.on_download)
set_action("on_data_open", self.on_data_open)
set_action("on_archive_open", self.on_archive_open)
list(map(lambda x: set_action(x, self._handlers.get(x)), main_handlers))
# Import
action = set_action("on_import_bouquet", self._handlers.get("on_import_bouquet"), False)
self._tool_elements.get("bouquet_import_popup_item").bind_property("sensitive", action, "enabled")
# IPTV
iptv_elem = self._tool_elements.get("fav_iptv_popup_item")
for h in iptv_handlers:
action = set_action(h, self._handlers.get(h), False)
iptv_elem.bind_property("sensitive", action, "enabled")
# Search, Filter
search_action = Gio.SimpleAction.new_stateful("search", None, GLib.Variant.new_boolean(False))
search_action.connect("change-state", self.on_search_toggled)
search_action.set_enabled(False)
self._app_info_box.bind_property("visible", search_action, "enabled", 4)
self._main_window.add_action(search_action) # For "win.*" actions!
filter_action = Gio.SimpleAction.new_stateful("filter", None, GLib.Variant.new_boolean(False))
filter_action.connect("change-state", self.on_filter_toggled)
filter_action.set_enabled(False)
self._app_info_box.bind_property("visible", filter_action, "enabled", 4)
self._main_window.add_action(filter_action)
# Lock, Hide
set_action("on_hide", self.on_hide)
set_action("on_locked", self.on_locked)
self._app_info_box.bind_property("visible", set_action("on_hide", self.on_hide, False), "enabled", 4)
self._app_info_box.bind_property("visible", set_action("on_locked", self.on_locked, False), "enabled", 4)
# Open and download/upload data
set_action("open_data", lambda a, v: self.open_data())
set_action("on_download_data", self.on_download_data)
@@ -361,6 +388,8 @@ class Application(Gtk.Application):
set_action("upload_bouquets", lambda a, v: self.on_upload_data(DownloadType.BOUQUETS))
# Edit
set_action("on_edit", self.on_edit)
# Save
self._app_info_box.bind_property("visible", set_action("on_data_save", self.on_data_save, False), "enabled", 4)
# Screenshots
set_action("on_screenshot_all", self.on_screenshot_all)
set_action("on_screenshot_video", self.on_screenshot_video)
@@ -412,6 +441,18 @@ class Application(Gtk.Application):
log("Starting record of current stream...")
log("Not implemented yet!")
if "telnet" in options:
t_op = options.get("telnet", "off")
if t_op == "on":
self._settings.add("telnet", True)
elif t_op == "off":
self._settings.add("telnet", False)
else:
log("No valid [on, off] arguments for -t found!")
return 1
log("Telnet support is {}. Restart the program to apply the settings!".format(t_op))
self._settings.save()
if "debug" in options:
d_op = options.get("debug", "off")
if d_op == "on":
@@ -434,7 +475,7 @@ class Application(Gtk.Application):
self.set_profile(profile)
def init_drag_and_drop(self):
""" Enable drag-and-drop. """
""" Enable drag-and-drop """
target = []
bq_target = []
@@ -454,20 +495,13 @@ class Application(Gtk.Application):
self._services_view.drag_source_set_target_list(None)
self._services_view.drag_source_add_text_targets()
self._services_view.drag_dest_add_text_targets()
self._services_view.drag_dest_add_uri_targets()
self._bouquets_view.drag_dest_set_target_list(None)
self._bouquets_view.drag_source_set_target_list(None)
self._bouquets_view.drag_dest_add_text_targets()
self._bouquets_view.drag_source_add_text_targets()
self._app_info_box.drag_dest_set(Gtk.DestDefaults.ALL, [], Gdk.DragAction.COPY)
self._app_info_box.drag_dest_add_text_targets()
# For multiple selection.
self._services_view.get_selection().set_select_function(lambda *args: self._select_enabled)
self._fav_view.get_selection().set_select_function(lambda *args: self._select_enabled)
self._bouquets_view.get_selection().set_select_function(lambda *args: self._select_enabled)
self._bouquets_view.drag_dest_add_uri_targets()
def init_colors(self, update=False):
""" Initialisation of background colors for the services.
@@ -729,8 +763,6 @@ class Application(Gtk.Application):
self._bouquets.pop("{}:{}".format(b_row[Column.BQ_NAME], b_row[Column.BQ_TYPE]), None)
self._bouquets_model.remove(itr)
self._bq_selected = ""
self._bq_name_label.set_text(self._bq_selected)
self._wait_dialog.hide()
yield True
@@ -877,6 +909,7 @@ class Application(Gtk.Application):
self._wait_dialog.show(get_message("Sorting data..."))
GLib.idle_add(self.sort_fav, c_num, bq, paths, order, 0 if c_num == Column.FAV_NUM else "")
@run_idle
def sort_fav(self, c_num, bq, paths, rev=False, nv=""):
""" Sorting function for the bouquet details list.
@@ -944,116 +977,30 @@ class Application(Gtk.Application):
pol = ", {}: {},".format(get_message("Pol"), srv.pol) if srv.pol else ","
fec = "{}: {}".format("FEC", srv.fec) if srv.fec else ","
ht = "{}{}: {}\n{}: {}\n{}: {}\n{}: {}{} {}, {}\n{}"
ht = "{}{}: {}\n{}: {}\n{}: {}\n{}: {}{} {}, {}: {}\n{}"
return ht.format(header,
get_message("Package"), srv.package,
get_message("System"), srv.system,
get_message("Freq"), srv.freq,
get_message("Rate"), srv.rate, pol, fec, self.get_ssid_info(srv),
get_message("Rate"), srv.rate, pol, fec, "SID", srv.ssid,
ref)
def get_hint_for_srv_list(self, srv):
""" Returns short info about service as formatted string for using as hint. """
header, ref = self.get_hint_header_info(srv)
return "{}{}\n{}".format(header, self.get_ssid_info(srv), ref)
return "{}{}".format(*self.get_hint_header_info(srv))
def get_hint_header_info(self, srv):
header = "{}: {}\n{}: {}\n".format(get_message("Name"), srv.service, get_message("Type"), srv.service_type)
ref = "{}: {}".format(get_message("Service reference"), srv.picon_id.rstrip(".png"))
return header, ref
def get_ssid_info(self, srv):
""" Returns SID representation in hex and dec formats. """
sid = srv.ssid or "0"
try:
dec = "{0:04d}".format(int(sid, 16))
except ValueError as e:
log("SID value conversion error: {}".format(e))
else:
return "SID: 0x{} ({})".format(sid.upper(), dec)
return "SID: 0x{}".format(sid.upper())
# ***************** Drag-and-drop *********************#
def on_view_drag_begin(self, view, context):
""" Sets its own icon for dragging.
We have to use "connect_after" (after="yes" in xml) to override what the default handler did.
https://lazka.github.io/pgi-docs/Gtk-3.0/classes/Widget.html#Gtk.Widget.signals.drag_begin
"""
model, paths = view.get_selection().get_selected_rows()
if len(paths) < 1:
return
name, model = get_model_data(view)
name_column, type_column = Column.SRV_SERVICE, Column.SRV_TYPE
if name == self.FAV_MODEL_NAME:
name_column, type_column = Column.FAV_SERVICE, Column.FAV_TYPE
elif name == self.BQ_MODEL_NAME:
name_column, type_column = Column.BQ_NAME, Column.BQ_TYPE
# https://stackoverflow.com/a/52248549
Gtk.drag_set_icon_pixbuf(context, self.get_drag_icon_pixbuf(model, paths, name_column, type_column), 0, 0)
return True
def on_view_drag_end(self, view, context):
self._select_enabled = True
view.get_selection().unselect_all()
def get_drag_icon_pixbuf(self, model, paths, text_column, type_column):
""" Creates and returns Pixbuf for a dragging icon. """
import cairo
window = Gtk.OffscreenWindow()
window.get_style_context().add_class(Gtk.STYLE_CLASS_DND)
frame = Gtk.Frame()
list_box = Gtk.ListBox()
list_box.set_selection_mode(Gtk.SelectionMode.NONE)
padding = 10
for index, row in enumerate([model[p] for p in paths]):
if index == 25:
list_box.add(Gtk.Arrow(Gtk.ArrowType.DOWN))
break
h_box = Gtk.HBox()
h_box.set_spacing(10)
h_box.get_style_context().add_class(Gtk.STYLE_CLASS_LIST_ROW)
label = Gtk.Label(row[text_column])
label.set_alignment(0, 0)
label.set_padding(padding, 2)
h_box.add(label)
label = Gtk.Label(row[type_column])
label.set_halign(Gtk.Align.END)
label.set_padding(padding, 2)
h_box.add(label)
list_box.add(h_box)
if len(paths) > 1:
list_box.add(Gtk.Separator())
h_box = Gtk.HBox()
h_box.set_spacing(2)
img = Gtk.Image.new_from_icon_name("document-properties", 0)
h_box.add(img)
h_box.add(Gtk.Label(len(paths)))
h_box.set_halign(Gtk.Align.START)
h_box.set_margin_left(10)
h_box.set_margin_bottom(5)
h_box.set_margin_top(2)
list_box.add(h_box)
frame.add(list_box)
frame.show_all()
window.add(frame)
window.show()
alloc = frame.get_allocation()
w, h = alloc.width, alloc.height
surf = cairo.ImageSurface(cairo.FORMAT_ARGB32, w, h)
frame.draw(cairo.Context(surf))
pix = Gdk.pixbuf_get_from_surface(surf, 0, 0, w, h)
window.destroy()
return pix
""" Selects a row under the cursor in the view at the dragging beginning. """
path, column = view.get_cursor()
if path:
view.get_selection().select_path(path)
def on_view_drag_data_get(self, view, drag_context, data, info, time):
selection = self.get_selection(view)
@@ -1064,7 +1011,7 @@ class Application(Gtk.Application):
view.stop_emission_by_name("drag_drop")
# https://stackoverflow.com/q/7661016 [Some data was dropped, get the data!]
targets = drag_context.list_targets()
view.drag_get_data(drag_context, targets[-1] if targets else Gdk.atom_intern("text/plain", False), time)
view.drag_get_data(drag_context, targets[-1] if targets else Gdk.atom_intern("text/uri-list", False), time)
def on_services_view_drag_data_received(self, view, drag_context, x, y, data, info, time):
# Needs for the GtkTreeView when using models [filter, sort]
@@ -1076,25 +1023,29 @@ class Application(Gtk.Application):
txt = data.get_text()
uris = data.get_uris()
if txt:
name, model = get_model_data(view)
if txt.startswith("file://") and name == self.SERVICE_MODEL_NAME:
self.on_import_data(urlparse(unquote(txt)).path.strip())
elif name == self.FAV_MODEL_NAME:
self.receive_selection(view=view, drop_info=view.get_dest_row_at_pos(x, y), data=txt)
elif len(uris) == 2:
self.picons_buffer = self.on_assign_picon(view, urlparse(unquote(uris[0])).path,
urlparse(unquote(uris[1])).path + os.sep)
drag_context.finish(True, False, time)
self.receive_selection(view=view, drop_info=view.get_dest_row_at_pos(x, y), data=txt)
if uris:
from urllib.parse import unquote, urlparse
src, sep, dest = uris[0].partition("::::")
picon_path = urlparse(unquote(src)).path
dest_path = urlparse(unquote(dest)).path + "/"
self.picons_buffer = self.on_assign_picon(view, picon_path, dest_path)
drag_context.finish(True, None, time)
def on_bq_view_drag_data_received(self, view, drag_context, x, y, data, info, time):
model_name, model = get_model_data(view)
drop_info = view.get_dest_row_at_pos(x, y)
data = data.get_text()
if not data:
uris = data.get_uris()
if uris:
from urllib.parse import unquote, urlparse
self.on_import_bouquet(None, file_path=urlparse(unquote(uris[0])).path.strip())
return
if data.startswith("file://"):
self.on_import_bouquet(None, file_path=urlparse(unquote(data)).path.strip())
data = data.get_text()
if not data:
return
itr_str, sep, source = data.partition("::::")
@@ -1107,19 +1058,21 @@ class Application(Gtk.Application):
top_iter = model.get_iter(path)
parent_itr = model.iter_parent(top_iter) # parent
to_del = []
is_darwin = self._settings.is_darwin
if parent_itr:
p_path = model.get_path(parent_itr)[0]
for itr in itrs:
p_itr = model.iter_parent(itr)
if not p_itr:
break
if p_itr and model.get_path(p_itr)[0] == p_path:
model.move_after(itr, top_iter)
top_iter = itr
if all((not is_darwin, p_itr, model.get_path(p_itr)[0] == p_path)):
top_iter = model.move_before(itr, top_iter)
else:
model.insert(parent_itr, model.get_path(top_iter)[1], model[itr][:])
to_del.append(itr)
elif not model.iter_has_child(top_iter):
elif not model.iter_has_child(top_iter) or is_darwin:
for itr in itrs:
model.append(top_iter, model[itr][:])
to_del.append(itr)
@@ -1185,22 +1138,10 @@ class Application(Gtk.Application):
self.show_error_dialog(str(e))
def on_view_press(self, view, event):
""" Handles a mouse click (press) to view. """
if event.get_event_type() == Gdk.EventType.BUTTON_PRESS and event.button == Gdk.BUTTON_PRIMARY:
target = view.get_path_at_pos(event.x, event.y)
# Idea taken from here: https://kevinmehall.net/2010/pygtk_multi_select_drag_drop
mask = not (event.state & (Gdk.ModifierType.CONTROL_MASK | Gdk.ModifierType.SHIFT_MASK))
if target and mask and view.get_selection().path_is_selected(target[0]):
self._select_enabled = False
name, model = get_model_data(view)
self.delete_views_selection(name)
def on_view_release(self, view, event):
""" Handles a mouse click (release) to view. """
# Enable selection.
self._select_enabled = True
def delete_views_selection(self, name):
if name == self.SERVICE_MODEL_NAME:
self.delete_selection(self._fav_view)
@@ -1284,71 +1225,15 @@ class Application(Gtk.Application):
self.show_error_dialog(str(e))
def on_data_open(self, action=None, value=None):
""" Opening data via "File/Open". """
response = show_dialog(DialogType.CHOOSER, self._main_window, settings=self._settings, title="Open folder")
if response in (Gtk.ResponseType.CANCEL, Gtk.ResponseType.DELETE_EVENT):
return
self.open_data(response)
def on_archive_open(self, action=None, value=None):
""" Opening the data archive via "File/Open archive". """
file_filter = Gtk.FileFilter()
file_filter.set_name("*.zip, *.gz")
file_filter.add_mime_type("application/zip")
file_filter.add_mime_type("application/gzip")
response = show_dialog(DialogType.CHOOSER, self._main_window,
action_type=Gtk.FileChooserAction.OPEN,
file_filter=file_filter,
settings=self._settings,
title="Open archive")
response = show_dialog(DialogType.CHOOSER, self._main_window, settings=self._settings)
if response in (Gtk.ResponseType.CANCEL, Gtk.ResponseType.DELETE_EVENT):
return
self.open_data(response)
def open_data(self, data_path=None, callback=None):
""" Opening data and fill views. """
if data_path and os.path.isfile(data_path):
self.open_compressed_data(data_path)
else:
gen = self.update_data(data_path, callback)
GLib.idle_add(lambda: next(gen, False), priority=GLib.PRIORITY_LOW)
def open_compressed_data(self, data_path):
""" Opening archived data. """
arch_path = self.get_archive_path(data_path)
if arch_path:
gen = self.update_data("{}{}".format(arch_path.name, os.sep), callback=arch_path.cleanup)
GLib.idle_add(lambda: next(gen, False), priority=GLib.PRIORITY_LOW)
def get_archive_path(self, data_path):
""" Returns the temp dir path for the extracted data, or None if the archive format is not supported. """
import zipfile
import tarfile
import tempfile
tmp_path = tempfile.TemporaryDirectory()
tmp_path_name = tmp_path.name
if zipfile.is_zipfile(data_path):
with zipfile.ZipFile(data_path) as zip_file:
for zip_info in zip_file.infolist():
if not zip_info.filename.endswith(os.sep):
zip_info.filename = os.path.basename(zip_info.filename)
zip_file.extract(zip_info, path=tmp_path_name)
elif tarfile.is_tarfile(data_path):
with tarfile.open(data_path) as tar:
for mb in tar.getmembers():
if mb.isfile():
mb.name = os.path.basename(mb.name)
tar.extract(mb, path=tmp_path_name)
else:
tmp_path.cleanup()
log("Error getting the path for the archive. Unsupported file format: {}".format(data_path))
self.show_error_dialog("Unsupported format!")
return
return tmp_path
gen = self.update_data(data_path, callback)
GLib.idle_add(lambda: next(gen, False), priority=GLib.PRIORITY_LOW)
def update_data(self, data_path, callback=None):
self._profile_combo_box.set_sensitive(False)
@@ -1558,7 +1443,6 @@ class Application(Gtk.Application):
GLib.idle_add(lambda: next(gen, False), priority=GLib.PRIORITY_LOW)
def save_data(self, callback=None):
self._save_header_button.set_sensitive(False)
profile = self._s_type
path = self._settings.data_local_path
backup_path = self._settings.backup_local_path
@@ -1601,8 +1485,6 @@ class Application(Gtk.Application):
if profile is SettingsType.ENIGMA_2:
# blacklist
write_blacklist(path, self._blacklist)
self._save_header_button.set_sensitive(True)
yield True
self._data_hash = self.get_data_hash()
yield True
@@ -1664,7 +1546,7 @@ class Application(Gtk.Application):
if len(path) > 1:
gen = self.update_bouquet_services(model, path)
GLib.idle_add(lambda: next(gen, False))
GLib.idle_add(lambda: next(gen, False), priority=GLib.PRIORITY_LOW)
def update_bouquet_services(self, model, path, bq_key=None):
""" Updates list of bouquet services """
@@ -1676,12 +1558,12 @@ class Application(Gtk.Application):
services = self._bouquets.get(key, [])
ex_services = self._extra_bouquets.get(key, None)
if len(services) > self.FAV_FACTOR * 20:
factor = self.FAV_FACTOR * 20
if len(services) > factor or len(self._fav_model) > factor:
self._bouquets_view.set_sensitive(False)
yield True
self._fav_view.set_model(None)
self._fav_model.clear()
yield True
num = 0
for srv_id in services:
@@ -1700,11 +1582,11 @@ class Application(Gtk.Application):
self._fav_model.append((0 if is_marker else num, srv.coded, ex_srv_name if ex_srv_name else srv.service,
srv.locked, srv.hide, srv_type, srv.pos, srv.fav_id,
self._picons.get(srv.picon_id, None), None, background))
if num % self.FAV_FACTOR == 0:
yield True
yield True
self._fav_view.set_model(self._fav_model)
self._bouquets_view.set_sensitive(True)
self._bouquets_view.grab_focus()
GLib.idle_add(self._bouquets_view.set_sensitive, True)
GLib.idle_add(self._bouquets_view.grab_focus)
yield True
def check_bouquet_selection(self):
@@ -2091,16 +1973,6 @@ class Application(Gtk.Application):
else:
show_dialog(DialogType.INFO, self._main_window, "Done!")
def on_import_data(self, path):
msg = "Combine with the current data?"
if len(self._services_model) > 0 and show_dialog(DialogType.QUESTION, self._main_window,
msg) == Gtk.ResponseType.OK:
self.import_data(path, force=True)
else:
if os.path.isdir(path) and not path.endswith(os.sep):
path += os.sep
self.open_data(path)
def on_import_bouquet(self, action, value=None, file_path=None):
model, paths = self._bouquets_view.get_selection().get_selected_rows()
if not paths:
@@ -2115,34 +1987,17 @@ class Application(Gtk.Application):
if response in (Gtk.ResponseType.CANCEL, Gtk.ResponseType.DELETE_EVENT):
return
self.import_data(response)
def import_data(self, path, force=None, callback=None):
if os.path.isdir(path) and not path.endswith(os.sep):
path += os.sep
elif os.path.isfile(path):
arch_path = self.get_archive_path(path)
if not arch_path:
return
path = arch_path.name + os.sep
callback = arch_path.cleanup
def append(b, s):
gen = self.append_imported_data(b, s, callback)
gen = self.append_imported_data(b, s)
GLib.idle_add(lambda: next(gen, False))
dialog = ImportDialog(self._main_window, path, self._settings, self._services.keys(), append)
dialog.import_data() if force else dialog.show()
ImportDialog(self._main_window, response, self._settings, self._services.keys(), append).show()
def append_imported_data(self, bouquets, services, callback=None):
def append_imported_data(self, bouquets, services):
try:
self._wait_dialog.show()
yield from self.append_data(bouquets, services)
finally:
log("Importing data done!")
if callback:
callback()
self._wait_dialog.hide()
# ***************** Backup ********************#
@@ -2151,6 +2006,12 @@ class Application(Gtk.Application):
""" Shows backup tool dialog """
BackupDialog(self._main_window, self._settings, self.open_data).show()
# ***************** Telnet *********************#
def on_telnet_client_show(self, action, value=None):
from app.ui.telnet import TelnetDialog
TelnetDialog(self._main_window, self._settings).show()
# ***************** Player *********************#
def on_play_stream(self, item=None):
@@ -2195,7 +2056,8 @@ class Application(Gtk.Application):
self.set_playback_elms_active()
else:
if not self._player_box.get_visible():
self.set_player_area_size(self._player_box)
w, h = self._main_window.get_size()
self._player_box.set_size_request(w * 0.6, -1)
self._current_mrl = url
self._player_box.set_visible(True)
@@ -2265,13 +2127,14 @@ class Application(Gtk.Application):
self._fav_view.do_grab_focus(self._fav_view)
def get_time_str(self, duration):
""" Returns a string representation of time from duration in milliseconds """
""" returns a string representation of time from duration in milliseconds """
m, s = divmod(duration // 1000, 60)
h, m = divmod(m, 60)
return "{}{:02d}:{:02d}".format(str(h) + ":" if h else "", m, s)
def on_drawing_area_realize(self, widget):
self.set_player_area_size(widget)
w, h = self._main_window.get_size()
widget.set_size_request(w * 0.6, -1)
if not self._player:
try:
@@ -2291,10 +2154,6 @@ class Application(Gtk.Application):
finally:
self.set_playback_elms_active()
def set_player_area_size(self, widget):
w, h = self._main_window.get_size()
widget.set_size_request(w * 0.6, -1)
def on_player_drawing_area_draw(self, widget, cr):
""" Used for black background drawing in the player drawing area.
@@ -2318,16 +2177,14 @@ class Application(Gtk.Application):
def on_full_screen(self, item=None):
self._full_screen = not self._full_screen
self.update_state_on_full_screen(not self._full_screen)
self._main_window.fullscreen() if self._full_screen else self._main_window.unfullscreen()
def on_main_window_state(self, window, event):
state = event.new_window_state
full = not state & Gdk.WindowState.FULLSCREEN
self._main_data_box.set_visible(full)
self._player_tool_bar.set_visible(full)
self._status_bar_box.set_visible(full)
if not state & Gdk.WindowState.ICONIFIED and self._links_transmitter:
self._links_transmitter.hide()
@run_idle
def update_state_on_full_screen(self, visible):
self._main_data_box.set_visible(visible)
self._player_tool_bar.set_visible(visible)
self._status_bar_box.set_visible(visible and not self._app_info_box.get_visible())
# ************************* Record ***************************** #
@@ -2416,11 +2273,6 @@ class Application(Gtk.Application):
def on_watch(self, item=None):
""" Switch to the channel and watch in the player """
if self._app_info_box.get_visible() and self._settings.play_streams_mode is PlayStreamsMode.BUILT_IN:
self.set_player_area_size(self._player_box)
self._player_box.set_visible(True)
GLib.idle_add(self._app_info_box.set_visible, False)
self._http_api.send(HttpRequestType.STREAM_CURRENT, None, self.watch)
def watch(self, data):
@@ -2756,7 +2608,7 @@ class Application(Gtk.Application):
dialog.show()
def on_bouquets_edit(self, view):
""" Renaming bouquets. """
""" Rename bouquets """
if not self._bq_selected:
self.show_error_dialog("This item is not allowed to edit!")
return
@@ -2776,15 +2628,10 @@ class Application(Gtk.Application):
return
model.set_value(itr, 0, response)
old_bq_name = "{}:{}".format(bq_name, bq_type)
self._bouquets[bq] = self._bouquets.pop(old_bq_name)
self._bouquets[bq] = self._bouquets.pop("{}:{}".format(bq_name, bq_type))
self._current_bq_name = response
self._bq_name_label.set_text(self._current_bq_name)
self._bq_selected = bq
# services with extra names for the bouquet
ext_bq = self._extra_bouquets.get(old_bq_name, None)
if ext_bq:
self._extra_bouquets[bq] = ext_bq
self._bq_selected = "{}:{}".format(response, bq_type)
def on_rename(self, view):
name, model = get_model_data(view)
@@ -2924,11 +2771,11 @@ class Application(Gtk.Application):
profile_name = self._profile_combo_box.get_active_text()
msg = get_message("Profile:")
if self._s_type is SettingsType.ENIGMA_2:
self._header_bar.set_subtitle("{} {} [Enigma2 v.{}]".format(msg, profile_name, self.get_format_version()))
title = "DemonEditor [{} {} - Enigma2 v.{}]".format(msg, profile_name, self.get_format_version())
self._main_window.set_title(title)
elif self._s_type is SettingsType.NEUTRINO_MP:
self._header_bar.set_subtitle("{} {} [Neutrino-MP]".format(msg, profile_name))
self._main_window.set_title("DemonEditor [{} {} - Neutrino-MP]".format(msg, profile_name))
def get_format_version(self):
return 5 if self._settings.v5_support else 4

View File

@@ -46,57 +46,54 @@ def move_items(key, view: Gtk.TreeView):
""" Move items in the tree view """
selection = view.get_selection()
model, paths = selection.get_selected_rows()
if not paths:
return
is_tree_store = type(model) is Gtk.TreeStore
mod_length = len(model)
if not is_tree_store and mod_length == len(paths):
return
cursor_path = view.get_cursor()[0]
max_path = Gtk.TreePath.new_from_indices((mod_length,))
min_path = Gtk.TreePath.new_from_indices((0,))
if is_tree_store:
if paths:
mod_length = len(model)
if mod_length == len(paths):
return
cursor_path = view.get_cursor()[0]
max_path = Gtk.TreePath.new_from_indices((mod_length,))
min_path = Gtk.TreePath.new_from_indices((0,))
is_tree_store = False
parent_paths = list(filter(lambda p: p.get_depth() == 1, paths))
if parent_paths:
paths = parent_paths
min_path = model.get_path(model.get_iter_first())
view.collapse_all()
if mod_length == len(paths):
return
else:
if not is_some_level(paths):
return
parent_itr = model.iter_parent(model.get_iter(paths[0]))
parent_index = model.get_path(parent_itr)
children_num = model.iter_n_children(parent_itr)
if key in (KeyboardKey.PAGE_DOWN, KeyboardKey.END, KeyboardKey.END_KP, KeyboardKey.PAGE_DOWN_KP):
children_num -= 1
min_path = Gtk.TreePath.new_from_string("{}:{}".format(parent_index, 0))
max_path = Gtk.TreePath.new_from_string("{}:{}".format(parent_index, children_num))
is_tree_store = True
if key is KeyboardKey.UP:
top_path = Gtk.TreePath(paths[0])
set_cursor(top_path, paths, selection, view)
top_path.prev()
move_up(top_path, model, paths)
elif key is KeyboardKey.DOWN:
down_path = Gtk.TreePath(paths[-1])
set_cursor(down_path, paths, selection, view)
down_path.next()
if down_path < max_path:
move_down(down_path, model, paths)
else:
max_path.prev()
move_down(max_path, model, paths)
elif key in (KeyboardKey.PAGE_UP, KeyboardKey.HOME, KeyboardKey.PAGE_UP_KP, KeyboardKey.HOME_KP):
move_up(min_path if is_tree_store else cursor_path, model, paths)
elif key in (KeyboardKey.PAGE_DOWN, KeyboardKey.END, KeyboardKey.END_KP, KeyboardKey.PAGE_DOWN_KP):
move_down(max_path if is_tree_store else cursor_path, model, paths)
if type(model) is Gtk.TreeStore:
parent_paths = list(filter(lambda p: p.get_depth() == 1, paths))
if parent_paths:
paths = parent_paths
min_path = model.get_path(model.get_iter_first())
view.collapse_all()
if mod_length == len(paths):
return
else:
if not is_some_level(paths):
return
parent_itr = model.iter_parent(model.get_iter(paths[0]))
parent_index = model.get_path(parent_itr)
children_num = model.iter_n_children(parent_itr)
if key in (KeyboardKey.PAGE_DOWN, KeyboardKey.END, KeyboardKey.END_KP, KeyboardKey.PAGE_DOWN_KP):
children_num -= 1
min_path = Gtk.TreePath.new_from_string("{}:{}".format(parent_index, 0))
max_path = Gtk.TreePath.new_from_string("{}:{}".format(parent_index, children_num))
is_tree_store = True
if key is KeyboardKey.UP:
top_path = Gtk.TreePath(paths[0])
set_cursor(top_path, paths, selection, view)
top_path.prev()
move_up(top_path, model, paths)
elif key is KeyboardKey.DOWN:
down_path = Gtk.TreePath(paths[-1])
set_cursor(down_path, paths, selection, view)
down_path.next()
if down_path < max_path:
move_down(down_path, model, paths)
else:
max_path.prev()
move_down(max_path, model, paths)
elif key in (KeyboardKey.PAGE_UP, KeyboardKey.HOME, KeyboardKey.PAGE_UP_KP, KeyboardKey.HOME_KP):
move_up(min_path if is_tree_store else cursor_path, model, paths)
elif key in (KeyboardKey.PAGE_DOWN, KeyboardKey.END, KeyboardKey.END_KP, KeyboardKey.PAGE_DOWN_KP):
move_down(max_path if is_tree_store else cursor_path, model, paths)
def move_up(top_path, model, paths):
@@ -164,8 +161,7 @@ def rename(view, parent_window, target, fav_view=None, service_view=None, servic
return
srv_name = response
if not model.get_value(itr, Column.FAV_BACKGROUND):
model.set_value(itr, Column.FAV_SERVICE, response)
model.set_value(itr, Column.FAV_SERVICE, response)
if service_view is not None:
for row in get_base_model(service_view.get_model()):
@@ -405,19 +401,15 @@ def assign_picons(target, srv_view, fav_view, transient, picons, settings, servi
picons_path = dst_path or settings.picons_local_path
os.makedirs(os.path.dirname(picons_path), exist_ok=True)
picon_file = picons_path + picon_id
try:
shutil.copy(src_path, picon_file)
except shutil.SameFileError:
pass # NOP
shutil.copy(src_path, picon_file)
picons_files.append(picon_file)
picon = get_picon_pixbuf(picon_file)
picons[picon_id] = picon
model.set_value(itr, p_pos, picon)
if target is ViewTarget.SERVICES:
set_picon(fav_id, fav_view.get_model(), picon, Column.FAV_ID, p_pos)
else:
picons_files.append(picon_file)
picon = get_picon_pixbuf(picon_file)
picons[picon_id] = picon
model.set_value(itr, p_pos, picon)
if target is ViewTarget.SERVICES:
set_picon(fav_id, fav_view.get_model(), picon, Column.FAV_ID, p_pos)
else:
set_picon(fav_id, get_base_model(srv_view.get_model()), picon, Column.SRV_FAV_ID, p_pos)
set_picon(fav_id, get_base_model(srv_view.get_model()), picon, Column.SRV_FAV_ID, p_pos)
return picons_files

File diff suppressed because it is too large Load Diff

View File

@@ -32,6 +32,34 @@ Author: Dmitriy Yefremov
<!-- interface-name DemonEditor -->
<!-- interface-copyright 2018-2020 Dmitriy Yefremov -->
<!-- interface-authors Dmitriy Yefremov -->
<object class="GtkImage" id="cancel_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">window-close-symbolic</property>
</object>
<object class="GtkImage" id="convert_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">edit-redo-symbolic</property>
<property name="icon_size">1</property>
</object>
<object class="GtkImage" id="filter_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">edit-find-replace-symbolic</property>
<property name="icon_size">1</property>
</object>
<object class="GtkImage" id="info_toggle_button_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">emblem-important-symbolic</property>
</object>
<object class="GtkImage" id="load_providers">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">network-server-symbolic</property>
<property name="icon_size">1</property>
</object>
<object class="GtkListStore" id="picons_dest_list_store">
<columns>
<!-- column-name picon -->
@@ -177,10 +205,28 @@ Author: Dmitriy Yefremov
<column type="gboolean"/>
</columns>
</object>
<object class="GtkImage" id="receive_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">network-receive-symbolic</property>
<property name="icon_size">1</property>
</object>
<object class="GtkImage" id="receive_picons_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">network-receive-symbolic</property>
<property name="icon_size">1</property>
</object>
<object class="GtkImage" id="remove_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">user-trash-symbolic</property>
</object>
<object class="GtkImage" id="remove_selection_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">edit-undo</property>
<property name="icon_size">1</property>
</object>
<object class="GtkMenu" id="providers_popup_menu">
<property name="visible">True</property>
@@ -216,232 +262,23 @@ Author: Dmitriy Yefremov
<column type="gchararray"/>
</columns>
</object>
<object class="GtkImage" id="send_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">network-transmit-symbolic</property>
<property name="icon_size">1</property>
</object>
<object class="GtkWindow" id="picons_dialog">
<property name="can_focus">False</property>
<property name="title" translatable="yes">Picons manager</property>
<property name="window_position">center-on-parent</property>
<property name="destroy_with_parent">True</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_close" swapped="no"/>
<child type="titlebar">
<object class="GtkHeaderBar" id="header">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">2</property>
<property name="show_close_button">True</property>
<child>
<object class="GtkButton" id="cancel_button">
<property name="can_focus">False</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Cancel</property>
<property name="always_show_image">True</property>
<signal name="clicked" handler="on_cancel" swapped="no"/>
<child>
<object class="GtkImage" id="cancel_button_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-cancel</property>
</object>
</child>
<accelerator key="z" signal="clicked" modifiers="GDK_CONTROL_MASK"/>
</object>
</child>
<child>
<object class="GtkBox" id="header_download_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">2</property>
<child>
<object class="GtkButton" id="load_providers_button">
<property name="sensitive">False</property>
<property name="can_focus">False</property>
<property name="receives_default">False</property>
<property name="tooltip_text" translatable="yes">Load providers</property>
<property name="halign">center</property>
<property name="always_show_image">True</property>
<signal name="clicked" handler="on_load_providers" swapped="no"/>
<child>
<object class="GtkImage" id="load_providers_button_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">network-server-symbolic</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="receive_button">
<property name="sensitive">False</property>
<property name="can_focus">False</property>
<property name="receives_default">False</property>
<property name="tooltip_text" translatable="yes">Receive picons</property>
<property name="halign">center</property>
<property name="always_show_image">True</property>
<signal name="clicked" handler="on_receive" swapped="no"/>
<child>
<object class="GtkImage" id="receive_button_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-goto-bottom</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkButton" id="send_button">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Transfer to receiver</property>
<property name="always_show_image">True</property>
<signal name="clicked" handler="on_send" swapped="no"/>
<signal name="drag-data-received" handler="on_send_button_drag_data_received" swapped="no"/>
<child>
<object class="GtkImage" id="send_button_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-go-up</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">4</property>
</packing>
</child>
<child>
<object class="GtkButton" id="download_button">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Download from the receiver</property>
<signal name="clicked" handler="on_download" swapped="no"/>
<signal name="drag-data-received" handler="on_download_button_drag_data_received" swapped="no"/>
<child>
<object class="GtkImage" id="download_button_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-go-down</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">5</property>
</packing>
</child>
<child>
<object class="GtkButton" id="remove_button">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Remove all picons from the receiver</property>
<signal name="clicked" handler="on_remove" swapped="no"/>
<signal name="drag-data-received" handler="on_remove_button_drag_data_received" swapped="no"/>
<child>
<object class="GtkImage" id="remove_button_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-delete</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">6</property>
</packing>
</child>
</object>
<packing>
<property name="position">6</property>
</packing>
</child>
<child type="title">
<object class="GtkStackSwitcher" id="sctack">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stack">stack</property>
</object>
</child>
<child>
<object class="GtkButton" id="convert_button">
<property name="can_focus">False</property>
<property name="receives_default">False</property>
<property name="tooltip_text" translatable="yes">Convert</property>
<property name="halign">center</property>
<property name="always_show_image">True</property>
<signal name="clicked" handler="on_convert" swapped="no"/>
<child>
<object class="GtkImage" id="convert_button_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-execute</property>
</object>
</child>
</object>
<packing>
<property name="pack_type">end</property>
<property name="position">4</property>
</packing>
</child>
<child>
<object class="GtkCheckButton" id="info_check_button">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="receives_default">False</property>
<property name="tooltip_text" translatable="yes">Details</property>
<property name="draw_indicator">False</property>
<child>
<object class="GtkImage" id="info_check_button_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-dialog-info</property>
</object>
</child>
<accelerator key="i" signal="clicked" modifiers="GDK_CONTROL_MASK"/>
</object>
<packing>
<property name="pack_type">end</property>
<property name="position">5</property>
</packing>
</child>
<child>
<object class="GtkToggleButton" id="filter_button">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Filter</property>
<signal name="toggled" handler="on_filter_toggled" swapped="no"/>
<child>
<object class="GtkImage" id="filter_button_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Filter</property>
<property name="stock">gtk-select-all</property>
</object>
</child>
<accelerator key="f" signal="clicked" modifiers="GDK_SHIFT_MASK | GDK_CONTROL_MASK"/>
</object>
<packing>
<property name="pack_type">end</property>
<property name="position">4</property>
</packing>
</child>
</object>
<child>
<placeholder/>
</child>
<child>
<object class="GtkBox" id="main_box">
@@ -452,6 +289,7 @@ Author: Dmitriy Yefremov
<object class="GtkFrame" id="stack_frame">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_top">5</property>
<property name="label_xalign">0.5</property>
<property name="shadow_type">none</property>
<child>
@@ -460,8 +298,7 @@ Author: Dmitriy Yefremov
<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="margin_bottom">5</property>
<property name="margin_top">10</property>
<signal name="notify::visible-child" handler="on_visible_page" swapped="no"/>
<child>
<object class="GtkBox" id="explorer_box">
@@ -512,49 +349,6 @@ Author: Dmitriy Yefremov
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkSearchBar" id="search_bar">
<property name="can_focus">False</property>
<property name="margin_top">1</property>
<property name="margin_bottom">1</property>
<child>
<object class="GtkSearchEntry" id="picons_search_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="primary_icon_name">edit-find-symbolic</property>
<property name="primary_icon_activatable">False</property>
<property name="primary_icon_sensitive">False</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkSearchBar" id="filter_bar">
<property name="can_focus">False</property>
<property name="margin_top">1</property>
<property name="margin_bottom">1</property>
<child>
<object class="GtkSearchEntry" id="picons_filter_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="primary_icon_stock">gtk-spell-check</property>
<property name="primary_icon_activatable">False</property>
<property name="primary_icon_sensitive">False</property>
<signal name="search-changed" handler="on_picons_filter_changed" swapped="no"/>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
<child>
<object class="GtkFrame" id="explorer_paths_frame">
<property name="visible">True</property>
@@ -569,6 +363,7 @@ Author: Dmitriy Yefremov
<property name="margin_right">5</property>
<property name="margin_top">5</property>
<property name="margin_bottom">5</property>
<property name="orientation">vertical</property>
<property name="wide_handle">True</property>
<child>
<object class="GtkBox" id="src_picons_box">
@@ -580,10 +375,33 @@ Author: Dmitriy Yefremov
<object class="GtkBox" id="src_title_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child type="center">
<object class="GtkLabel" id="explorer_src_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Source:</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
<child>
<object class="GtkGrid" id="src_title_grid">
<property name="can_focus">False</property>
<property name="column_spacing">2</property>
<child>
<object class="GtkLabel" id="src_filter_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Filter</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkCheckButton" id="src_filter_button">
<property name="visible">True</property>
@@ -594,17 +412,6 @@ Author: Dmitriy Yefremov
<property name="draw_indicator">True</property>
<signal name="toggled" handler="on_fiter_srcs_toggled" object="picons_src_filter_model" swapped="no"/>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="src_filter_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Filter</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">0</property>
@@ -614,21 +421,10 @@ Author: Dmitriy Yefremov
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack_type">end</property>
<property name="position">0</property>
</packing>
</child>
<child type="center">
<object class="GtkLabel" id="explorer_src_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Source:</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
@@ -917,8 +713,8 @@ Author: Dmitriy Yefremov
<property name="spacing">10</property>
<child>
<object class="GtkImage" id="picon_info_image">
<property name="width_request">128</property>
<property name="height_request">72</property>
<property name="width_request">100</property>
<property name="height_request">60</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-missing-image</property>
@@ -935,6 +731,7 @@ Author: Dmitriy Yefremov
<object class="GtkLabel" id="picon_info_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="ellipsize">end</property>
</object>
<packing>
<property name="expand">False</property>
@@ -964,6 +761,49 @@ Author: Dmitriy Yefremov
<property name="position">6</property>
</packing>
</child>
<child>
<object class="GtkSearchBar" id="search_bar">
<property name="can_focus">False</property>
<property name="margin_top">1</property>
<property name="margin_bottom">1</property>
<child>
<object class="GtkSearchEntry" id="picons_search_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="primary_icon_name">edit-find-symbolic</property>
<property name="primary_icon_activatable">False</property>
<property name="primary_icon_sensitive">False</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">7</property>
</packing>
</child>
<child>
<object class="GtkSearchBar" id="filter_bar">
<property name="can_focus">False</property>
<property name="margin_top">1</property>
<property name="margin_bottom">1</property>
<child>
<object class="GtkSearchEntry" id="picons_filter_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="primary_icon_name">edit-find-replace-symbolic</property>
<property name="primary_icon_activatable">False</property>
<property name="primary_icon_sensitive">False</property>
<signal name="search-changed" handler="on_picons_filter_changed" swapped="no"/>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">8</property>
</packing>
</child>
</object>
<packing>
<property name="name">explorer</property>
@@ -993,7 +833,7 @@ Author: Dmitriy Yefremov
<property name="wide_handle">True</property>
<child>
<object class="GtkBox" id="satellites_box">
<property name="width_request">200</property>
<property name="width_request">180</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_right">2</property>
@@ -1118,7 +958,6 @@ Author: Dmitriy Yefremov
</child>
<child>
<object class="GtkBox" id="proveders_pox">
<property name="width_request">280</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_left">2</property>
@@ -1410,7 +1249,7 @@ Author: Dmitriy Yefremov
<property name="halign">center</property>
<child>
<object class="GtkRadioButton" id="enigma2_radio_button">
<property name="label" translatable="yes">Enigma2 (default)</property>
<property name="label" translatable="yes">Enigma2</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
@@ -1478,7 +1317,7 @@ Author: Dmitriy Yefremov
<property name="halign">center</property>
<child>
<object class="GtkRadioButton" id="resize_no_radio_button">
<property name="label" translatable="yes">No(default)</property>
<property name="label" translatable="yes">No</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
@@ -1676,8 +1515,12 @@ Author: Dmitriy Yefremov
</child>
</object>
</child>
<child type="label_item">
<placeholder/>
<child type="label">
<object class="GtkStackSwitcher" id="sctack">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stack">stack</property>
</object>
</child>
</object>
<packing>
@@ -1686,14 +1529,220 @@ Author: Dmitriy Yefremov
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkBox" id="action_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">center</property>
<property name="valign">center</property>
<property name="margin_left">15</property>
<property name="margin_right">15</property>
<property name="margin_top">10</property>
<property name="margin_bottom">10</property>
<child>
<object class="GtkButtonBox" id="explorer_action_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="layout_style">expand</property>
<child>
<object class="GtkButton" id="download_button">
<property name="label" translatable="yes">Receive</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Download from the receiver</property>
<property name="image">receive_image</property>
<property name="always_show_image">True</property>
<signal name="clicked" handler="on_download" swapped="no"/>
<signal name="drag-data-received" handler="on_download_button_drag_data_received" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
<property name="secondary">True</property>
</packing>
</child>
<child>
<object class="GtkButton" id="send_button">
<property name="label" translatable="yes">Send</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Transfer to receiver</property>
<property name="image">send_image</property>
<property name="always_show_image">True</property>
<signal name="clicked" handler="on_send" swapped="no"/>
<signal name="drag-data-received" handler="on_send_button_drag_data_received" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="remove_button">
<property name="label" translatable="yes">Remove</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Remove all picons from the receiver</property>
<property name="image">remove_image</property>
<property name="always_show_image">True</property>
<signal name="clicked" handler="on_remove" swapped="no"/>
<signal name="drag-data-received" handler="on_remove_button_drag_data_received" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">4</property>
</packing>
</child>
<child>
<object class="GtkToggleButton" id="filter_button">
<property name="label" translatable="yes">Filter</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Filter</property>
<property name="image">filter_image</property>
<property name="always_show_image">True</property>
<signal name="toggled" handler="on_filter_toggled" swapped="no"/>
<accelerator key="f" signal="clicked" modifiers="GDK_SHIFT_MASK | Primary"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">5</property>
</packing>
</child>
<child>
<object class="GtkToggleButton" id="info_toggle_button">
<property name="label" translatable="yes">Details</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="image">info_toggle_button_image</property>
<property name="always_show_image">True</property>
<accelerator key="i" signal="clicked" modifiers="Primary"/>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="pack_type">end</property>
<property name="position">5</property>
<property name="secondary">True</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButtonBox" id="downloader_action_box">
<property name="can_focus">False</property>
<property name="layout_style">expand</property>
<child>
<object class="GtkButton" id="cancel_button">
<property name="label" translatable="yes">Cancel</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Cancel</property>
<property name="valign">center</property>
<property name="image">cancel_image</property>
<property name="always_show_image">True</property>
<signal name="clicked" handler="on_cancel" swapped="no"/>
<accelerator key="z" signal="clicked" modifiers="Primary"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="load_providers_button">
<property name="label" translatable="yes">Load providers</property>
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="tooltip_text" translatable="yes">Load providers</property>
<property name="valign">center</property>
<property name="image">load_providers</property>
<property name="always_show_image">True</property>
<signal name="clicked" handler="on_load_providers" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkButton" id="receive_button">
<property name="label" translatable="yes">Receive picons</property>
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="tooltip_text" translatable="yes">Receive picons</property>
<property name="valign">center</property>
<property name="image">receive_picons_image</property>
<property name="always_show_image">True</property>
<signal name="clicked" handler="on_receive" swapped="no"/>
</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">1</property>
</packing>
</child>
<child>
<object class="GtkButton" id="convert_button">
<property name="label" translatable="yes">Convert</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="tooltip_text" translatable="yes">Convert</property>
<property name="valign">center</property>
<property name="image">convert_image</property>
<property name="always_show_image">True</property>
<signal name="clicked" handler="on_convert" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkExpander" id="expander">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="resize_toplevel">True</property>
<child>
<object class="GtkScrolledWindow" id="scrolled_window">
<property name="height_request">150</property>
<property name="height_request">100</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="shadow_type">in</property>
@@ -1720,7 +1769,7 @@ Author: Dmitriy Yefremov
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
<property name="position">3</property>
</packing>
</child>
<child>
@@ -1777,7 +1826,7 @@ Author: Dmitriy Yefremov
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
<property name="position">4</property>
</packing>
</child>
</object>

View File

@@ -14,9 +14,9 @@ from app.settings import SettingsType, Settings
from app.tools.picons import PiconsParser, parse_providers, Provider, convert_to
from app.tools.satellites import SatellitesParser, SatelliteSource
from .dialogs import show_dialog, DialogType, get_message
from .main_helper import (update_entry_data, append_text_to_tview, scroll_to, on_popup_menu, get_base_model, set_picon,
get_picon_pixbuf)
from .uicommons import Gtk, Gdk, UI_RESOURCES_PATH, TV_ICON, Column, KeyboardKey
from .main_helper import update_entry_data, append_text_to_tview, scroll_to, on_popup_menu, get_base_model, set_picon, \
get_picon_pixbuf
from .uicommons import Gtk, Gdk, UI_RESOURCES_PATH, TV_ICON, Column, GTK_PATH, KeyboardKey
class PiconsDialog:
@@ -103,10 +103,8 @@ class PiconsDialog:
self._picons_entry = builder.get_object("picons_entry")
self._url_entry = builder.get_object("url_entry")
self._picons_dir_entry = builder.get_object("picons_dir_entry")
self._info_bar = builder.get_object("info_bar")
self._info_bar = builder.get_object("info_bar")
self._message_label = builder.get_object("info_bar_message_label")
self._info_check_button = builder.get_object("info_check_button")
self._info_toggle_button = builder.get_object("info_toggle_button")
self._picon_info_image = builder.get_object("picon_info_image")
self._picon_info_label = builder.get_object("picon_info_label")
self._load_providers_button = builder.get_object("load_providers_button")
@@ -124,24 +122,24 @@ class PiconsDialog:
self._resize_220_132_radio_button = builder.get_object("resize_220_132_radio_button")
self._resize_100_60_radio_button = builder.get_object("resize_100_60_radio_button")
self._satellite_label = builder.get_object("satellite_label")
self._header_download_box = builder.get_object("header_download_box")
self._explorer_action_box = builder.get_object("explorer_action_box")
self._satellite_label.bind_property("visible", builder.get_object("loading_data_label"), "visible", 4)
self._satellite_label.bind_property("visible", builder.get_object("loading_data_spinner"), "visible", 4)
self._cancel_button.bind_property("visible", self._header_download_box, "visible", 4)
self._convert_button.bind_property("visible", self._header_download_box, "visible", 4)
self._load_providers_button.bind_property("visible", self._receive_button, "visible")
self._cancel_button.bind_property("visible", builder.get_object("receive_button"), "visible", 4)
self._cancel_button.bind_property("visible", self._load_providers_button, "visible", 4)
self._convert_button.bind_property("visible", self._explorer_action_box, "visible", 4)
downloader_action_box = builder.get_object("downloader_action_box")
self._explorer_action_box.bind_property("visible", downloader_action_box, "visible", 4)
self._convert_button.bind_property("visible", downloader_action_box, "visible", 4)
self._filter_bar.bind_property("search-mode-enabled", self._filter_bar, "visible")
self._explorer_src_path_button.bind_property("sensitive", builder.get_object("picons_view_sw"), "sensitive")
self._filter_button.bind_property("active", builder.get_object("filter_service_box"), "visible")
self._filter_button.bind_property("active", builder.get_object("src_title_grid"), "visible")
self._filter_button.bind_property("active", builder.get_object("dst_title_grid"), "visible")
self._filter_button.bind_property("visible", self._info_check_button, "visible")
self._filter_button.bind_property("visible", self._send_button, "visible")
self._filter_button.bind_property("visible", self._download_button, "visible")
self._filter_button.bind_property("visible", self._remove_button, "visible")
self._filter_button.bind_property("visible", self._info_toggle_button, "visible")
explorer_info_bar = builder.get_object("explorer_info_bar")
explorer_info_bar.bind_property("visible", builder.get_object("explorer_info_bar_frame"), "visible")
self._info_check_button.bind_property("active", explorer_info_bar, "visible")
self._info_toggle_button.bind_property("active", explorer_info_bar, "visible")
# Init drag-and-drop
self.init_drag_and_drop()
# Style
@@ -265,8 +263,9 @@ class PiconsDialog:
def on_picons_view_drag_data_get(self, view, drag_context, data, info, time):
model, path = view.get_selection().get_selected_rows()
if path:
data.set_uris([Path(model[path][-1]).as_uri(),
Path(self._explorer_dest_path_button.get_filename()).as_uri()])
p_uri = Path(model[path][-1]).as_uri()
dest_uri = Path(self._explorer_dest_path_button.get_filename()).as_uri()
data.set_uris(["{}::::{}".format(p_uri, dest_uri)])
def on_picons_src_view_drag_drop(self, view, drag_context, x, y, time):
view.stop_emission_by_name("drag_drop")
@@ -341,10 +340,11 @@ class PiconsDialog:
return
uris = data.get_uris()
if len(uris) == 2:
if uris:
name, fav_id = self._current_picon_info
src = urlparse(unquote(uris[0])).path
dst = "{}/{}".format(urlparse(unquote(uris[1])).path, name)
src, sep, dst = uris[0].partition("::::")
src = urlparse(unquote(src)).path
dst = "{}/{}".format(urlparse(unquote(dst)).path, name)
if src != dst:
shutil.copy(src, dst)
for row in get_base_model(self._picons_dest_view.get_model()):
@@ -357,7 +357,7 @@ class PiconsDialog:
def on_send_button_drag_data_received(self, button, drag_context, x, y, data, info, time):
path = self.get_path_from_uris(data)
if path:
if path and show_dialog(DialogType.QUESTION, self._dialog) == Gtk.ResponseType.OK:
self.on_send(files_filter={path.name}, path=path.parent)
def on_download_button_drag_data_received(self, button, drag_context, x, y, data, info, time):
@@ -372,8 +372,9 @@ class PiconsDialog:
def get_path_from_uris(self, data):
uris = data.get_uris()
if len(uris) == 2:
return Path(urlparse(unquote(uris[0])).path).resolve()
if uris:
src, sep, dst = uris[0].partition("::::")
return Path(urlparse(unquote(src)).path).resolve()
def update_picon_in_lists(self, dst, fav_id):
picon = get_picon_pixbuf(dst)
@@ -385,7 +386,7 @@ class PiconsDialog:
def on_selective_send(self, view):
path = self.get_selected_path(view)
if path:
if path and show_dialog(DialogType.QUESTION, self._dialog) == Gtk.ResponseType.OK:
self.on_send(files_filter={path.name}, path=path.parent)
def on_selective_download(self, view):
@@ -438,7 +439,7 @@ class PiconsDialog:
files_filter=files_filter), True)
def on_remove(self, item=None, files_filter=None):
if show_dialog(DialogType.QUESTION, self._dialog) == Gtk.ResponseType.CANCEL:
if show_dialog(DialogType.QUESTION, self._dialog) != Gtk.ResponseType.OK:
return
self.run_func(lambda: remove_picons(settings=self._settings,
@@ -500,7 +501,8 @@ class PiconsDialog:
url = self._url_entry.get_text()
try:
self._current_process = subprocess.Popen(["wget", "-pkP", self._TMP_DIR, url],
exe = "{}wget".format("./" if GTK_PATH else "")
self._current_process = subprocess.Popen([exe, "-pkP", self._TMP_DIR, url],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
universal_newlines=True)
@@ -563,10 +565,10 @@ class PiconsDialog:
return
self.process_provider(Provider(*prv))
if not self._resize_no_radio_button.get_active():
if self._resize_no_radio_button.get_active():
self.resize(self._picons_dir_entry.get_text())
else:
self.show_info_message(get_message("Done!"), Gtk.MessageType.INFO)
self.show_info_message(get_message("Done!"), Gtk.MessageType.INFO)
finally:
GLib.idle_add(self._cancel_button.hide)
self._terminate = False
@@ -574,7 +576,8 @@ class PiconsDialog:
def process_provider(self, prv):
url = prv.url
self.show_info_message(get_message("Please, wait..."), Gtk.MessageType.INFO)
self._current_process = subprocess.Popen(["wget", "-pkP", self._TMP_DIR, url],
exe = "{}wget".format("./" if GTK_PATH else "")
self._current_process = subprocess.Popen([exe, "-pkP", self._TMP_DIR, url],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
universal_newlines=True)
@@ -595,24 +598,16 @@ class PiconsDialog:
def append_output(self, char):
append_text_to_tview(char, self._text_view)
@run_task
def resize(self, path):
self.show_info_message(get_message("Resizing..."), Gtk.MessageType.INFO)
exe = "{}mogrify".format("./" if GTK_PATH else "")
is_220_132 = self._resize_220_132_radio_button.get_active()
command = "{} -resize {}! *.png".format(exe, "220x132" if is_220_132 else "100x60").split()
try:
from pathlib import Path
from PIL import Image
except ImportError as e:
self.show_info_message("{} {}".format(get_message("Conversion error."), e), Gtk.MessageType.ERROR)
else:
res = (220, 132) if self._resize_220_132_radio_button.get_active() else (100, 60)
for img_file in Path(path).glob("*.png"):
img = Image.open(img_file)
img = img.resize(res, Image.ANTIALIAS)
img.save(img_file, "PNG", optimize=True)
self.show_info_message(get_message("Done!"), Gtk.MessageType.INFO)
self._current_process = subprocess.Popen(command, universal_newlines=True, cwd=path)
self._current_process.wait()
except FileNotFoundError as e:
self.show_info_message("Conversion error. " + str(e), Gtk.MessageType.ERROR)
def on_cancel(self, item=None):
if self.is_task_running() and show_dialog(DialogType.QUESTION, self._dialog) == Gtk.ResponseType.CANCEL:
@@ -653,12 +648,12 @@ class PiconsDialog:
def run_func(self, func, update=False):
try:
GLib.idle_add(self._expander.set_expanded, True)
GLib.idle_add(self._header_download_box.set_sensitive, False)
GLib.idle_add(self._explorer_action_box.set_sensitive, False)
func()
except OSError as e:
self.show_info_message(str(e), Gtk.MessageType.ERROR)
finally:
GLib.idle_add(self._header_download_box.set_sensitive, True)
GLib.idle_add(self._explorer_action_box.set_sensitive, True)
if update:
self.on_picons_dest_changed(self._explorer_dest_path_button)
@@ -737,7 +732,7 @@ class PiconsDialog:
map(lambda s: s.picon_id, filter(lambda s: txt in s.service.upper(), self._app.current_services.values())))
def on_picon_activated(self, view):
if self._info_check_button.get_active():
if self._info_toggle_button.get_active():
model, path = view.get_selection().get_selected_rows()
if not path:
return
@@ -787,9 +782,8 @@ class PiconsDialog:
def on_visible_page(self, stack: Gtk.Stack, param):
name = stack.get_visible_child_name()
self._convert_button.set_visible(name == "converter")
self._load_providers_button.set_visible(name == "downloader")
is_explorer = name == "explorer"
self._filter_button.set_visible(is_explorer)
self._explorer_action_box.set_visible(is_explorer)
if is_explorer:
self.on_picons_dest_changed(self._explorer_dest_path_button)

File diff suppressed because it is too large Load Diff

View File

@@ -48,7 +48,8 @@ class SatellitesDialog:
builder.set_translation_domain(TEXT_DOMAIN)
builder.add_objects_from_string(get_dialogs_string(_UI_PATH),
("satellites_editor_window", "satellites_tree_store", "popup_menu",
"left_header_menu", "popup_menu_add_image", "popup_menu_add_image_2"))
"left_header_menu", "popup_menu_add_image", "popup_menu_add_image_2",
"sat_editor_save_image", "sat_editor_update_image"))
builder.connect_signals(handlers)
self._window = builder.get_object("satellites_editor_window")
@@ -456,7 +457,8 @@ class SatellitesUpdateDialog:
("satellites_update_window", "update_source_store", "update_sat_list_store",
"update_sat_list_model_filter", "update_sat_list_model_sort", "side_store",
"pos_adjustment", "pos_adjustment2", "satellites_update_popup_menu",
"remove_selection_image"))
"remove_selection_image", "sat_update_cancel_image", "sat_receive_image",
"sat_update_filter_image", "sat_update_search_image", "sat_update_image"))
builder.connect_signals(handlers)
self._window = builder.get_object("satellites_update_window")

View File

@@ -43,6 +43,19 @@
</row>
</data>
</object>
<object class="GtkComboBox" id="rate_lp_combo_box">
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">False</property>
<property name="model">fec_list_store</property>
<property name="id_column">0</property>
<child>
<object class="GtkCellRendererText" id="rate_lp_cellrenderertext"/>
<attributes>
<attribute name="text">0</attribute>
</attributes>
</child>
</object>
<object class="GtkListStore" id="invertion_list_store">
<columns>
<!-- column-name invertion -->
@@ -217,19 +230,6 @@
</row>
</data>
</object>
<object class="GtkComboBox" id="rate_lp_combo_box">
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">False</property>
<property name="model">fec_list_store</property>
<property name="id_column">0</property>
<child>
<object class="GtkCellRendererText" id="rate_lp_cellrenderertext"/>
<attributes>
<attribute name="text">0</attribute>
</attributes>
</child>
</object>
<object class="GtkDialog" id="service_details_dialog">
<property name="use-header-bar">{use_header}</property>
<property name="can_focus">False</property>
@@ -246,40 +246,6 @@
<child type="titlebar">
<placeholder/>
</child>
<child type="action">
<object class="GtkButton" id="cancel_button">
<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="tooltip_text" translatable="yes">Cancel</property>
<property name="use_stock">True</property>
<property name="always_show_image">True</property>
</object>
</child>
<child type="action">
<object class="GtkButton" id="apply_button">
<property name="label">gtk-save</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Save current service</property>
<property name="use_stock">True</property>
<property name="always_show_image">True</property>
<signal name="clicked" handler="on_save" swapped="no"/>
</object>
</child>
<child type="action">
<object class="GtkButton" id="create_button">
<property name="label">gtk-new</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Create and save as new service</property>
<property name="use_stock">True</property>
<property name="always_show_image">True</property>
<signal name="clicked" handler="on_create_new" swapped="no"/>
</object>
</child>
<child internal-child="vbox">
<object class="GtkBox" id="dialog_vbox">
<property name="can_focus">False</property>
@@ -290,6 +256,54 @@
<child internal-child="action_area">
<object class="GtkButtonBox">
<property name="can_focus">False</property>
<property name="valign">center</property>
<property name="layout_style">end</property>
<child>
<object class="GtkButton" id="cancel_button">
<property name="label" translatable="yes">Cancel</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="valign">center</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="apply_button">
<property name="label" translatable="yes">Apply</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Save current service</property>
<property name="valign">center</property>
<signal name="clicked" handler="on_save" swapped="no"/>
<accelerator key="Return" signal="activate"/>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkButton" id="create_button">
<property name="label" translatable="yes">Create</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Create and save as new service</property>
<property name="valign">center</property>
<signal name="clicked" handler="on_create_new" swapped="no"/>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
@@ -335,7 +349,7 @@
<object class="GtkEntry" id="name_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="primary_icon_stock">gtk-edit</property>
<property name="primary_icon_name">document-edit-symbolic</property>
</object>
<packing>
<property name="left_attach">0</property>
@@ -357,7 +371,7 @@
<object class="GtkEntry" id="package_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="primary_icon_stock">gtk-edit</property>
<property name="primary_icon_name">document-edit-symbolic</property>
</object>
<packing>
<property name="left_attach">1</property>
@@ -381,7 +395,7 @@
<property name="can_focus">True</property>
<property name="width_chars">10</property>
<property name="max_width_chars">10</property>
<property name="primary_icon_stock">gtk-edit</property>
<property name="primary_icon_name">document-edit-symbolic</property>
<signal name="changed" handler="on_non_empty_entry_changed" swapped="no"/>
<signal name="key-release-event" handler="update_reference" swapped="no"/>
</object>
@@ -426,7 +440,7 @@
<property name="can_focus">True</property>
<property name="width_chars">7</property>
<property name="max_width_chars">7</property>
<property name="primary_icon_stock">gtk-edit</property>
<property name="primary_icon_name">document-edit-symbolic</property>
<signal name="changed" handler="on_non_empty_entry_changed" swapped="no"/>
<signal name="changed" handler="update_reference" swapped="no"/>
</object>
@@ -864,7 +878,7 @@
<property name="tooltip_text">C:0000,C:a1b2,etc.</property>
<property name="width_chars">15</property>
<property name="max_width_chars">26</property>
<property name="primary_icon_stock">gtk-edit</property>
<property name="primary_icon_name">document-edit-symbolic</property>
<property name="placeholder_text" translatable="yes">C:0000,C:a1b2,etc.</property>
<signal name="changed" handler="on_cas_entry_changed" swapped="no"/>
</object>
@@ -967,7 +981,7 @@
<property name="can_focus">True</property>
<property name="width_chars">12</property>
<property name="max_width_chars">12</property>
<property name="primary_icon_stock">gtk-edit</property>
<property name="primary_icon_name">document-edit-symbolic</property>
<signal name="changed" handler="on_non_empty_entry_changed" swapped="no"/>
</object>
<packing>
@@ -993,7 +1007,7 @@
<property name="can_focus">True</property>
<property name="width_chars">12</property>
<property name="max_width_chars">12</property>
<property name="primary_icon_stock">gtk-edit</property>
<property name="primary_icon_name">document-edit-symbolic</property>
<signal name="changed" handler="on_non_empty_entry_changed" swapped="no"/>
</object>
<packing>
@@ -1072,7 +1086,7 @@
<property name="can_focus">True</property>
<property name="width_chars">12</property>
<property name="max_width_chars">12</property>
<property name="primary_icon_stock">gtk-edit</property>
<property name="primary_icon_name">document-edit-symbolic</property>
<signal name="changed" handler="on_non_empty_entry_changed" swapped="no"/>
<signal name="key-release-event" handler="update_reference" swapped="no"/>
</object>
@@ -1125,7 +1139,7 @@
<property name="can_focus">True</property>
<property name="width_chars">8</property>
<property name="max_width_chars">10</property>
<property name="primary_icon_stock">gtk-edit</property>
<property name="primary_icon_name">document-edit-symbolic</property>
<signal name="changed" handler="on_non_empty_entry_changed" swapped="no"/>
<signal name="key-release-event" handler="update_reference" swapped="no"/>
</object>
@@ -1152,7 +1166,7 @@
<property name="can_focus">True</property>
<property name="width_chars">8</property>
<property name="max_width_chars">10</property>
<property name="primary_icon_stock">gtk-edit</property>
<property name="primary_icon_name">document-edit-symbolic</property>
<signal name="changed" handler="on_non_empty_entry_changed" swapped="no"/>
<signal name="key-release-event" handler="update_reference" swapped="no"/>
</object>
@@ -1317,7 +1331,7 @@
<property name="can_focus">True</property>
<property name="width_chars">8</property>
<property name="max_width_chars">10</property>
<property name="primary_icon_stock">gtk-edit</property>
<property name="primary_icon_name">document-edit-symbolic</property>
<signal name="changed" handler="on_digit_entry_changed" swapped="no"/>
</object>
<packing>
@@ -1343,7 +1357,7 @@
<property name="can_focus">True</property>
<property name="width_chars">8</property>
<property name="max_width_chars">10</property>
<property name="primary_icon_stock">gtk-edit</property>
<property name="primary_icon_name">document-edit-symbolic</property>
<signal name="changed" handler="on_digit_entry_changed" swapped="no"/>
</object>
<packing>
@@ -1369,7 +1383,7 @@
<property name="can_focus">True</property>
<property name="width_chars">8</property>
<property name="max_width_chars">10</property>
<property name="primary_icon_stock">gtk-edit</property>
<property name="primary_icon_name">document-edit-symbolic</property>
<signal name="changed" handler="on_digit_entry_changed" swapped="no"/>
</object>
<packing>
@@ -1498,7 +1512,7 @@
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_left">10</property>
<property name="stock">gtk-edit</property>
<property name="icon_name">document-edit-symbolic</property>
</object>
<packing>
<property name="expand">False</property>
@@ -1562,26 +1576,6 @@
<child>
<placeholder/>
</child>
<child type="action">
<object class="GtkButton" id="tr_services_no_button">
<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>
<property name="always_show_image">True</property>
</object>
</child>
<child type="action">
<object class="GtkButton" id="tr_services_ok_button">
<property name="label">gtk-ok</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
<property name="always_show_image">True</property>
</object>
</child>
<child internal-child="vbox">
<object class="GtkBox" id="tr_services_dialog_vbox">
<property name="can_focus">False</property>
@@ -1590,6 +1584,35 @@
<child internal-child="action_area">
<object class="GtkButtonBox">
<property name="can_focus">False</property>
<property name="valign">center</property>
<child>
<object class="GtkButton" id="tr_services_no_button">
<property name="label" translatable="yes">Cancel</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="valign">center</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="tr_services_ok_button">
<property name="label" translatable="yes">OK</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="valign">center</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
@@ -1616,7 +1639,7 @@
<property name="margin_right">20</property>
<property name="margin_top">5</property>
<property name="margin_bottom">5</property>
<property name="label" translatable="yes">Changes will be applied to all services of this transponder!
<property name="label" translatable="yes">Changes will be applied to all services of this transponder!
Continue?</property>
<property name="justify">center</property>
<property name="lines">2</property>

View File

@@ -1,16 +1,15 @@
import os
import re
import os
from app.commons import run_idle
from app.eparser import Service
from app.eparser.ecommons import (MODULATION, Inversion, ROLL_OFF, Pilot, Flag, Pids, POLARIZATION, get_key_by_value,
get_value_by_name, FEC_DEFAULT, PLS_MODE, SERVICE_TYPE, T_MODULATION, C_MODULATION,
TrType, SystemCable, T_SYSTEM, BANDWIDTH, TRANSMISSION_MODE, GUARD_INTERVAL, T_FEC,
HIERARCHY)
from app.eparser.ecommons import MODULATION, Inversion, ROLL_OFF, Pilot, Flag, Pids, POLARIZATION, \
get_key_by_value, get_value_by_name, FEC_DEFAULT, PLS_MODE, SERVICE_TYPE, T_MODULATION, C_MODULATION, TrType, \
SystemCable, T_SYSTEM, BANDWIDTH, TRANSMISSION_MODE, GUARD_INTERVAL, HIERARCHY, T_FEC
from app.settings import SettingsType
from .uicommons import Gtk, Gdk, UI_RESOURCES_PATH, HIDE_ICON, TEXT_DOMAIN, CODED_ICON, Column, IS_GNOME_SESSION
from .dialogs import show_dialog, DialogType, Action, get_dialogs_string
from .main_helper import get_base_model
from .uicommons import Gtk, Gdk, UI_RESOURCES_PATH, HIDE_ICON, TEXT_DOMAIN, CODED_ICON, Column, IS_GNOME_SESSION
_UI_PATH = UI_RESOURCES_PATH + "service_details_dialog.glade"
@@ -439,17 +438,14 @@ class ServiceDetailsDialog:
def update_fav_view(self, old_service, new_service):
model = self._fav_view.get_model()
for row in filter(lambda r: old_service.fav_id == r[7], model):
itr = row.iter
if not model.get_value(itr, Column.FAV_BACKGROUND):
model.set_value(itr, Column.FAV_SERVICE, new_service.service)
model.set(itr, {Column.FAV_CODED: new_service.coded,
Column.FAV_LOCKED: new_service.locked,
Column.FAV_HIDE: new_service.hide,
Column.FAV_TYPE: new_service.service_type,
Column.FAV_POS: new_service.pos,
Column.FAV_ID: new_service.fav_id,
Column.FAV_PICON: new_service.picon})
model.set(row.iter, {1: new_service.coded,
2: new_service.service,
3: new_service.locked,
4: new_service.hide,
5: new_service.service_type,
6: new_service.pos,
7: new_service.fav_id,
8: new_service.picon})
def update_picon_name(self, old_name, new_name):
if not os.path.isdir(self._picons_dir_path):

File diff suppressed because it is too large Load Diff

View File

@@ -36,7 +36,6 @@ class SettingsDialog:
"on_set_color_switch": self.on_set_color_switch,
"on_force_bq_name": self.on_force_bq_name,
"on_http_mode_switch": self.on_http_mode_switch,
"on_experimental_switch": self.on_experimental_switch,
"on_yt_dl_switch": self.on_yt_dl_switch,
"on_default_path_mode_switch": self.on_default_path_mode_switch,
"on_default_data_path_changed": self.on_default_data_path_changed,
@@ -114,7 +113,6 @@ class SettingsDialog:
self._support_ver5_switch = builder.get_object("support_ver5_switch")
self._force_bq_name_switch = builder.get_object("force_bq_name_switch")
# Streaming
header_separator = builder.get_object("header_separator")
self._apply_presets_button = builder.get_object("apply_presets_button")
self._transcoding_switch = builder.get_object("transcoding_switch")
self._edit_preset_switch = builder.get_object("edit_preset_switch")
@@ -126,7 +124,6 @@ class SettingsDialog:
self._audio_channels_combo_box = builder.get_object("audio_channels_combo_box")
self._audio_sample_rate_combo_box = builder.get_object("audio_sample_rate_combo_box")
self._audio_codec_combo_box = builder.get_object("audio_codec_combo_box")
self._apply_presets_button.bind_property("visible", header_separator, "visible")
self._transcoding_switch.bind_property("active", builder.get_object("record_box"), "sensitive")
self._edit_preset_switch.bind_property("active", self._apply_presets_button, "sensitive")
self._edit_preset_switch.bind_property("active", builder.get_object("video_options_frame"), "sensitive")
@@ -137,7 +134,8 @@ class SettingsDialog:
# Program
self._before_save_switch = builder.get_object("before_save_switch")
self._before_downloading_switch = builder.get_object("before_downloading_switch")
self._enable_experimental_box = builder.get_object("enable_experimental_box")
self._program_frame = builder.get_object("program_frame")
self._extra_support_grid = builder.get_object("extra_support_grid")
self._colors_grid = builder.get_object("colors_grid")
self._set_color_switch = builder.get_object("set_color_switch")
self._new_color_button = builder.get_object("new_color_button")
@@ -158,24 +156,15 @@ class SettingsDialog:
self._click_mode_zap_and_play_button = builder.get_object("click_mode_zap_and_play_button")
self._click_mode_zap_button.bind_property("sensitive", self._click_mode_play_button, "sensitive")
self._click_mode_zap_button.bind_property("sensitive", self._click_mode_zap_and_play_button, "sensitive")
# EXPERIMENTAL
self._enable_exp_switch = builder.get_object("enable_experimental_switch")
self._enable_exp_switch.bind_property("active", builder.get_object("yt_dl_box"), "sensitive")
self._click_mode_zap_button.bind_property("sensitive", self._enable_send_to_switch, "sensitive")
self._enable_send_to_switch.bind_property("sensitive", builder.get_object("enable_send_to_label"), "sensitive")
self._extra_support_grid.bind_property("sensitive", builder.get_object("v5_support_grid"), "sensitive")
self._enable_yt_dl_switch.bind_property("active", builder.get_object("yt_dl_update_box"), "sensitive")
self._enable_exp_switch.bind_property("active", builder.get_object("v5_support_box"), "sensitive")
self._enable_exp_switch.bind_property("active", builder.get_object("enable_direct_playback_box"), "sensitive")
# Enigma2 only
self._enigma_radio_button.bind_property("active", builder.get_object("bq_naming_grid"), "sensitive")
self._enigma_radio_button.bind_property("active", builder.get_object("enable_http_box"), "sensitive")
self._enigma_radio_button.bind_property("active", builder.get_object("enable_experimental_box"), "sensitive")
self._enigma_radio_button.bind_property("active", builder.get_object("program_frame"), "sensitive")
self._enigma_radio_button.bind_property("active", builder.get_object("experimental_box"), "sensitive")
# Profiles
self._profile_view = builder.get_object("profile_tree_view")
self._profile_add_button = builder.get_object("profile_add_button")
self._profile_remove_button = builder.get_object("profile_remove_button")
self._apply_profile_button = builder.get_object("apply_profile_button")
self._apply_profile_button.bind_property("visible", header_separator, "visible")
self._apply_profile_button.bind_property("visible", builder.get_object("reset_button"), "visible")
# Style
self._style_provider = Gtk.CssProvider()
@@ -195,7 +184,6 @@ class SettingsDialog:
self._theme_thumbnail_image = builder.get_object("theme_thumbnail_image")
self._theme_combo_box = builder.get_object("theme_combo_box")
self._icon_theme_combo_box = builder.get_object("icon_theme_combo_box")
self._dark_mode_switch = builder.get_object("dark_mode_switch")
self._themes_support_switch = builder.get_object("themes_support_switch")
self._themes_support_switch.bind_property("active", builder.get_object("gtk_theme_frame"), "sensitive")
self._themes_support_switch.bind_property("active", builder.get_object("icon_theme_frame"), "sensitive")
@@ -205,8 +193,10 @@ class SettingsDialog:
def init_ui_elements(self, s_type):
is_enigma_profile = s_type is SettingsType.ENIGMA_2
self._neutrino_radio_button.set_active(s_type is SettingsType.NEUTRINO_MP)
self.update_header_bar()
self.update_title()
self._settings_stack.get_child_by_name(Property.HTTP.value).set_visible(is_enigma_profile)
self._program_frame.set_sensitive(is_enigma_profile)
self._extra_support_grid.set_sensitive(is_enigma_profile)
http_active = self._support_http_api_switch.get_active()
self._click_mode_zap_button.set_sensitive(is_enigma_profile and http_active)
self._lang_combo_box.set_active_id(self._ext_settings.language)
@@ -224,12 +214,12 @@ class SettingsDialog:
self.on_profile_selected(self._profile_view, False)
self._profile_remove_button.set_sensitive(len(self._profile_view.get_model()) > 1)
def update_header_bar(self):
label, sep, st = self._header_bar.get_subtitle().partition(":")
def update_title(self):
title = "{} [{}]"
if self._s_type is SettingsType.ENIGMA_2:
self._header_bar.set_subtitle("{}: {}".format(label, self._enigma_radio_button.get_label()))
self._dialog.set_title(title.format(get_message("Options"), self._enigma_radio_button.get_label()))
elif self._s_type is SettingsType.NEUTRINO_MP:
self._header_bar.set_subtitle("{}: {}".format(label, self._neutrino_radio_button.get_label()))
self._dialog.set_title(title.format(get_message("Options"), self._neutrino_radio_button.get_label()))
def show(self):
self._dialog.run()
@@ -292,7 +282,6 @@ class SettingsDialog:
self.on_transcoding_preset_changed(self._presets_combo_box)
if self._s_type is SettingsType.ENIGMA_2:
self._enable_exp_switch.set_active(self._settings.is_enable_experimental)
self._support_ver5_switch.set_active(self._settings.v5_support)
self._force_bq_name_switch.set_active(self._settings.force_bq_names)
self._support_http_api_switch.set_active(self._settings.http_api_support)
@@ -360,13 +349,11 @@ class SettingsDialog:
self._ext_settings.active_preset = self._presets_combo_box.get_active_id()
if self._ext_settings.is_darwin:
self._ext_settings.dark_mode = self._dark_mode_switch.get_active()
self._ext_settings.is_themes_support = self._themes_support_switch.get_active()
self._ext_settings.theme = self._theme_combo_box.get_active_id()
self._ext_settings.icon_theme = self._icon_theme_combo_box.get_active_id()
if self._s_type is SettingsType.ENIGMA_2:
self._ext_settings.is_enable_experimental = self._enable_exp_switch.get_active()
self._ext_settings.use_colors = self._set_color_switch.get_active()
self._ext_settings.new_color = self._new_color_button.get_rgba().to_string()
self._ext_settings.extra_color = self._extra_color_button.get_rgba().to_string()
@@ -452,12 +439,6 @@ class SettingsDialog:
self._click_mode_zap_and_play_button.get_active())):
self._click_mode_disabled_button.set_active(True)
def on_experimental_switch(self, switch, state):
if not state:
self._support_ver5_switch.set_active(state)
self._enable_send_to_switch.set_active(state)
self._enable_yt_dl_switch.set_active(state)
def on_force_bq_name(self, switch, state):
if self._main_stack.get_visible_child_name() != "extra":
return
@@ -777,7 +758,6 @@ class SettingsDialog:
@run_idle
def init_appearance(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:

View File

@@ -1,15 +1,21 @@
#digit-entry {
border-color: Red;
border-width: 0.15em;
}
#status-bar-button {
padding: 1px;
margin: 1px;
margin: 0.1em;
}
#textview-large {
font-size: 14px;
}
.group {}
.group :first-child {
padding-left: 0.5em;
padding-right: 0.5em;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}

250
app/ui/telnet.glade Executable file
View File

@@ -0,0 +1,250 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.22.1
The MIT License (MIT)
Copyright (c) 2018-2020 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 domain="demon-editor">
<requires lib="gtk+" version="3.16"/>
<!-- interface-license-type mit -->
<!-- interface-name DemonEditor -->
<!-- interface-copyright 2018-2020 Dmitriy Yefremov -->
<!-- interface-authors Dmitriy Yefremov -->
<object class="GtkTextTagTable" id="tag_table">
<child type="tag">
<object class="GtkTextTag" id="end_tag">
<property name="font">Normal</property>
<property name="editable">False</property>
</object>
</child>
</object>
<object class="GtkTextBuffer" id="text_buffer">
<property name="tag_table">tag_table</property>
</object>
<object class="GtkWindow" id="dialog_window">
<property name="can_focus">False</property>
<property name="title" translatable="yes">DemonEditor [Telnet client]</property>
<property name="destroy_with_parent">True</property>
<property name="icon_name">terminal</property>
<property name="skip_taskbar_hint">True</property>
<property name="skip_pager_hint">True</property>
<signal name="delete-event" handler="on_close" swapped="no"/>
<child>
<placeholder/>
</child>
<child>
<object class="GtkBox" id="main_box">
<property name="width_request">560</property>
<property name="height_request">320</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<property name="spacing">2</property>
<child>
<object class="GtkScrolledWindow" id="telnet_scrolled_window">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="shadow_type">in</property>
<child>
<object class="GtkTextView" id="text_view">
<property name="name">textview-large</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="wrap_mode">char</property>
<property name="left_margin">5</property>
<property name="right_margin">5</property>
<property name="buffer">text_buffer</property>
<property name="overwrite">True</property>
<property name="input_hints">GTK_INPUT_HINT_WORD_COMPLETION | GTK_INPUT_HINT_NONE</property>
<property name="monospace">True</property>
<signal name="key-press-event" handler="on_view_key_press" swapped="no"/>
<signal name="realize" handler="on_text_view_realize" swapped="no"/>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkBox" id="commands_entry">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_left">5</property>
<property name="margin_right">5</property>
<property name="margin_bottom">2</property>
<property name="spacing">2</property>
<child>
<object class="GtkComboBoxText" id="profile_combo_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="active">0</property>
<property name="has_frame">False</property>
<signal name="changed" handler="on_profile_changed" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="connect_button">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Connect</property>
<signal name="clicked" handler="on_connect" swapped="no"/>
<child>
<object class="GtkImage" id="connect_button_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-connect</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkButton" id="disconnect_button">
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Disconnect</property>
<signal name="clicked" handler="on_disconnect" swapped="no"/>
<child>
<object class="GtkImage" id="disconnect_button_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-disconnect</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">4</property>
</packing>
</child>
<child type="center">
<placeholder/>
</child>
<child>
<object class="GtkButton" id="clear_button">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Clear</property>
<property name="halign">center</property>
<property name="valign">center</property>
<signal name="clicked" handler="on_clear" swapped="no"/>
<child>
<object class="GtkImage" id="clear_button_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-clear</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack_type">end</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkInfoBar" id="info_bar">
<property name="app_paintable">True</property>
<property name="can_focus">False</property>
<property name="spacing">2</property>
<property name="show_close_button">True</property>
<signal name="response" handler="on_info_bar_close" swapped="no"/>
<child internal-child="action_area">
<object class="GtkButtonBox">
<property name="can_focus">False</property>
<property name="layout_style">end</property>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child internal-child="content_area">
<object class="GtkBox">
<property name="can_focus">False</property>
<child>
<object class="GtkLabel" id="info_bar_message_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label">Info</property>
<property name="justify">center</property>
<property name="wrap">True</property>
<property name="wrap_mode">word-char</property>
<property name="lines">2</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
</child>
</object>
</interface>

256
app/ui/telnet.py Executable file
View File

@@ -0,0 +1,256 @@
import re
import selectors
import socket
from collections import deque
from telnetlib import Telnet
from gi.repository import GLib
from app.commons import run_task, run_idle, log
from app.settings import Settings
from app.ui.uicommons import Gtk, Gdk, UI_RESOURCES_PATH, KeyboardKey, MOD_MASK
class ExtTelnet(Telnet):
def __init__(self, output_callback, **kwargs):
super().__init__(**kwargs)
self._output_callback = output_callback
def interact(self):
"""Interaction function, emulates a very dumb telnet client."""
with selectors.DefaultSelector() as selector:
selector.register(self, selectors.EVENT_READ)
while True:
for key, events in selector.select():
if key.fileobj is self:
try:
text = self.read_very_eager()
except EOFError as e:
msg = "\n*** Connection closed by remote host ***\n"
self._output_callback(msg)
log(msg)
raise e
else:
if text:
self._output_callback(text)
class TelnetDialog:
""" Dialog of very simple telnet client. """
_COLOR_PATTERN = re.compile("\x1b.*?m") # Color info
_ERASING_PATTERN = re.compile("\x1b.*?K") # Erase to right
_APP_MODE_PATTERN = re.compile("\x1b.*?(1h)|(1l)") # h - on, l - off
_ALL_PATTERN = re.compile(r'(\x1b\[|\x9b)[0-?]*[@-~]')
_NOT_SUPPORTED = {"mc", "mcedit", "vi", "nano"}
def __init__(self, transient, settings):
self._handlers = {"on_profile_changed": self.on_profile_changed,
"on_clear": self.on_clear,
"on_text_view_realize": self.on_text_view_realize,
"on_view_key_press": self.on_view_key_press,
"on_info_bar_close": self.on_info_bar_close,
"on_connect": self.on_connect,
"on_disconnect": self.on_disconnect,
"on_close": self.on_close}
builder = Gtk.Builder()
builder.add_from_file(UI_RESOURCES_PATH + "telnet.glade")
builder.connect_signals(self._handlers)
self._dialog_window = builder.get_object("dialog_window")
self._dialog_window.set_transient_for(transient)
self._profile_combo_box = builder.get_object("profile_combo_box")
self._info_bar = builder.get_object("info_bar")
self._info_message_label = builder.get_object("info_bar_message_label")
self._text_view = builder.get_object("text_view")
self._buf = builder.get_object("text_buffer")
self._end_tag = builder.get_object("end_tag")
self._connect_button = builder.get_object("connect_button")
self._connect_button.bind_property("visible", builder.get_object("disconnect_button"), "visible", 4)
provider = Gtk.CssProvider()
provider.load_from_path(UI_RESOURCES_PATH + "style.css")
builder.get_object("main_box").get_style_context().add_provider(provider, Gtk.STYLE_PROVIDER_PRIORITY_USER)
window_size = settings.get("telnet_dialog_window_size")
if window_size:
self._dialog_window.resize(*window_size)
self._ext_settings = settings
self._settings = Settings(settings.settings)
self._tn = None
self._app_mode = False
self._commands = deque(maxlen=10)
def show(self):
self._dialog_window.show()
def on_close(self, window, event):
""" Performs shutdown tasks """
self._ext_settings.add("telnet_dialog_window_size", window.get_size())
self.on_disconnect()
def on_info_bar_close(self, bar=None, resp=None):
self._info_bar.set_visible(False)
@run_idle
def show_info_message(self, text, message_type):
self._info_bar.set_visible(True)
self._info_bar.set_message_type(message_type)
self._info_message_label.set_text(text)
def on_text_view_realize(self, view):
self.init_profiles()
self.on_connect()
@run_idle
def init_profiles(self):
for p in self._settings.profiles:
self._profile_combo_box.append(p, p)
self._profile_combo_box.set_active_id(self._settings.current_profile)
@run_task
def on_connect(self, item=None):
try:
GLib.idle_add(self._connect_button.set_visible, False)
GLib.idle_add(self.on_info_bar_close)
user, password = self._settings.telnet_user, self._settings.telnet_password
timeout = self._settings.telnet_timeout
self._tn = ExtTelnet(self.append_output,
host=self._settings.host,
port=self._settings.telnet_port,
timeout=timeout)
if user != "":
self._tn.read_until(b"login: ")
self._tn.write(user.encode("utf-8") + b"\n")
if password != "":
self._tn.read_until(b"Password: ")
self._tn.write(password.encode("utf-8") + b"\n")
self._tn.interact()
except (OSError, EOFError, socket.timeout, ConnectionRefusedError) as e:
log("{}: {}".format(self.__class__.__name__, e))
self.show_info_message(str(e), Gtk.MessageType.ERROR)
finally:
GLib.idle_add(self._connect_button.set_visible, True)
@run_task
def on_disconnect(self, item=None):
if self._tn:
GLib.idle_add(self._connect_button.set_visible, True)
self._tn.close()
def on_profile_changed(self, button):
self._settings.current_profile = button.get_active_id()
def on_command_done(self, entry):
command = entry.get_text()
entry.set_text("")
if command and self._tn:
self._tn.write(command.encode("ascii") + b"\r")
def on_clear(self, item=None):
self._buf.delete(self._buf.get_start_iter(), self._buf.get_end_iter())
def on_view_key_press(self, view, event):
""" Handling keystrokes on press """
if event.keyval == Gdk.KEY_Return:
self.do_command()
return True
key_code = event.hardware_keycode
if not KeyboardKey.value_exist(key_code):
return
key = KeyboardKey(key_code)
ctrl = event.state & MOD_MASK
if ctrl and key is KeyboardKey.C:
if self._tn and self._tn.sock:
self._tn.write(b"\x03") # interrupt
# last commands navigation
if key is KeyboardKey.UP:
self.delete_last_command()
if self._commands:
cmd = self._commands.pop()
self._commands.appendleft(cmd)
self._buf.insert_at_cursor(cmd, -1)
return True
elif key is KeyboardKey.DOWN:
self.delete_last_command()
if self._commands:
cmd = self._commands.popleft()
self._commands.append(cmd)
self._buf.insert_at_cursor(cmd, -1)
return True
def delete_last_command(self):
end = self._buf.get_end_iter()
if end.ends_tag(self._end_tag):
return
if end.backward_to_tag_toggle(self._end_tag):
self._buf.delete(self._buf.get_end_iter(), end)
def do_command(self):
count = self._buf.get_line_count()
begin = self._buf.get_iter_at_line(count)
end = self._buf.get_end_iter()
command = []
while end.backward_to_tag_toggle(self._end_tag):
command.append(self._buf.get_text(end, begin, False))
break
else: # if buf is empty
command.append(self._buf.get_text(begin, end, False))
# to preventing duplication of the command in the buf
self._buf.delete(end, begin)
if command and self._tn.sock:
cmd = command[0]
if cmd in self._NOT_SUPPORTED:
self.show_info_message("'{}' is not supported by this client.".format(cmd), Gtk.MessageType.ERROR)
else:
self._tn.write(cmd.encode("ascii") + b"\r")
self._commands.append(cmd)
@run_idle
def append_output(self, txt):
t = txt.decode("ascii", errors="ignore")
ap = re.search(self._APP_MODE_PATTERN, t)
if ap:
on, of = ap.group(1), ap.group(2)
if on:
self._app_mode = True
elif of:
self._app_mode = False
self.on_clear()
t = re.sub(self._ALL_PATTERN, "", t) # removing [replacing] ascii escape sequences
if self._app_mode:
start, end = self._buf.get_start_iter(), self._buf.get_end_iter()
count = self._buf.get_line_count()
new_lines = t.split("\r\n")
ext_lines = self._buf.get_text(start, end, True).split("\r\n")
if count < len(new_lines):
self._buf.set_text(re.sub(self._ERASING_PATTERN, "", t))
else:
for i, line in enumerate(new_lines):
if line:
ext_lines[i] = re.sub(self._ERASING_PATTERN, "", line)
self._buf.set_text("\r\n".join(ext_lines))
else:
self._buf.insert_at_cursor(t, -1)
insert = self._buf.get_insert()
self._text_view.scroll_to_mark(insert, 0.0, True, 0.0, 1.0)
self._buf.apply_tag(self._end_tag, self._buf.get_start_iter(), self._buf.get_end_iter())
if __name__ == "__main__":
pass

View File

@@ -5,6 +5,7 @@ import gi
from gi.repository import GLib
from app.commons import log
from app.settings import IS_DARWIN
from app.connections import HttpRequestType
from app.tools.yt import YouTube
from app.ui.iptv import get_yt_icon
@@ -12,7 +13,7 @@ from .uicommons import Gtk, Gdk, UI_RESOURCES_PATH
class LinksTransmitter:
""" The main class for the "send to" function.
""" The main media bar class for the "send to" function..
It used for direct playback of media links by the enigma2 media player.
"""
@@ -47,16 +48,19 @@ class LinksTransmitter:
self._status_passive = None
self._yt = YouTube.get_instance(settings)
try:
gi.require_version("AppIndicator3", "0.1")
from gi.repository import AppIndicator3
except (ImportError, ValueError) as e:
log("{}: Load library error: {}".format(__class__.__name__, e))
if IS_DARWIN:
self._tray = builder.get_object("status_icon")
else:
self._is_status_icon = False
self._status_active = AppIndicator3.IndicatorStatus.ACTIVE
self._status_passive = AppIndicator3.IndicatorStatus.PASSIVE
try:
gi.require_version("AppIndicator3", "0.1")
from gi.repository import AppIndicator3
except (ImportError, ValueError) as e:
log("{}: Load library error: {}".format(__class__.__name__, e))
self._tray = builder.get_object("status_icon")
else:
self._is_status_icon = False
self._status_active = AppIndicator3.IndicatorStatus.ACTIVE
self._status_passive = AppIndicator3.IndicatorStatus.PASSIVE
category = AppIndicator3.IndicatorCategory.APPLICATION_STATUS
path = Path(UI_RESOURCES_PATH + "/icons/hicolor/scalable/apps/demon-editor.svg")

View File

@@ -1,4 +1,3 @@
import locale
import os
from enum import Enum, IntEnum
from functools import lru_cache
@@ -8,15 +7,15 @@ import gi
gi.require_version("Gtk", "3.0")
gi.require_version("Gdk", "3.0")
gi.require_version("Notify", "0.7")
from gi.repository import Gtk, Gdk, Notify
from gi.repository import Gtk, Gdk, GLib
# Init notify
Notify.init("DemonEditor")
# Setting mod mask for the keyboard depending on the platform.
# Setting mod mask for keyboard depending on platform
MOD_MASK = Gdk.ModifierType.MOD2_MASK if IS_DARWIN else Gdk.ModifierType.CONTROL_MASK
# Path to *.glade files.
UI_RESOURCES_PATH = "app/ui/" if os.path.exists("app/ui/") else "/usr/share/demoneditor/app/ui/"
# Path to *.glade files
UI_RESOURCES_PATH = "app/ui/" if os.path.exists("app/ui/") else "ui/"
LANG_PATH = UI_RESOURCES_PATH + "lang"
GTK_PATH = os.environ.get("GTK_PATH", None)
NOTIFY_IS_INIT = False
IS_GNOME_SESSION = int(bool(os.environ.get("GNOME_DESKTOP_SESSION_ID")))
# Translation.
TEXT_DOMAIN = "demon-editor"
@@ -27,27 +26,59 @@ except SettingsException:
pass
else:
os.environ["LANGUAGE"] = settings.language
if UI_RESOURCES_PATH == "app/ui/":
locale.bindtextdomain(TEXT_DOMAIN, UI_RESOURCES_PATH + "lang")
if settings.is_themes_support:
st = Gtk.Settings().get_default()
st.set_property("gtk-theme-name", settings.theme)
st.set_property("gtk-icon-theme-name", settings.icon_theme)
else:
style_provider = Gtk.CssProvider()
s_path = "{}default_style.css".format(GTK_PATH + "/" + UI_RESOURCES_PATH if GTK_PATH else UI_RESOURCES_PATH)
style_provider.load_from_path(s_path)
Gtk.StyleContext.add_provider_for_screen(Gdk.Screen.get_default(), style_provider,
Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)
if IS_DARWIN:
import gettext
if GTK_PATH:
LANG_PATH = GTK_PATH + "/share/locale"
gettext.bindtextdomain(TEXT_DOMAIN, LANG_PATH)
# For launching from the bundle.
if os.getcwd() == "/" and GTK_PATH:
os.chdir(GTK_PATH)
else:
import locale
locale.bindtextdomain(TEXT_DOMAIN, LANG_PATH)
# Init notify
try:
gi.require_version("Notify", "0.7")
from gi.repository import Notify
except ImportError:
pass
else:
NOTIFY_IS_INIT = Notify.init("DemonEditor")
theme = Gtk.IconTheme.get_default()
theme.append_search_path(UI_RESOURCES_PATH + "icons")
theme.append_search_path(GTK_PATH + "/share/icons" if GTK_PATH else UI_RESOURCES_PATH + "icons")
_IMAGE_MISSING = theme.load_icon("image-missing", 16, 0) if theme.lookup_icon("image-missing", 16, 0) else None
CODED_ICON = theme.load_icon("emblem-readonly", 16, 0) if theme.lookup_icon(
"emblem-readonly", 16, 0) else _IMAGE_MISSING
LOCKED_ICON = theme.load_icon("changes-prevent-symbolic", 16, 0) if theme.lookup_icon(
"system-lock-screen", 16, 0) else _IMAGE_MISSING
HIDE_ICON = theme.load_icon("go-jump", 16, 0) if theme.lookup_icon("go-jump", 16, 0) else _IMAGE_MISSING
TV_ICON = theme.load_icon("tv-symbolic", 16, 0) if theme.lookup_icon("tv-symbolic", 16, 0) else _IMAGE_MISSING
IPTV_ICON = theme.load_icon("emblem-shared", 16, 0) if theme.lookup_icon("emblem-shared", 16, 0) else None
EPG_ICON = theme.load_icon("gtk-index", 16, 0) if theme.lookup_icon("gtk-index", 16, 0) else None
DEFAULT_ICON = theme.load_icon("emblem-default", 16, 0) if theme.lookup_icon("emblem-default", 16, 0) else None
def get_theme_icon(icon_theme, name, size):
try:
return icon_theme.load_icon(name, size, 0)
except GLib.Error:
pass
_IMAGE_MISSING = get_theme_icon(theme, "image-missing", 16)
CODED_ICON = get_theme_icon(theme, "emblem-readonly", 16) or _IMAGE_MISSING
LOCKED_ICON = get_theme_icon(theme, "changes-prevent-symbolic", 16) or _IMAGE_MISSING
HIDE_ICON = get_theme_icon(theme, "go-jump", 16) or _IMAGE_MISSING
TV_ICON = get_theme_icon(theme, "tv-symbolic", 16) or _IMAGE_MISSING
IPTV_ICON = get_theme_icon(theme, "emblem-shared", 16)
EPG_ICON = get_theme_icon(theme, "gtk-index", 16)
DEFAULT_ICON = get_theme_icon(theme, "emblem-default", 16)
@lru_cache(maxsize=1)
@@ -64,11 +95,12 @@ def get_yt_icon(icon_name, size=24):
import glob
for theme_name in map(os.path.basename, filter(os.path.isdir, glob.glob("/usr/share/icons/*"))):
n_theme.set_custom_theme(theme_name)
theme.set_custom_theme(theme_name)
if n_theme.has_icon(icon_name):
return n_theme.load_icon(icon_name, size, 0)
return default_theme.load_icon("info", size, 0)
if default_theme.lookup_icon(Gtk.STOCK_APPLY, size, 0):
return default_theme.load_icon(Gtk.STOCK_APPLY, size, 0)
def show_notification(message, timeout=10000, urgency=1):
@@ -78,40 +110,46 @@ def show_notification(message, timeout=10000, urgency=1):
@param timeout: milliseconds
@param urgency: 0 - low, 1 - normal, 2 - critical
"""
notify = Notify.Notification.new("DemonEditor", message, "demon-editor")
notify.set_urgency(urgency)
notify.set_timeout(timeout)
notify.show()
if IS_DARWIN:
# Since NSUserNotification has been deprecated, osascript will be used.
os.system("""osascript -e 'display notification "{}" with title "DemonEditor"'""".format(message))
elif NOTIFY_IS_INIT:
notify = Notify.Notification.new("DemonEditor", message, "demon-editor")
notify.set_urgency(urgency)
notify.set_timeout(timeout)
notify.show()
class KeyboardKey(Enum):
""" The raw(hardware) codes of the keyboard keys. """
E = 26
R = 27
T = 28
P = 33
S = 39
F = 41
X = 53
C = 54
V = 55
W = 25
Z = 52
INSERT = 118
HOME = 110
END = 115
UP = 111
DOWN = 116
PAGE_UP = 112
PAGE_DOWN = 117
LEFT = 113
RIGHT = 114
F2 = 68
SPACE = 65
DELETE = 119
BACK_SPACE = 22
CTRL_L = 37
CTRL_R = 105
F = 3 if IS_DARWIN else 41
E = 14 if IS_DARWIN else 26
R = 15 if IS_DARWIN else 27
T = 17 if IS_DARWIN else 28
P = 35 if IS_DARWIN else 33
S = 1 if IS_DARWIN else 39
H = 4 if IS_DARWIN else 43
L = 37 if IS_DARWIN else 46
X = 7 if IS_DARWIN else 53
C = 8 if IS_DARWIN else 54
V = 9 if IS_DARWIN else 55
W = 13 if IS_DARWIN else 25
Z = 6 if IS_DARWIN else 52
INSERT = -1 if IS_DARWIN else 118
HOME = -1 if IS_DARWIN else 110
END = -1 if IS_DARWIN else 115
UP = 126 if IS_DARWIN else 111
DOWN = 125 if IS_DARWIN else 116
PAGE_UP = -1 if IS_DARWIN else 112
PAGE_DOWN = -1 if IS_DARWIN else 117
LEFT = 123 if IS_DARWIN else 113
RIGHT = 123 if IS_DARWIN else 114
F2 = 120 if IS_DARWIN else 68
SPACE = 49 if IS_DARWIN else 65
DELETE = 51 if IS_DARWIN else 119
BACK_SPACE = 76 if IS_DARWIN else 22
CTRL_L = 55 if IS_DARWIN else 37
CTRL_R = 55 if IS_DARWIN else 105
# Laptop codes
HOME_KP = 79
END_KP = 87

View File

@@ -1,18 +0,0 @@
#!/bin/bash
VER="1.0.1_Beta"
B_PATH="dist/DemonEditor"
DEB_PATH="$B_PATH/usr/share/demoneditor"
mkdir -p $B_PATH
cp -TRv deb $B_PATH
rsync --exclude=app/ui/lang --exclude=app/ui/icons -arv app $DEB_PATH
cd dist
fakeroot dpkg-deb --build DemonEditor
mv DemonEditor.deb DemonEditor_$VER.deb
rm -R DemonEditor

View File

@@ -1,58 +0,0 @@
demon-editor for Debian
----------------------
DemonEditor
Enigma2 channel and satellites list editor for GNU/Linux.
Experimental support of Neutrino-MP or others on the same basis (BPanther, etc).
Focused on the convenience of working in lists from the keyboard. The mouse is also fully supported (Drag and Drop etc).
Main features of the program:
Editing bouquets, channels, satellites.
Import function.
Backup function.
Extended support of IPTV.
Support of picons.
Downloading of picons and updating of satellites (transponders) from the web.
Import to bouquet(Neutrino WEBTV) from m3u.
Export of bouquets with IPTV services in m3u.
Assignment of EPGs from DVB or XML for IPTV services (only Enigma2, experimental).
Preview (playback) of IPTV or other streams directly from the bouquet list (should be installed VLC).
Keyboard shortcuts:
Ctrl + Insert - copies the selected channels from the main list to the the bouquet beginning or inserts (creates) a new bouquet.
Ctrl + BackSpace - copies the selected channels from the main list to the bouquet end.
Ctrl + X - only in bouquet list. Ctrl + C - only in services list.
Clipboard is "rubber". There is an accumulation before the insertion!
Ctrl + E - edit.
Ctrl + R, F2 - rename.
Ctrl + S, T in Satellites edit tool for create satellite or transponder.
Ctrl + L - parental lock.
Ctrl + H - hide/skip.
Ctrl + P - start play IPTV or other stream in the bouquet list.
Ctrl + Z - switch (zap) the channel (works when the HTTP API is enabled, Enigma2 only).
Ctrl + W - switch to the channel and watch in the program.
Space - select/deselect.
Left/Right - remove selection.
Ctrl + Up, Down, PageUp, PageDown, Home, End - move selected items in the list.
Ctrl + O - (re)load user data from current dir.
Ctrl + D - load data from receiver.
Ctrl + U/B upload data/bouquets to receiver.
Ctrl + F - show/hide search bar.
Ctrl + Shift + F - show/hide filter bar.
For multiple selection with the mouse, press and hold the Ctrl key!
Minimum requirements:
Python >= 3.5.2 and GTK+ >= 3.16 with PyGObject bindings, python3-requests.
Important:
Terrestrial(DVB-T/T2) and cable(DVB-C) channels are only supported for Enigma2!
Main supported *lamedb* format is version **4**. Versions **3** and **5** has only **experimental** support!
For version **3** is only read mode available. When saving, version **4** format is used instead!
When using the multiple import feature, from *lamedb* will be taken data **only for channels that are in the
selected bouquets!** If you need full set of the data, including *[satellites, terrestrial, cables].xml* (current files will be overwritten),
just load your data via *"File/Open"* and press *"Save"*. When importing separate bouquet files, only those services
(excluding IPTV) that are in the **current open lamedb** (main list of services) will be imported.

View File

@@ -1,9 +0,0 @@
Package: demon-editor
Version: 1.0.1-Beta
Section: utils
Priority: optional
Architecture: all
Essential: no
Depends: python3 (>= 3.5)
Maintainer: Dmitriy Yefremov <dmitry.v.yefremov@gmail.com>
Description: Enigma2 channel and satellites list editor

View File

@@ -1,26 +0,0 @@
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Contact: Dmitriy Yefremov <dmitry.v.yefremov@gmail.com>
Source: https://github.com/DYefremov/DemonEditor
Files: *
MIT License
Copyright (c) 2018-2020 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.

View File

@@ -1 +0,0 @@
README.source

View File

@@ -1,2 +0,0 @@
#!/bin/bash
python3 /usr/share/demoneditor/start.py $1

View File

@@ -1,11 +0,0 @@
[Desktop Entry]
Version=1.0
Name=DemonEditor
Comment=Channels and satellites list editor for Enigma2
Comment[ru]=Редактор списка каналов и спутников для Enigma2
Icon=demon-editor
Exec=/usr/bin/demon-editor
Terminal=false
Type=Application
Categories=Utility;Application;
StartupNotify=false

View File

@@ -1,4 +0,0 @@
#!/usr/bin/env python3
from app.ui.main_app_window import start_app
start_app()

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

View File

@@ -1,634 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
id="svg1541"
version="1.1"
viewBox="0 0 16.743339 16.72816"
height="63.224556"
width="63.281971"
sodipodi:docname="demon-editor.svg"
inkscape:version="0.92.4 (unknown)">
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1366"
inkscape:window-height="716"
id="namedview127"
showgrid="true"
fit-margin-left="0"
inkscape:zoom="6.1714295"
inkscape:cx="40.088627"
inkscape:cy="31.742631"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg1541"
fit-margin-top="0"
fit-margin-right="0"
fit-margin-bottom="0">
<inkscape:grid
type="xygrid"
id="grid128"
originx="-10.604603"
originy="-1.1727724" />
</sodipodi:namedview>
<title
id="title1088">DeamonEditor Icons</title>
<defs
id="defs1535">
<linearGradient
id="linearGradient2198">
<stop
id="stop2194"
style="stop-color:#ffb320;stop-opacity:1"
offset="0" />
<stop
id="stop2196"
style="stop-color:#e7ff00;stop-opacity:1"
offset="1" />
</linearGradient>
<linearGradient
id="linearGradient2192">
<stop
offset="0"
style="stop-color:#ffb320;stop-opacity:1"
id="stop2188" />
<stop
offset="1"
style="stop-color:#b3c54c;stop-opacity:1"
id="stop2190" />
</linearGradient>
<linearGradient
id="linearGradient3700-8">
<stop
offset="0"
style="stop-color:#2e4f84;stop-opacity:1"
id="stop2183" />
<stop
offset="1"
style="stop-color:#4c77c5;stop-opacity:1"
id="stop2185" />
</linearGradient>
<linearGradient
x1="0"
y1="0"
x2="1"
y2="0"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(13.526835,20.525875,20.525875,-13.526835,19.18986,1021.0543)"
spreadMethod="pad"
id="linearGradient1844">
<stop
style="stop-opacity:1;stop-color:#29282b"
offset="0"
id="stop1826" />
<stop
id="stop1828"
offset="0.13293758"
style="stop-color:#b5bdcf;stop-opacity:1" />
<stop
style="stop-opacity:1;stop-color:#92979f"
offset="0.21261224"
id="stop1832" />
<stop
style="stop-opacity:1;stop-color:#737881"
offset="0.29780689"
id="stop1834" />
<stop
style="stop-opacity:1;stop-color:#70757e"
offset="0.29780689"
id="stop1836" />
<stop
style="stop-opacity:1;stop-color:#e4e6e8"
offset="0.45395693"
id="stop1838" />
<stop
style="stop-opacity:1;stop-color:#696c76"
offset="0.71871042"
id="stop1840" />
<stop
style="stop-opacity:1;stop-color:#29282b"
offset="1"
id="stop1842" />
</linearGradient>
<linearGradient
id="linearGradient1754"
spreadMethod="pad"
gradientTransform="matrix(13.526835,20.525875,20.525875,-13.526835,19.18986,1021.0543)"
gradientUnits="userSpaceOnUse"
y2="0"
x2="1"
y1="0"
x1="0">
<stop
id="stop1736"
offset="0"
style="stop-opacity:1;stop-color:#29282b" />
<stop
style="stop-color:#b5bdcf;stop-opacity:1"
offset="0.02582242"
id="stop1738" />
<stop
id="stop1740"
offset="0.14669065"
style="stop-opacity:1;stop-color:#868c95" />
<stop
id="stop1742"
offset="0.21261224"
style="stop-opacity:1;stop-color:#92979f" />
<stop
id="stop1744"
offset="0.29780689"
style="stop-opacity:1;stop-color:#737881" />
<stop
id="stop1746"
offset="0.29780689"
style="stop-opacity:1;stop-color:#70757e" />
<stop
id="stop1748"
offset="0.45395693"
style="stop-opacity:1;stop-color:#e4e6e8" />
<stop
id="stop1750"
offset="0.71871042"
style="stop-opacity:1;stop-color:#ffffff" />
<stop
id="stop1752"
offset="1"
style="stop-opacity:1;stop-color:#1d191a" />
</linearGradient>
<linearGradient
x1="0"
y1="0"
x2="1"
y2="0"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(13.526835,20.525875,20.525875,-13.526835,19.18986,1021.0543)"
spreadMethod="pad"
id="linearGradient1606">
<stop
style="stop-opacity:1;stop-color:#29282b"
offset="0"
id="stop1590" />
<stop
id="stop1608"
offset="0.03065561"
style="stop-color:#b5bdcf;stop-opacity:1" />
<stop
style="stop-opacity:1;stop-color:#868c95"
offset="0.1125849"
id="stop1592" />
<stop
style="stop-opacity:1;stop-color:#92979f"
offset="0.13955873"
id="stop1594" />
<stop
style="stop-opacity:1;stop-color:#737881"
offset="0.1915853"
id="stop1596" />
<stop
style="stop-opacity:1;stop-color:#70757e"
offset="0.25400829"
id="stop1598" />
<stop
style="stop-opacity:1;stop-color:#e4e6e8"
offset="0.45395693"
id="stop1600" />
<stop
style="stop-opacity:1;stop-color:#ffffff"
offset="0.71871042"
id="stop1602" />
<stop
style="stop-opacity:1;stop-color:#1d191a"
offset="1"
id="stop1604" />
</linearGradient>
<linearGradient
id="linearGradient886-0">
<stop
style="stop-color:#535353;stop-opacity:1"
offset="0"
id="stop888" />
<stop
style="stop-color:#f0f0f0;stop-opacity:1"
offset="1"
id="stop890" />
</linearGradient>
<linearGradient
id="linearGradient1473">
<stop
id="stop1469"
offset="0"
style="stop-color:#ffffff;stop-opacity:0" />
<stop
id="stop1471"
offset="1"
style="stop-color:#ffffff;stop-opacity:0.96088022" />
</linearGradient>
<linearGradient
id="linearGradient2447-35">
<stop
id="stop2449"
offset="0"
style="stop-color:#00c62e;stop-opacity:1" />
<stop
id="stop2451"
offset="1"
style="stop-color:#136100;stop-opacity:1" />
</linearGradient>
<linearGradient
id="linearGradient3795-1">
<stop
id="stop3797-1"
offset="0"
style="stop-color:#803400;stop-opacity:1" />
<stop
id="stop3799-3"
offset="1"
style="stop-color:#c87137;stop-opacity:1" />
</linearGradient>
<linearGradient
id="linearGradient2447-3">
<stop
style="stop-color:#c60300;stop-opacity:1"
offset="0"
id="stop2443" />
<stop
style="stop-color:#c40e00;stop-opacity:1"
offset="1"
id="stop2445" />
</linearGradient>
<linearGradient
id="linearGradient2458">
<stop
id="stop2454"
offset="0"
style="stop-color:#c60300;stop-opacity:1" />
<stop
id="stop2456"
offset="1"
style="stop-color:#ee6000;stop-opacity:1" />
</linearGradient>
<linearGradient
id="linearGradient3519">
<stop
id="stop3521"
offset="0"
style="stop-color:#1d2120;stop-opacity:1" />
<stop
id="stop3523"
offset="1"
style="stop-color:#545d5d;stop-opacity:1" />
</linearGradient>
<linearGradient
id="linearGradient1446">
<stop
id="stop1442"
offset="0"
style="stop-color:#ffffff;stop-opacity:1;" />
<stop
id="stop1444"
offset="1"
style="stop-color:#ffffff;stop-opacity:0;" />
</linearGradient>
<linearGradient
id="linearGradient1547"
spreadMethod="pad"
gradientTransform="matrix(13.526835,20.525875,20.525875,-13.526835,19.18986,1021.0543)"
gradientUnits="userSpaceOnUse"
y2="0"
x2="1"
y1="0"
x1="0">
<stop
id="stop1529"
offset="0"
style="stop-opacity:1;stop-color:#ffffff" />
<stop
id="stop1531"
offset="0.0263736"
style="stop-opacity:1;stop-color:#29282b" />
<stop
id="stop1533"
offset="0.263736"
style="stop-opacity:1;stop-color:#868c95" />
<stop
id="stop1535"
offset="0.395604"
style="stop-opacity:1;stop-color:#92979f" />
<stop
id="stop1537"
offset="0.39560401"
style="stop-opacity:1;stop-color:#737881" />
<stop
id="stop1539"
offset="0.42333773"
style="stop-opacity:1;stop-color:#70757e" />
<stop
id="stop1541"
offset="0.56268591"
style="stop-opacity:1;stop-color:#e4e6e8" />
<stop
id="stop1543"
offset="0.62400264"
style="stop-opacity:1;stop-color:#ffffff" />
<stop
id="stop1545"
offset="1"
style="stop-opacity:1;stop-color:#1d191a" />
</linearGradient>
<linearGradient
id="linearGradient1527"
spreadMethod="pad"
gradientTransform="matrix(13.526835,20.525875,20.525875,-13.526835,19.18986,1021.0543)"
gradientUnits="userSpaceOnUse"
y2="0"
x2="1"
y1="0"
x1="0">
<stop
id="stop1509"
offset="0"
style="stop-opacity:1;stop-color:#ffffff" />
<stop
id="stop1511"
offset="0.0527472"
style="stop-opacity:1;stop-color:#29282b" />
<stop
id="stop1513"
offset="0.142147"
style="stop-opacity:1;stop-color:#868c95" />
<stop
id="stop1515"
offset="0.19700864"
style="stop-opacity:1;stop-color:#92979f" />
<stop
id="stop1517"
offset="0.25031137"
style="stop-opacity:1;stop-color:#737881" />
<stop
id="stop1519"
offset="0.3710371"
style="stop-opacity:1;stop-color:#70757e" />
<stop
id="stop1521"
offset="0.53961843"
style="stop-opacity:1;stop-color:#e4e6e8" />
<stop
id="stop1523"
offset="0.76283824"
style="stop-opacity:1;stop-color:#ffffff" />
<stop
id="stop1525"
offset="1"
style="stop-opacity:1;stop-color:#1d191a" />
</linearGradient>
<linearGradient
gradientTransform="matrix(0.26458333,0,0,0.26458333,-5.8254634,-78.732754)"
y2="1179.7145"
x2="66.791626"
y1="1188.7661"
x1="99.044022"
gradientUnits="userSpaceOnUse"
id="linearGradient1485"
xlink:href="#linearGradient1473" />
<linearGradient
gradientTransform="matrix(0.26458333,0,0,0.26458333,-2.2733744,-70.526334)"
gradientUnits="userSpaceOnUse"
y2="1155.8046"
x2="67.311417"
y1="1161.6112"
x1="77.19442"
id="linearGradient1448"
xlink:href="#linearGradient1446" />
<linearGradient
gradientTransform="matrix(0.26458333,0,0,0.26458333,-18.198747,-79.859424)"
gradientUnits="userSpaceOnUse"
y2="1186.8096"
x2="146.16808"
y1="1186.8096"
x1="131.86871"
id="linearGradient2180"
xlink:href="#linearGradient886-0" />
<linearGradient
gradientTransform="matrix(0.20863982,0,0,0.20863982,-0.63935937,-13.031239)"
gradientUnits="userSpaceOnUse"
y2="1184.73"
x2="101.19952"
y1="1184.73"
x1="83.066002"
id="linearGradient2160"
xlink:href="#linearGradient886-0" />
<linearGradient
gradientTransform="matrix(0.26458333,0,0,0.26458333,-6.2370714,-102.12414)"
gradientUnits="userSpaceOnUse"
y2="1267.1335"
x2="117.99127"
y1="1267.1335"
x1="75.853806"
id="linearGradient2131"
xlink:href="#linearGradient886-0" />
<linearGradient
id="linearGradient3700-8-3">
<stop
id="stop3702-1"
style="stop-color:#2e4f84;stop-opacity:1"
offset="0" />
<stop
id="stop3704-8"
style="stop-color:#4c77c5;stop-opacity:1"
offset="1" />
</linearGradient>
<defs
id="defs4922">
<filter
style="color-interpolation-filters:sRGB"
id="Adobe_OpacityMaskFilter"
filterUnits="userSpaceOnUse"
x="3.7850001"
y="4.6750002"
width="5.8829999"
height="73.013">
<feColorMatrix
type="matrix"
values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0"
id="feColorMatrix4925" />
</filter>
</defs>
<mask
maskUnits="userSpaceOnUse"
x="3.785"
y="4.675"
width="5.883"
height="73.013"
id="SVGID_2_">
<g
style="filter:url(#Adobe_OpacityMaskFilter)"
id="g4928">
<linearGradient
id="SVGID_3_"
gradientUnits="userSpaceOnUse"
x1="3.7852001"
y1="41.181198"
x2="9.6680002"
y2="41.181198">
<stop
offset="0"
style="stop-color:#FFFFFF"
id="stop4931" />
<stop
offset="0.0029"
style="stop-color:#FAFBFB"
id="stop4933" />
<stop
offset="0.0756"
style="stop-color:#BBBDBF"
id="stop4935" />
<stop
offset="0.1438"
style="stop-color:#898B8E"
id="stop4937" />
<stop
offset="0.2053"
style="stop-color:#646567"
id="stop4939" />
<stop
offset="0.259"
style="stop-color:#444446"
id="stop4941" />
<stop
offset="0.3028"
style="stop-color:#1D1C1D"
id="stop4943" />
<stop
offset="0.3313"
style="stop-color:#000000"
id="stop4945" />
</linearGradient>
<rect
style="fill:url(#SVGID_3_)"
x="3.7850001"
y="4.6750002"
width="5.8829999"
height="73.013"
id="rect4947" />
</g>
</mask>
<filter
style="color-interpolation-filters:sRGB"
id="filter1268"
filterUnits="userSpaceOnUse"
x="3.7850001"
y="4.6750002"
width="5.8829999"
height="73.013">
<feColorMatrix
type="matrix"
values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0"
id="feColorMatrix1266" />
</filter>
<linearGradient
gradientUnits="userSpaceOnUse"
y2="203.22046"
x2="23.551136"
y1="203.22046"
x1="13.487289"
id="linearGradient1160"
xlink:href="#linearGradient3519" />
<clipPath
id="clipPath1890"
clipPathUnits="userSpaceOnUse">
<circle
style="opacity:1;fill:#2d2d2d;fill-opacity:1;stroke:#434242;stroke-width:0.0575568;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="circle1892"
cx="78.548424"
cy="-31.019459"
r="6.4721422"
transform="scale(1,-1)" />
</clipPath>
<linearGradient
gradientTransform="translate(-0.24389927,14.877856)"
y2="27.314217"
x2="84.864914"
y1="27.314217"
x1="72.164909"
gradientUnits="userSpaceOnUse"
id="linearGradient2134"
xlink:href="#linearGradient3700-8-3" />
</defs>
<metadata
id="metadata1538">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title>DeamonEditor Icons</dc:title>
<dc:publisher>
<cc:Agent>
<dc:title>mfgeg</dc:title>
</cc:Agent>
</dc:publisher>
<dc:date>7.1.2020</dc:date>
</cc:Work>
</rdf:RDF>
</metadata>
<g
transform="matrix(1.1690805,0,0,1.1690805,-14.929261,-167.45253)"
id="layer1">
<g
transform="translate(0.86526724,-82.691658)"
id="g1351">
<path
d="m 13.715358,227.65981 h 2.97616 v 12.57332 h -2.97616 z m 5.79826,-1.73376 -0.327076,0.42227 c -0.179879,0.23226 -0.586303,0.67932 -0.903223,0.99412 -0.480677,0.47726 -0.640897,0.57235 -0.967777,0.57235 -0.223557,0 -0.380895,-0.0584 -0.624024,-0.25067 v 3.18307 c 0.172884,-0.0214 0.359647,-0.0333 0.575071,-0.0352 0.68403,-0.006 0.91815,0.0416 1.436333,0.29581 1.14586,0.56274 1.762492,1.5589 1.768251,2.8566 0.0094,2.10836 -1.870896,3.55161 -3.779655,3.16529 v 3.10345 c 4.345352,0.0758 4.093104,-2.37537 6.573781,-2.25837 1.486139,0.0748 1.333421,0.16555 1.796225,-1.064 l 0.259834,-0.6913 -0.803704,-0.66493 c -0.960855,-0.79478 -1.303983,-1.29079 -1.205013,-1.74132 0.06631,-0.30189 1.20818,-1.50093 1.779011,-1.86778 0.240181,-0.1543 0.244255,-0.17878 0.09575,-0.59661 -0.08522,-0.23979 -0.259522,-0.65746 -0.386789,-0.92744 l -0.23132,-0.49115 h -1.412666 c -1.868582,0 -1.802386,0.068 -1.805368,-1.82472 l -0.0021,-1.43582 -0.917745,-0.37171 z"
style="opacity:1;fill:#000000;fill-opacity:0.5372549;stroke:none;stroke-width:0.18460207;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.5012225"
id="path2133"
inkscape:connector-curvature="0" />
<path
id="path2106"
style="opacity:1;fill:url(#linearGradient2131);fill-opacity:1;stroke:none;stroke-width:0.17733108;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.5012225"
d="m 13.832581,227.93117 h 2.858936 v 12.07807 h -2.858936 z m 5.569881,-1.6655 -0.314194,0.40566 c -0.172793,0.22309 -0.563209,0.65257 -0.867647,0.95496 -0.46174,0.45847 -0.615654,0.5498 -0.929658,0.5498 -0.214752,0 -0.365893,-0.056 -0.599446,-0.24079 v 3.05768 c 0.166077,-0.0206 0.345483,-0.0319 0.55242,-0.0338 0.657089,-0.006 0.881987,0.0399 1.379764,0.28416 1.100724,0.54057 1.693073,1.49747 1.698606,2.74408 0.009,2.02535 -1.797211,3.41174 -3.63079,3.04061 v 2.98122 c 4.174205,0.0728 3.931888,-2.28179 6.314859,-2.1694 1.427604,0.0718 1.2809,0.15902 1.725477,-1.02213 l 0.249597,-0.66408 -0.772046,-0.63871 c -0.923009,-0.76345 -1.252622,-1.23996 -1.157552,-1.67277 0.0637,-0.29001 1.160592,-1.44177 1.708939,-1.79419 0.230721,-0.14825 0.234635,-0.17174 0.09198,-0.57312 -0.08187,-0.23032 -0.249296,-0.63156 -0.371555,-0.89088 l -0.222207,-0.4718 h -1.357022 c -1.794983,0 -1.731396,0.0653 -1.734262,-1.75284 l -0.0021,-1.3793 -0.881603,-0.35705 z"
inkscape:connector-curvature="0" />
<path
id="path2151"
d="m 17.266983,230.95755 c -0.215637,0.003 -0.402408,0.014 -0.575465,0.0354 v 6.28854 c 1.910653,0.38671 3.792716,-1.05815 3.783336,-3.16865 -0.0058,-1.29897 -0.623064,-2.29597 -1.770059,-2.85927 -0.518699,-0.25451 -0.753103,-0.30234 -1.437812,-0.29607 z m 0.482341,1.17002 c 0.433747,-0.004 0.582202,0.0265 0.910784,0.18761 0.726595,0.35682 1.117604,0.98848 1.121256,1.81134 0.0059,1.33694 -1.186343,2.25211 -2.396695,2.00715 v -3.98359 c 0.109628,-0.0135 0.228054,-0.0214 0.364655,-0.0225 z"
style="opacity:1;fill:url(#linearGradient2160);fill-opacity:1;stroke:none;stroke-width:0.18478528;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.5012225"
inkscape:connector-curvature="0" />
<path
style="opacity:1;fill:none;fill-opacity:1;stroke:url(#linearGradient2180);stroke-width:0.18478528;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.5012225"
d="m 17.266981,230.95753 c -0.215636,0.003 -0.402408,0.014 -0.575464,0.0354 v 6.28853 c 1.910652,0.38672 3.792715,-1.05815 3.783336,-3.16865 -0.0057,-1.29897 -0.623065,-2.29597 -1.77006,-2.85927 -0.518697,-0.2545 -0.753103,-0.30234 -1.437812,-0.29607 z m 0.482343,1.17001 c 0.433747,-0.004 0.5822,0.0265 0.910783,0.18762 0.726594,0.35681 1.117605,0.98848 1.121257,1.81133 0.006,1.33694 -1.186344,2.25211 -2.396697,2.00716 v -3.98359 c 0.109628,-0.0135 0.228055,-0.0214 0.364657,-0.0225 z"
id="path2170"
inkscape:connector-curvature="0" />
<path
id="path1422"
d="m 17.266983,230.95755 c -0.215637,0.003 -0.402408,0.014 -0.575464,0.0354 v 6.28854 c 1.910652,0.38671 3.792715,-1.05815 3.783335,-3.16865 -0.0057,-1.29897 -0.623064,-2.29597 -1.770059,-2.85927 -0.518699,-0.25451 -0.753103,-0.30234 -1.437812,-0.29607 z m 0.482342,1.17002 c 0.433748,-0.004 0.582201,0.0265 0.910784,0.18761 0.726594,0.35682 1.117605,0.98848 1.121257,1.81134 0.006,1.33694 -1.186344,2.25211 -2.396697,2.00715 v -3.98359 c 0.109628,-0.0135 0.228054,-0.0214 0.364656,-0.0225 z"
style="opacity:1;fill:none;fill-opacity:1;stroke:url(#linearGradient1448);stroke-width:0.1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
inkscape:connector-curvature="0" />
<path
id="path1454"
d="m 19.402462,226.26149 -0.314194,0.40566 c -0.172793,0.22309 -0.563209,0.65259 -0.867644,0.95499 -0.461741,0.45847 -0.615657,0.54983 -0.929661,0.54983 -0.214752,0 -0.365893,-0.056 -0.599446,-0.2408 v -0.004 h -2.858741 v 12.0783 h 2.858741 c 4.174205,0.0728 3.931888,-2.28177 6.314861,-2.16937 1.427604,0.0718 1.280898,0.15899 1.725475,-1.02217 l 0.249597,-0.66402 -0.772046,-0.63873 c -0.923009,-0.76346 -1.252622,-1.23997 -1.157552,-1.67278 0.0637,-0.29001 1.160595,-1.44176 1.708939,-1.79419 0.230721,-0.14825 0.234635,-0.17171 0.09198,-0.57309 -0.08187,-0.23032 -0.249296,-0.63158 -0.371555,-0.8909 l -0.222207,-0.47181 h -1.357025 c -1.794983,0 -1.731393,0.0653 -1.734259,-1.75286 l -0.0021,-1.37925 -0.8816,-0.35708 z"
style="opacity:1;fill:none;fill-opacity:1;stroke:url(#linearGradient1485);stroke-width:0.1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
inkscape:connector-curvature="0" />
</g>
<g
transform="translate(63.49728,-55.136805)"
id="g1174" />
<g
transform="translate(50.48327,11.624037)"
id="g1812" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 22 KiB

BIN
icon.icns Normal file

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@@ -12,7 +12,7 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
msgid "translator-credits"
msgstr "Charly\nDmitriy Yefremov"
msgstr "Charly, Dmitriy Yefremov"
# Main
msgid "Service"
@@ -105,9 +105,6 @@ msgstr "Standardbezeichnung setzen"
msgid "Insert marker"
msgstr "Marker einfügen"
msgid "Insert space"
msgstr "Leerzeichen einfügen"
msgid "Locate in services"
msgstr "In den Diensten suchen"
@@ -163,7 +160,7 @@ msgid "Remove"
msgstr "Entfernen"
msgid "Remove all unavailable"
msgstr "Entfernen alle nicht verfügbaren"
msgstr "Entfernt alle nicht verfügbaren"
msgid "Satellites editor"
msgstr "Satelliten-Editor"
@@ -519,9 +516,6 @@ msgstr "Bitte wählen Sie nur einen Eintrag aus!"
msgid "No png file is selected!"
msgstr "Es ist keine png-Datei ausgewählt!"
msgid "No profile selected!"
msgstr "Kein Profil ausgewählt!"
msgid "No reference is present!"
msgstr "Es liegt keine Referenz vor!"
@@ -677,11 +671,11 @@ msgstr "Play Stream"
msgid "Disabled"
msgstr "Ausgeschaltet"
msgid "Enable lamedb ver. 5 support"
msgstr "Lamedb ver. 5 Unterstützung aktivieren"
msgid "Enable ver. 5 support (experimental)"
msgstr "Lamedb ver. 5 Unterstützung aktivieren (experimentell)"
msgid "Enable HTTP API"
msgstr "HTTP-API aktivieren"
msgid "Enable HTTP API (experimental)"
msgstr "HTTP-API aktivieren (experimentell)"
msgid "Switch(zap) the channel(Ctrl + Z)"
msgstr "Umschalten des Kanals (Strg + Z)"
@@ -801,8 +795,8 @@ msgstr "Sprache:"
msgid "Load the last open configuration at program startup"
msgstr "Laden der zuletzt geöffneten Konfiguration beim Programmstart"
msgid "Enable direct playback bar"
msgstr "Aktivieren der direkten Wiedergabeleiste"
msgid "Enable direct playback bar (experimental)"
msgstr "Aktivieren der direkten Wiedergabeleiste (experimentell)"
msgid "Enables direct sending and playback of media links on the receiver"
msgstr "Ermöglicht das direkte Senden und Abspielen von Medienlinks auf dem Box"
@@ -1029,41 +1023,3 @@ msgstr "Screenshot"
msgid "Video"
msgstr "Video"
msgid "The Neutrino has only experimental support. Not all features are supported!"
msgstr "Die Neutrino hat nur experimentelle Unterstützung. Nicht alle Funktionen werden unterstützt!"
msgid "Enable experimental features"
msgstr "Experimentelle Funktionen aktivieren"
msgid "Can't Playback!"
msgstr "Kann nicht abgespielt werden!"
msgid "Enable Dark Mode"
msgstr "Dunkelmodus aktivieren"
msgid "Extract..."
msgstr "Entpacken..."
msgid "Unsupported format!"
msgstr "Nicht unterstütztes Format!"
msgid "Combine with the current data?"
msgstr "Mit den aktuellen Daten kombinieren?"
msgid "Importing data done!"
msgstr "Daten importieren erledigt!"
msgid "Current service"
msgstr "Aktueller Service"
msgid "Open folder"
msgstr "Ordner öffnen"
msgid "Open archive"
msgstr "Archiv öffnen"

View File

@@ -54,7 +54,7 @@ msgid "Current IP:"
msgstr "IP actual:"
msgid "Assign"
msgstr "Asignar"
msgstr "Assignar"
msgid "Bouquet details"
msgstr "Detalles bouquet"
@@ -66,7 +66,7 @@ msgid "Copy"
msgstr "Copiar"
msgid "Copy reference"
msgstr "Copiar referencia"
msgstr "Copia de referencia"
msgid "Download"
msgstr "Descargar"
@@ -123,7 +123,7 @@ msgid "New"
msgstr "Nuevo"
msgid "New bouquet"
msgstr "Nuevo bouquet"
msgstr "Bouquet nuevo"
msgid "Create bouquet"
msgstr "Crear bouquet"
@@ -156,10 +156,10 @@ msgid "Picons"
msgstr "Picons"
msgid "Picons downloader"
msgstr "Descarga de picons"
msgstr "Descargar picons"
msgid "Satellites downloader"
msgstr "Descarga de satélites"
msgstr "Descargar satélites"
msgid "Remove"
msgstr "Quitar"
@@ -210,7 +210,7 @@ msgid "Enigma2 channel and satellites list editor for GNU/Linux"
msgstr "Editor de canales y satélites Enigma2 para GNU/Linux"
msgid "Host:"
msgstr "Host:"
msgstr "Anfitrión:"
msgid "Loading data..."
msgstr "Cargando datos..."
@@ -256,7 +256,7 @@ msgstr "Extra:"
# Filter bar
msgid "Only free"
msgstr "Solamente libres"
msgstr "Solamente gratis"
msgid "All positions"
msgstr "Todas las posiciones"
@@ -272,10 +272,10 @@ msgid "Stop playback"
msgstr "Detener la reproducción"
msgid "Previous stream in the list"
msgstr "Anterior stream en la lista"
msgstr "Anterior flujo en la lista"
msgid "Next stream in the list"
msgstr "Siguiente stream en la lista"
msgstr "Siguiente flujo en la lista"
msgid "Toggle in fullscreen"
msgstr "Cambiar a pantalla completa"
@@ -294,7 +294,7 @@ msgid "Receive picons"
msgstr "Recibir picons"
msgid "Picons name format:"
msgstr "Formato del nombre de los picons:"
msgstr "Picons formato nombres:"
msgid "Resize:"
msgstr "Redimensionar:"
@@ -433,7 +433,7 @@ msgstr "Buscar"
# IPTV dialog
msgid "Stream data"
msgstr "Transmitir stream"
msgstr "Transmitir flujo"
# IPTV list configuration dialog
msgid "Starting values"
@@ -443,7 +443,7 @@ msgid "Reset to default"
msgstr "Restablecer a predeterminado"
msgid "IPTV streams list configuration"
msgstr "Configurar lista de streams IPTV"
msgstr "Configurar lista de flujos IPTV"
# Settings dialog
msgid "Preferences"
@@ -511,13 +511,13 @@ msgid "No m3u file is selected!"
msgstr "¡No se ha seleccionado ningún fichero m3u!"
msgid "Not implemented yet!"
msgstr "¡No implementado!"
msgstr "¡Aún sin implementar!"
msgid "The text of marker is empty, please try again!"
msgstr "¡El texto del marcador está vacío, inténtalo de nuevo!"
msgid "Please, select only one item!"
msgstr "¡Por favor, seleccione un único elemento!"
msgstr "¡Por favor, seleccione sólo un elemento!"
msgid "No png file is selected!"
msgstr "¡No se ha seleccionado ningún fichero png!"
@@ -526,7 +526,7 @@ msgid "No reference is present!"
msgstr "¡Ninguna referencia presente!"
msgid "No selected item!"
msgstr "¡No se ha seleccionado ningún elemento!"
msgstr "¡Ningún elemento seleccionado!"
msgid "The task is already running!"
msgstr "¡La tarea ya se está ejecutando!"
@@ -562,23 +562,23 @@ msgid "Operation not allowed in this context!"
msgstr "¡Operación no permitida en este contexto!"
msgid "No VLC is found. Check that it is installed!"
msgstr "VLC no encontrado. ¡Compruebe que está instalado!"
msgstr "VLC no encontrado. ¡Verifique que está instalado!"
# Search unavailable streams dialog
msgid "Please wait, streams testing in progress..."
msgstr "Por favor espere, hay una prueba de stream en progreso..."
msgstr "Por favor espere, hay una prueba de flujo en progreso..."
msgid "Found"
msgstr "Encontrado"
msgid "unavailable streams."
msgstr "Streams no presentes."
msgstr "Flujos no presentes."
msgid "No changes required!"
msgstr "¡No se requieren cambios!"
msgstr "¡Ningún cambio requerido!"
msgid "This list does not contains IPTV streams!"
msgstr "¡La lista no contiene streams IPTV!"
msgstr "¡La lista no contiene flujos IPTV!"
msgid "New empty configuration"
msgstr "Nueva configuración vacía"
@@ -672,16 +672,16 @@ msgid "Zap"
msgstr "Zapear"
msgid "Play stream"
msgstr "Reproducir stream"
msgstr "Reproducir flujo"
msgid "Disabled"
msgstr "Desactivado"
msgid "Enable lamedb ver. 5 support"
msgstr "Soporte para lamedb ver. 5"
msgid "Enable ver. 5 support (experimental)"
msgstr "Soporte para ver. 5 (experimental)"
msgid "Enable HTTP API"
msgstr "Habilitar API HTTP"
msgid "Enable HTTP API (experimental)"
msgstr "Habilitar API HTTP (experimental)"
msgid "Switch(zap) the channel(Ctrl + Z)"
msgstr "Poner el canal (Ctrl + Z)"
@@ -690,7 +690,7 @@ msgid "Switch the channel and watch in the program(Ctrl + W)"
msgstr "Poner el canal y ver en el programa (Ctrl + W)"
msgid "Play IPTV or other stream in the program(Ctrl + P)"
msgstr "Reproducir IPTV u otro stream en el programa (Ctrl + P)"
msgstr "Reproducir IPTV u otro flujo en el programa (Ctrl + P)"
msgid "Export to m3u"
msgstr "Exportar a m3u"
@@ -795,10 +795,10 @@ msgid "Language:"
msgstr "Idioma:"
msgid "Load the last open configuration at program startup"
msgstr "Cargar la última configuración usada al iniciar el programa"
msgstr "Cargar la última configuración abierta al iniciar el programa"
msgid "Enable direct playback bar"
msgstr "Habilitar la barra de reproducción directa"
msgid "Enable direct playback bar (experimental)"
msgstr "Habilitar la barra de reproducción directa (experimental)"
msgid "Enables direct sending and playback of media links on the receiver"
msgstr "Habilita el envío directo y la reproducción de enlaces de medios en el receptor"
@@ -828,16 +828,16 @@ msgid "Reset"
msgstr "Reset"
msgid "File"
msgstr "Fichero"
msgstr "Archivo"
msgid "Picons manager"
msgstr "Gestor de picons"
msgstr "Picons manager"
msgid "Explorer"
msgstr "Explorador"
msgid "Satellite url:"
msgstr "Url satélite:"
msgstr "Url Satelite:"
msgid "Cut"
msgstr "Cortar"
@@ -867,43 +867,43 @@ msgid "IPTV tools"
msgstr "Intrumentos IPTV"
msgid "Make profile folder as default for the additional data"
msgstr "Usar por defecto el directorio de perfil para los datos adionales"
msgstr "Has folder de perfil estandar para datos adicionales"
msgid "Default data path:"
msgstr "Ruta estándar de datos:"
msgstr "Ruta estandar de datos:"
msgid "Streams record path:"
msgstr "Ruta de grabación del stream:"
msgstr "Ruta de gravacion de stream:"
msgid "Record"
msgstr "Grabación"
msgstr "Gravar"
msgid "Record:"
msgstr "Grabación:"
msgstr "Gravar:"
msgid "Record to disk:"
msgstr "Grabación en disco:"
msgstr "Gravar en disco:"
msgid "Streaming"
msgstr "Streaming"
msgstr "Streameando"
msgid "Activate transcoding"
msgstr "Activar transcodificación"
msgstr "Activer transcodificacion"
msgid "Presets:"
msgstr "Preajustes:"
msgstr "Presets:"
msgid "Video options:"
msgstr "Opciones deo:"
msgstr "Opciones Video:"
msgid "Audio options:"
msgstr "Opciones audio:"
msgstr "Opciones Audio:"
msgid "Bitrate (kb/s):"
msgstr "Bitrate (kb/s):"
msgid "Codec:"
msgstr "Códec:"
msgstr "Codec:"
msgid "Width (px):"
msgstr "Ancho (px):"
@@ -915,10 +915,10 @@ msgid "Channels:"
msgstr "Canales:"
msgid "Sample rate (Hz):"
msgstr "Frecuencia de muestreo (Hz):"
msgstr "Sample rate (Гц):"
msgid "Play streams mode:"
msgstr "Modo de reproducción de los streams:"
msgstr "Tocar en modo streams:"
msgid "Built-in player"
msgstr "Reproductor interno"
@@ -927,40 +927,40 @@ msgid "VLC media player"
msgstr "Reproductor VLC"
msgid "Only get m3u file"
msgstr "Sólo bajar fichero m3u"
msgstr "Solo bajar archivo *.m3u"
msgid "Save and restart the program to apply the settings."
msgstr "Guardar y reiniciar el programa para aplicar la configuración."
msgstr "Guarde y reinicie el programa para aplicar la configuración."
msgid "Some images may have problems displaying the favorites list!"
msgstr "Algunas imágenes pueden tener problemas al mostrar la lista de favoritos!"
msgstr "Algunas imágenes pueden tener problemas para mostrar la lista de favoritos!"
msgid "Operates in standby mode or current active transponder!"
msgstr "¡Funciona en modo de espera o transpondedor activo actual!"
msgstr "Funciona en modo de espera o transpondedor activo actual!"
msgid "No connection to the receiver!"
msgstr "¡Desconectado del receptor!"
msgstr "Sin conexión al receptor!"
msgid "Signal level"
msgstr "Nivel de señal"
msgid "Receiver info"
msgstr "Información sobre el receptor"
msgstr "Informacion sobre receptor"
msgid "A profile with that name exists!"
msgstr "¡Ya existe un perfil con ese nombre!"
msgstr "Existe un perfil con ese nombre!"
msgid "Show short info as hints in the main services list"
msgstr "Mostrar información breve como sugerencias en la lista de servicios principal"
msgid "Show detailed info as hints in the bouquet list"
msgstr "Mostrar información detallada como consejo en la lista de bouquets"
msgstr "Mostrar información detallada como pistas en la lista de bouquet"
msgid "Enable alternate bouquet file naming"
msgstr "Habilitar nombres alternativos para los ficheros de bouquets"
msgstr "Habilitar nombres alternativos de archivos de bouquet"
msgid "Allows you to name bouquet files using their names."
msgstr "Permite nombrar ficheros de bouquets usando sus propios nombres."
msgstr "Le permite nombrar archivos de bouquet usando sus nombres."
msgid "Appearance"
msgstr "Apariencia"
@@ -969,16 +969,16 @@ msgid "Enable Themes support"
msgstr "Habilitar compatibilidad con temas"
msgid "Gtk3 Theme:"
msgstr "Теma Gtk3:"
msgstr "Тема Gtk3:"
msgid "Icon Theme:"
msgstr "Icono del tema:"
msgstr "Тема Icono:"
msgid "Gtk3 Themes and Icons:"
msgstr "Tema Gtk3 e iconos:"
msgstr "Tema Gtk3 e Iconos:"
msgid "Deleting data..."
msgstr "Borrando datos..."
msgstr "Borrando datos ..."
msgid "Download from the receiver"
msgstr "Descargar desde el receptor"
@@ -987,13 +987,13 @@ msgid "Remove all picons from the receiver"
msgstr "Eliminar todos los picons del receptor"
msgid "Service reference"
msgstr "Referencia del servicio"
msgstr "Referencia de servicio"
msgid "Enable support for"
msgstr "Habilitar soporte para"
msgid "Auto-check for updates"
msgstr "Comprobación automática de actualizaciones"
msgstr "Verificación automática de actualizaciones"
msgid "Filter services"
msgstr "Filtrar servicios"
@@ -1005,23 +1005,23 @@ msgid "Destination:"
msgstr "Destino:"
msgid "EXPERIMENTAL!"
msgstr "¡EXPERIMENTAL!"
msgstr "EXPERIMENTAL!"
msgid "Sorting data..."
msgstr "Ordenando datos..."
msgid "There are unsaved changes.\n\n\t Save them now?"
msgstr "Hay cambios sin guardar.\n\n\t ¿Desea guardarlos ahora?"
msgstr "Hay cambios sin guardar.\n\n\t ¿Guardarlos ahora?"
msgid "Are you sure you want to change the order\n\t of services in this bouquet?"
msgstr "¿Está seguro de querer cambiar el orden\n\t de servicios en este bouquet?"
msgstr "¿Está seguro de que desea cambiar el orden\n\t de servicios en este bouquet?"
msgid "Remove from the receiver"
msgstr "Eliminar del receptor"
msgstr "Retirar del receptor"
msgid "Screenshot"
msgstr "Captura de pantalla"
msgid "Video"
msgstr "Vídео"
msgstr "Vidео"

View File

@@ -671,11 +671,11 @@ msgstr "Speel stream af"
msgid "Disabled"
msgstr "Uitgeschakeld"
msgid "Enable lamedb ver. 5 support"
msgstr "Ondersteuning voor lamedb ver. 5 inschakelen"
msgid "Enable ver. 5 support (experimental)"
msgstr "Ondersteuning voor ver. 5 inschakelen (experimenteel)"
msgid "Enable HTTP API"
msgstr "HTTP API inschakelen"
msgid "Enable HTTP API (experimental)"
msgstr "HTTP API inschakelen (experimenteel)"
msgid "Switch(zap) the channel(Ctrl + Z)"
msgstr "Schakelaar (ZAP) naar het kanaal (CTRL + Z)"
@@ -791,8 +791,8 @@ msgstr "Taal:"
msgid "Load the last open configuration at program startup"
msgstr "Laad de laatst geopende configuratie op bij opstart programma"
msgid "Enable direct playback bar"
msgstr "Laat onmiddelijk playback bar toe"
msgid "Enable direct playback bar (experimental)"
msgstr "Laat onmiddelijk playback bar toe (experimenteel)"
msgid "Enables direct sending and playback of media links on the receiver"
msgstr "Laat rechtstreeks versturen van and playback en media links op de ontvanger toe"

View File

@@ -1,7 +1,6 @@
# Copyright (C) 2018-2020 Dmitriy Yefremov
# Copyright (C) 2018-2019 Dmitriy Yefremov
# This file is distributed under the MIT license.
#
#
msgid ""
msgstr ""
"Last-Translator: wwns\n"
@@ -266,9 +265,6 @@ msgstr "Ukryj/Pomiń"
msgid "Parent lock"
msgstr "Blokada rodzicielska"
msgid "There are unsaved changes.\n\n\t Save them now?"
msgstr "Istnieją niezapisane zmiany.\n\n\t Zapisać je teraz?"
# Filter bar
msgid "Only free"
msgstr "Tylko FTA"
@@ -390,12 +386,6 @@ msgid "Remove selection"
msgstr "Usuń wybrane"
# Service details dialog
msgid "To the top"
msgstr "Przenieś na góre bukietu"
msgid "To the end"
msgstr "Przenieś na koniec bukietu"
msgid "Service data:"
msgstr "Dane usług:"
@@ -606,6 +596,9 @@ msgstr "Brak danych do zapisania!"
msgid "Network"
msgstr "Sieć"
msgid "Program"
msgstr "Program"
msgid "Backup"
msgstr "Kopia"
@@ -633,15 +626,6 @@ msgstr "Wyjście"
msgid "Tools"
msgstr "Narzędzia"
msgid "Cut"
msgstr "Wytnij"
msgid "Paste"
msgstr "Wklej"
msgid "Insert space"
msgstr "Wstaw spację"
# Import
msgid "Import"
msgstr "Importuj"
@@ -664,12 +648,12 @@ msgstr "Usuń wszystkie nieużywane"
msgid "Test"
msgstr "Test"
msgid "Details"
msgstr "Właściwości"
msgid "Test connection"
msgstr "Testuj połączenie"
msgid "Double click on the service in the bouquet list:"
msgstr "Kliknij dwukrotnie usługę na liście bukietów:"
msgid "Switch(zap) the channel(Ctrl + Z)"
msgstr "Przełącz(zap) kanał(Ctrl + Z)"
@@ -683,7 +667,7 @@ msgid "Export to m3u"
msgstr "Eksportuj do m3u"
msgid "EPG configuration"
msgstr "Konfiguruj EPG"
msgstr "Koniguruj EPG"
msgid "Apply"
msgstr "Zatwierdź"
@@ -770,11 +754,17 @@ msgstr "Import listy odtwarzania"
msgid "Getting link error:"
msgstr "Błąd pobierania łącza:"
msgid "Apply profile settings"
msgstr "Zastosuj ustawienia profilu"
msgid "Settings type:"
msgstr "Ustawienia dla:"
msgid "Set default"
msgstr "Ustaw domyślnie"
msgstr "Uataw domyślnie"
msgid "Enable direct playback bar (experimental)"
msgstr "Włącz pasek bezpośredniego odtwarzania (eksperymentalnie)"
msgid "Enables direct sending and playback of media links on the receiver"
msgstr "Umożliwia bezpośrednie wysyłanie i odtwarzanie łączy multimedialnych w odbiorniku"
@@ -795,10 +785,7 @@ msgid "Remove picons from the receiver"
msgstr "Usuń pikony z odbiornika"
msgid "Use http to reload data in the receiver."
msgstr "Użyj http aby przeładować dane w odbiorniku."
msgid "Apply profile settings"
msgstr "Zastosuj ustawienia profilu"
msgstr "Użyj http aby ponownie załadować dane do odbiornika."
msgid "Drag or paste the link here"
msgstr "Przeciągnij lub wklej tutaj link"
@@ -821,16 +808,10 @@ msgstr "Pobierz z odbiornika"
msgid "The Neutrino has only experimental support. Not all features are supported!"
msgstr "Neutrino ma jedynie wsparcie eksperymentalne. Nie wszystkie funkcje są obsługiwane!"
msgid "Some images may have problems displaying the favorites list!"
msgstr "Niektóre obrazy mogą mieć problemy z wyświetlaniem listy ulubionych!"
# Appearance
msgid "Appearance"
msgstr "Wygląd"
msgid "Enable Dark Mode"
msgstr "Włącz tryb ciemny"
msgid "Enable Themes support"
msgstr "Włącz obsługę motywów"
@@ -853,17 +834,23 @@ msgstr "Zapisz i uruchom ponownie program, aby zastosować ustawienia."
msgid "Extra"
msgstr "Ekstra"
msgid "Enable ver. 5 support (experimental)"
msgstr "Włącz wer. 5 wsparcie (eksperymentalne)"
msgid "Enable alternate bouquet file naming"
msgstr "Włącz alternatywne nazewnictwo plików bukietów"
msgid "Some images may have problems displaying the favorites list!"
msgstr "Niektóre obrazy mogą mieć problemy z wyświetlaniem listy ulubionych!"
msgid "Allows you to name bouquet files using their names."
msgstr "Pozwala nazwać pliki bukietów przy użyciu ich nazw."
msgid "Enable HTTP API"
msgstr "Włącz API HTTP"
msgid "Enable HTTP API (experimental)"
msgstr "Włącz API HTTP (eksperymentalne)"
msgid "Double click on the service in the bouquet list:"
msgstr "Kliknij dwukrotnie usługę na liście bukietów:"
msgid "Enable send to receiver (experimental)"
msgstr "Włącz wysyłanie do odbiornika (eksperymentalne)"
msgid "Zap"
msgstr "Przełącz"
@@ -880,28 +867,6 @@ msgstr "Odtwórz strumień"
msgid "Disabled"
msgstr "Wyłączone"
msgid "Enable experimental features"
msgstr "Włącz funkcje eksperymentalne"
msgid "Enable lamedb ver. 5 support"
msgstr "Włącz wsparcie dla lamedb w wer.5"
msgid "Enable support for"
msgstr "Włącz obsługę"
msgid "Enables parsing links using youtube-dl to get direct links to media"
msgstr "Umożliwia analizowanie linków za pomocą youtube-dl, aby uzyskać bezpośrednie linki do multimediów"
msgid "Auto-check for updates"
msgstr "Automatyczne sprawdzanie aktualizacji"
msgid "Enable direct playback bar"
msgstr "Włącz pasek bezpośredniego odtwarzania"
#Program
msgid "Program"
msgstr "Program"
msgid "Language:"
msgstr "Język:"
@@ -911,7 +876,7 @@ msgstr "Załaduj ostatnią otwartą konfigurację podczas uruchamiania programu"
msgid "Show short info as hints in the main services list"
msgstr "Pokaż krótkie informacje jako wskazówki na głównej liście usług"
msgid "Show detailed info as hints in the bouquet list"
msgid "Show detailed info as hints in the bouquet list"
msgstr "Pokaż szczegółowe informacje jako wskazówki na liście bukietów"
msgid "Set background color for the services"
@@ -997,8 +962,8 @@ msgstr "Ustawia folder profilu jako domyślny do przechowywania pikonów, kopii
msgid "Default data path:"
msgstr "Domyślna ścieżka danych:"
msgid "Record:"
msgstr "Nagrania:"
msgid "Record"
msgstr "Nagrania"
msgid "Streams record path:"
msgstr "Ścieżka zapisu nagrań:"

View File

@@ -663,11 +663,11 @@ msgstr "Play stream"
msgid "Disabled"
msgstr "Desativado"
msgid "Enable lamedb ver. 5 support"
msgstr "Ativar lamedb ver. 5 suporte"
msgid "Enable ver. 5 support (experimental)"
msgstr "Ativar ver. 5 suporte (experimental)"
msgid "Enable HTTP API"
msgstr "Ativar HTTP API"
msgid "Enable HTTP API (experimental)"
msgstr "Ativar HTTP API (experimental)"
msgid "Switch(zap) the channel(Ctrl + Z)"
msgstr "Mudar(zap) o canal(Ctrl + Z)"
@@ -783,8 +783,8 @@ msgstr "Idioma:"
msgid "Load the last open configuration at program startup"
msgstr "Cargar la última configuración abierta al iniciar el programa"
msgid "Enable direct playback bar"
msgstr "Habilitar la barra de reproducción directa"
msgid "Enable direct playback bar (experimental)"
msgstr "Habilitar la barra de reproducción directa (experimental)"
msgid "Enables direct sending and playback of media links on the receiver"
msgstr "Habilita el envío directo y la reproducción de enlaces de medios en el receptor"

View File

@@ -104,9 +104,6 @@ msgstr "Имя по умолчанию"
msgid "Insert marker"
msgstr "Вставить маркер"
msgid "Insert space"
msgstr "Вставить пробел"
msgid "Locate in services"
msgstr "Найти в списке сервисов"
@@ -510,9 +507,6 @@ msgstr "Пожалуйста, выберите только один элеме
msgid "No png file is selected!"
msgstr "Не выбран png файл!"
msgid "No profile selected!"
msgstr "Не выбран профиль!"
msgid "No reference is present!"
msgstr "Ссылка не найдена!"
@@ -668,17 +662,17 @@ msgstr "Воспр. потока"
msgid "Disabled"
msgstr "Выкл."
msgid "Enable lamedb ver. 5 support"
msgstr "Включить поддержку lamedb вер. 5"
msgid "Enable ver. 5 support (experimental)"
msgstr "Включить поддержку lamedb вер. 5 (экспериментально)"
msgid "Enable HTTP API"
msgstr "Включить HTTP API"
msgid "Enable HTTP API (experimental)"
msgstr "Включить HTTP API (экспериментально)"
msgid "Switch(zap) the channel(Ctrl + Z)"
msgstr "Переключить канал(Ctrl + Z)"
msgid "Switch the channel and watch in the program(Ctrl + W)"
msgstr "Переключить канал и просмотр в программе(Ctrl + W)."
msgstr "Переклють канал и просмотр в программе(Ctrl + W)."
msgid "Play IPTV or other stream in the program(Ctrl + P)"
msgstr "Воспроизведение IPTV или другого потока в программе(Ctrl + P)"
@@ -788,8 +782,8 @@ msgstr "Язык:"
msgid "Load the last open configuration at program startup"
msgstr "Загружать последнюю открытую конфигурацию при запуске программы"
msgid "Enable direct playback bar"
msgstr "Включить панель прямого воспроизведения"
msgid "Enable direct playback bar (experimental)"
msgstr "Включить панель прямого воспроизведения (экспериментально)"
msgid "Enables direct sending and playback of media links on the receiver"
msgstr "Включает прямую отправку и воспроизведение медиа-ссылок на ресивере"
@@ -1016,35 +1010,3 @@ msgstr "Скриншот"
msgid "Video"
msgstr "Видео"
msgid "The Neutrino has only experimental support. Not all features are supported!"
msgstr "Neutrino имеет только экспериментальную поддержку. Поддерживаются не все функции!"
msgid "Enable experimental features"
msgstr "Включить экспериментальные функции"
msgid "Can't Playback!"
msgstr "Не удается воспроизвести!"
msgid "Enable Dark Mode"
msgstr "Включить темный режим"
msgid "Extract..."
msgstr "Извлечь..."
msgid "Unsupported format!"
msgstr "Неподдерживаемый формат!"
msgid "Combine with the current data?"
msgstr "Объединить с текущими данными?"
msgid "Importing data done!"
msgstr "Импорт данных завершен!"
msgid "Current service"
msgstr "Текущий сервис"
msgid "Open folder"
msgstr "Открыть папку"
msgid "Open archive"
msgstr "Открыть архив"

View File

@@ -673,11 +673,11 @@ msgstr "Akışı oynat"
msgid "Disabled"
msgstr "Devre dışı"
msgid "Enable lamedb ver. 5 support"
msgstr "Sürüm 5 desteğini etkinleştir"
msgid "Enable ver. 5 support (experimental)"
msgstr "Sürüm 5 desteğini etkinleştir (deneysel)"
msgid "Enable HTTP API"
msgstr "HTTP API'sini etkinleştir"
msgid "Enable HTTP API (experimental)"
msgstr "HTTP API'sini etkinleştir (deneysel)"
msgid "Switch(zap) the channel(Ctrl + Z)"
msgstr "Kanalı değiştir (zap) (Ctrl + Z)"
@@ -797,8 +797,8 @@ msgstr "Dil:"
msgid "Load the last open configuration at program startup"
msgstr "Program açılışında son açık yapılandırmayı yükle"
msgid "Enable direct playback bar"
msgstr "Doğrudan oynatma çubuğunu etkinleştir"
msgid "Enable direct playback bar (experimental)"
msgstr "Doğrudan oynatma çubuğunu etkinleştir (deneysel)"
msgid "Enables direct sending and playback of media links on the receiver"
msgstr "Alıcıdaki medya bağlantılarının doğrudan gönderilmesini ve oynatılmasını sağlar"

View File

@@ -1,29 +1,19 @@
#!/usr/bin/env python3
import os
def update_icon():
need_update = False
icon_name = "DemonEditor.desktop"
with open(icon_name, "r") as f:
lines = f.readlines()
for i, line in enumerate(lines):
if line.startswith("Icon="):
icon_path = line.lstrip("Icon=")
current_path = "{}/app/ui/icons/hicolor/96x96/apps/demon-editor.png".format(os.getcwd())
if icon_path != current_path:
need_update = True
lines[i] = "Icon={}\n".format(current_path)
break
if need_update:
with open(icon_name, "w") as f:
f.writelines(lines)
try:
from Cocoa import NSBundle
except ImportError as e:
print(e)
else:
ns_bundle = NSBundle.mainBundle()
if ns_bundle:
ns_bundle = ns_bundle.localizedInfoDictionary() or ns_bundle.infoDictionary()
if ns_bundle:
ns_bundle["CFBundleName"] = "DemonEditor"
if __name__ == "__main__":
from multiprocessing import set_start_method
from app.ui.main_app_window import start_app
update_icon()
set_start_method("fork") # For compatibility [Python > 3.7]
start_app()