├── .gitignore
├── .idea
├── encodings.xml
├── misc.xml
├── modules.xml
├── scopes
│ └── scope_settings.xml
├── vcs.xml
├── vix-core.iml
└── workspace.xml
├── AUTHORS
├── ChangeLog
├── LICENSE
├── Makefile.am
├── NEWS
├── README
├── README.md
├── configure.ac
├── etc
├── Makefile.am
├── cron
│ ├── Makefile.am
│ ├── crontabs
│ │ └── Makefile.am
│ └── readme.txt
└── exports
├── m4
├── ax_pthread.m4
├── ax_python_devel.m4
└── tuxbox.m4
├── po
├── Makefile.am
├── ar.po
├── bg.po
├── ca.po
├── cs.po
├── da.po
├── de.po
├── el.po
├── en.po
├── en_GB.po
├── es.po
├── et.po
├── fa.po
├── fi.po
├── fr.po
├── fy.po
├── he.po
├── hr.po
├── hu.po
├── is.po
├── it.po
├── lt.po
├── lv.po
├── nb.po
├── nl.po
├── no.po
├── pl.po
├── pt.po
├── pt_BR.po
├── ro.po
├── ru.po
├── sk.po
├── sl.po
├── sr.po
├── sv.po
├── th.po
├── tr.po
├── uk.po
├── updateallpo-multiOS.sh
├── vix.pot
├── xml2po.py
└── zh_CN.po
└── src
├── BackupManager.py
├── H9SDmanager.py
├── IPKInstaller.py
├── ImageManager.py
├── LICENSE
├── Makefile.am
├── MountManager.py
├── Multibootmgr.py
├── RestoreWizard.py
├── ScriptRunner.py
├── SoftcamManager.py
├── SwapManager.py
├── __init__.py
├── images
├── Makefile.am
├── busy1.png
├── busy10.png
├── busy11.png
├── busy12.png
├── busy13.png
├── busy14.png
├── busy15.png
├── busy16.png
├── busy17.png
├── busy18.png
├── busy19.png
├── busy2.png
├── busy20.png
├── busy21.png
├── busy22.png
├── busy23.png
├── busy24.png
├── busy3.png
├── busy4.png
├── busy5.png
├── busy6.png
├── busy7.png
├── busy8.png
├── busy9.png
├── dev_cdrom.png
├── dev_cf.png
├── dev_hdd.png
├── dev_mmc.png
├── dev_sd.png
└── dev_usb.png
├── install.png
├── installable.png
├── installed.png
├── maintainer.info
├── noprev.png
├── plugin.py
├── remove.png
├── restorewizard.xml
├── setup.xml
├── ui.py
├── update.png
├── upgrade.png
└── upgradeable.png
/.gitignore:
--------------------------------------------------------------------------------
1 | /*.DS_Store
2 |
--------------------------------------------------------------------------------
/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.idea/scopes/scope_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/vix-core.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.idea/workspace.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 | 1391448462663
37 | 1391448462663
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/AUTHORS:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenViX/vix-core/11356134d3a0e0bfb92474e6a079dd2818376e09/AUTHORS
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 2, June 1991
3 |
4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
6 | Everyone is permitted to copy and distribute verbatim copies
7 | of this license document, but changing it is not allowed.
8 |
9 | Preamble
10 |
11 | The licenses for most software are designed to take away your
12 | freedom to share and change it. By contrast, the GNU General Public
13 | License is intended to guarantee your freedom to share and change free
14 | software--to make sure the software is free for all its users. This
15 | General Public License applies to most of the Free Software
16 | Foundation's software and to any other program whose authors commit to
17 | using it. (Some other Free Software Foundation software is covered by
18 | the GNU Lesser General Public License instead.) You can apply it to
19 | your programs, too.
20 |
21 | When we speak of free software, we are referring to freedom, not
22 | price. Our General Public Licenses are designed to make sure that you
23 | have the freedom to distribute copies of free software (and charge for
24 | this service if you wish), that you receive source code or can get it
25 | if you want it, that you can change the software or use pieces of it
26 | in new free programs; and that you know you can do these things.
27 |
28 | To protect your rights, we need to make restrictions that forbid
29 | anyone to deny you these rights or to ask you to surrender the rights.
30 | These restrictions translate to certain responsibilities for you if you
31 | distribute copies of the software, or if you modify it.
32 |
33 | For example, if you distribute copies of such a program, whether
34 | gratis or for a fee, you must give the recipients all the rights that
35 | you have. You must make sure that they, too, receive or can get the
36 | source code. And you must show them these terms so they know their
37 | rights.
38 |
39 | We protect your rights with two steps: (1) copyright the software, and
40 | (2) offer you this license which gives you legal permission to copy,
41 | distribute and/or modify the software.
42 |
43 | Also, for each author's protection and ours, we want to make certain
44 | that everyone understands that there is no warranty for this free
45 | software. If the software is modified by someone else and passed on, we
46 | want its recipients to know that what they have is not the original, so
47 | that any problems introduced by others will not reflect on the original
48 | authors' reputations.
49 |
50 | Finally, any free program is threatened constantly by software
51 | patents. We wish to avoid the danger that redistributors of a free
52 | program will individually obtain patent licenses, in effect making the
53 | program proprietary. To prevent this, we have made it clear that any
54 | patent must be licensed for everyone's free use or not licensed at all.
55 |
56 | The precise terms and conditions for copying, distribution and
57 | modification follow.
58 |
59 | GNU GENERAL PUBLIC LICENSE
60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
61 |
62 | 0. This License applies to any program or other work which contains
63 | a notice placed by the copyright holder saying it may be distributed
64 | under the terms of this General Public License. The "Program", below,
65 | refers to any such program or work, and a "work based on the Program"
66 | means either the Program or any derivative work under copyright law:
67 | that is to say, a work containing the Program or a portion of it,
68 | either verbatim or with modifications and/or translated into another
69 | language. (Hereinafter, translation is included without limitation in
70 | the term "modification".) Each licensee is addressed as "you".
71 |
72 | Activities other than copying, distribution and modification are not
73 | covered by this License; they are outside its scope. The act of
74 | running the Program is not restricted, and the output from the Program
75 | is covered only if its contents constitute a work based on the
76 | Program (independent of having been made by running the Program).
77 | Whether that is true depends on what the Program does.
78 |
79 | 1. You may copy and distribute verbatim copies of the Program's
80 | source code as you receive it, in any medium, provided that you
81 | conspicuously and appropriately publish on each copy an appropriate
82 | copyright notice and disclaimer of warranty; keep intact all the
83 | notices that refer to this License and to the absence of any warranty;
84 | and give any other recipients of the Program a copy of this License
85 | along with the Program.
86 |
87 | You may charge a fee for the physical act of transferring a copy, and
88 | you may at your option offer warranty protection in exchange for a fee.
89 |
90 | 2. You may modify your copy or copies of the Program or any portion
91 | of it, thus forming a work based on the Program, and copy and
92 | distribute such modifications or work under the terms of Section 1
93 | above, provided that you also meet all of these conditions:
94 |
95 | a) You must cause the modified files to carry prominent notices
96 | stating that you changed the files and the date of any change.
97 |
98 | b) You must cause any work that you distribute or publish, that in
99 | whole or in part contains or is derived from the Program or any
100 | part thereof, to be licensed as a whole at no charge to all third
101 | parties under the terms of this License.
102 |
103 | c) If the modified program normally reads commands interactively
104 | when run, you must cause it, when started running for such
105 | interactive use in the most ordinary way, to print or display an
106 | announcement including an appropriate copyright notice and a
107 | notice that there is no warranty (or else, saying that you provide
108 | a warranty) and that users may redistribute the program under
109 | these conditions, and telling the user how to view a copy of this
110 | License. (Exception: if the Program itself is interactive but
111 | does not normally print such an announcement, your work based on
112 | the Program is not required to print an announcement.)
113 |
114 | These requirements apply to the modified work as a whole. If
115 | identifiable sections of that work are not derived from the Program,
116 | and can be reasonably considered independent and separate works in
117 | themselves, then this License, and its terms, do not apply to those
118 | sections when you distribute them as separate works. But when you
119 | distribute the same sections as part of a whole which is a work based
120 | on the Program, the distribution of the whole must be on the terms of
121 | this License, whose permissions for other licensees extend to the
122 | entire whole, and thus to each and every part regardless of who wrote it.
123 |
124 | Thus, it is not the intent of this section to claim rights or contest
125 | your rights to work written entirely by you; rather, the intent is to
126 | exercise the right to control the distribution of derivative or
127 | collective works based on the Program.
128 |
129 | In addition, mere aggregation of another work not based on the Program
130 | with the Program (or with a work based on the Program) on a volume of
131 | a storage or distribution medium does not bring the other work under
132 | the scope of this License.
133 |
134 | 3. You may copy and distribute the Program (or a work based on it,
135 | under Section 2) in object code or executable form under the terms of
136 | Sections 1 and 2 above provided that you also do one of the following:
137 |
138 | a) Accompany it with the complete corresponding machine-readable
139 | source code, which must be distributed under the terms of Sections
140 | 1 and 2 above on a medium customarily used for software interchange; or,
141 |
142 | b) Accompany it with a written offer, valid for at least three
143 | years, to give any third party, for a charge no more than your
144 | cost of physically performing source distribution, a complete
145 | machine-readable copy of the corresponding source code, to be
146 | distributed under the terms of Sections 1 and 2 above on a medium
147 | customarily used for software interchange; or,
148 |
149 | c) Accompany it with the information you received as to the offer
150 | to distribute corresponding source code. (This alternative is
151 | allowed only for noncommercial distribution and only if you
152 | received the program in object code or executable form with such
153 | an offer, in accord with Subsection b above.)
154 |
155 | The source code for a work means the preferred form of the work for
156 | making modifications to it. For an executable work, complete source
157 | code means all the source code for all modules it contains, plus any
158 | associated interface definition files, plus the scripts used to
159 | control compilation and installation of the executable. However, as a
160 | special exception, the source code distributed need not include
161 | anything that is normally distributed (in either source or binary
162 | form) with the major components (compiler, kernel, and so on) of the
163 | operating system on which the executable runs, unless that component
164 | itself accompanies the executable.
165 |
166 | If distribution of executable or object code is made by offering
167 | access to copy from a designated place, then offering equivalent
168 | access to copy the source code from the same place counts as
169 | distribution of the source code, even though third parties are not
170 | compelled to copy the source along with the object code.
171 |
172 | 4. You may not copy, modify, sublicense, or distribute the Program
173 | except as expressly provided under this License. Any attempt
174 | otherwise to copy, modify, sublicense or distribute the Program is
175 | void, and will automatically terminate your rights under this License.
176 | However, parties who have received copies, or rights, from you under
177 | this License will not have their licenses terminated so long as such
178 | parties remain in full compliance.
179 |
180 | 5. You are not required to accept this License, since you have not
181 | signed it. However, nothing else grants you permission to modify or
182 | distribute the Program or its derivative works. These actions are
183 | prohibited by law if you do not accept this License. Therefore, by
184 | modifying or distributing the Program (or any work based on the
185 | Program), you indicate your acceptance of this License to do so, and
186 | all its terms and conditions for copying, distributing or modifying
187 | the Program or works based on it.
188 |
189 | 6. Each time you redistribute the Program (or any work based on the
190 | Program), the recipient automatically receives a license from the
191 | original licensor to copy, distribute or modify the Program subject to
192 | these terms and conditions. You may not impose any further
193 | restrictions on the recipients' exercise of the rights granted herein.
194 | You are not responsible for enforcing compliance by third parties to
195 | this License.
196 |
197 | 7. If, as a consequence of a court judgment or allegation of patent
198 | infringement or for any other reason (not limited to patent issues),
199 | conditions are imposed on you (whether by court order, agreement or
200 | otherwise) that contradict the conditions of this License, they do not
201 | excuse you from the conditions of this License. If you cannot
202 | distribute so as to satisfy simultaneously your obligations under this
203 | License and any other pertinent obligations, then as a consequence you
204 | may not distribute the Program at all. For example, if a patent
205 | license would not permit royalty-free redistribution of the Program by
206 | all those who receive copies directly or indirectly through you, then
207 | the only way you could satisfy both it and this License would be to
208 | refrain entirely from distribution of the Program.
209 |
210 | If any portion of this section is held invalid or unenforceable under
211 | any particular circumstance, the balance of the section is intended to
212 | apply and the section as a whole is intended to apply in other
213 | circumstances.
214 |
215 | It is not the purpose of this section to induce you to infringe any
216 | patents or other property right claims or to contest validity of any
217 | such claims; this section has the sole purpose of protecting the
218 | integrity of the free software distribution system, which is
219 | implemented by public license practices. Many people have made
220 | generous contributions to the wide range of software distributed
221 | through that system in reliance on consistent application of that
222 | system; it is up to the author/donor to decide if he or she is willing
223 | to distribute software through any other system and a licensee cannot
224 | impose that choice.
225 |
226 | This section is intended to make thoroughly clear what is believed to
227 | be a consequence of the rest of this License.
228 |
229 | 8. If the distribution and/or use of the Program is restricted in
230 | certain countries either by patents or by copyrighted interfaces, the
231 | original copyright holder who places the Program under this License
232 | may add an explicit geographical distribution limitation excluding
233 | those countries, so that distribution is permitted only in or among
234 | countries not thus excluded. In such case, this License incorporates
235 | the limitation as if written in the body of this License.
236 |
237 | 9. The Free Software Foundation may publish revised and/or new versions
238 | of the General Public License from time to time. Such new versions will
239 | be similar in spirit to the present version, but may differ in detail to
240 | address new problems or concerns.
241 |
242 | Each version is given a distinguishing version number. If the Program
243 | specifies a version number of this License which applies to it and "any
244 | later version", you have the option of following the terms and conditions
245 | either of that version or of any later version published by the Free
246 | Software Foundation. If the Program does not specify a version number of
247 | this License, you may choose any version ever published by the Free Software
248 | Foundation.
249 |
250 | 10. If you wish to incorporate parts of the Program into other free
251 | programs whose distribution conditions are different, write to the author
252 | to ask for permission. For software which is copyrighted by the Free
253 | Software Foundation, write to the Free Software Foundation; we sometimes
254 | make exceptions for this. Our decision will be guided by the two goals
255 | of preserving the free status of all derivatives of our free software and
256 | of promoting the sharing and reuse of software generally.
257 |
258 | NO WARRANTY
259 |
260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
268 | REPAIR OR CORRECTION.
269 |
270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
278 | POSSIBILITY OF SUCH DAMAGES.
279 |
280 | END OF TERMS AND CONDITIONS
281 |
282 | How to Apply These Terms to Your New Programs
283 |
284 | If you develop a new program, and you want it to be of the greatest
285 | possible use to the public, the best way to achieve this is to make it
286 | free software which everyone can redistribute and change under these terms.
287 |
288 | To do so, attach the following notices to the program. It is safest
289 | to attach them to the start of each source file to most effectively
290 | convey the exclusion of warranty; and each file should have at least
291 | the "copyright" line and a pointer to where the full notice is found.
292 |
293 |
294 | Copyright (C)
295 |
296 | This program is free software; you can redistribute it and/or modify
297 | it under the terms of the GNU General Public License as published by
298 | the Free Software Foundation; either version 2 of the License, or
299 | (at your option) any later version.
300 |
301 | This program is distributed in the hope that it will be useful,
302 | but WITHOUT ANY WARRANTY; without even the implied warranty of
303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
304 | GNU General Public License for more details.
305 |
306 | You should have received a copy of the GNU General Public License along
307 | with this program; if not, write to the Free Software Foundation, Inc.,
308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
309 |
310 | Also add information on how to contact you by electronic and paper mail.
311 |
312 | If the program is interactive, make it output a short notice like this
313 | when it starts in an interactive mode:
314 |
315 | Gnomovision version 69, Copyright (C) year name of author
316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
317 | This is free software, and you are welcome to redistribute it
318 | under certain conditions; type `show c' for details.
319 |
320 | The hypothetical commands `show w' and `show c' should show the appropriate
321 | parts of the General Public License. Of course, the commands you use may
322 | be called something other than `show w' and `show c'; they could even be
323 | mouse-clicks or menu items--whatever suits your program.
324 |
325 | You should also get your employer (if you work as a programmer) or your
326 | school, if any, to sign a "copyright disclaimer" for the program, if
327 | necessary. Here is a sample; alter the names:
328 |
329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program
330 | `Gnomovision' (which makes passes at compilers) written by James Hacker.
331 |
332 | , 1 April 1989
333 | Ty Coon, President of Vice
334 |
335 | This General Public License does not permit incorporating your program into
336 | proprietary programs. If your program is a subroutine library, you may
337 | consider it more useful to permit linking proprietary applications with the
338 | library. If this is what you want to do, use the GNU Lesser General
339 | Public License instead of this License.
340 |
--------------------------------------------------------------------------------
/Makefile.am:
--------------------------------------------------------------------------------
1 | ACLOCAL_AMFLAGS = -I m4
2 |
3 | SUBDIRS = src po etc
4 |
--------------------------------------------------------------------------------
/NEWS:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenViX/vix-core/11356134d3a0e0bfb92474e6a079dd2818376e09/NEWS
--------------------------------------------------------------------------------
/README:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenViX/vix-core/11356134d3a0e0bfb92474e6a079dd2818376e09/README
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://gitter.im/OpenViX/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
2 |
3 | vix-core
4 | ========
5 |
6 | OpenViX Core plugin
7 |
--------------------------------------------------------------------------------
/configure.ac:
--------------------------------------------------------------------------------
1 | AC_INIT(plugins,0.0.1)
2 | AM_INIT_AUTOMAKE(plugins,0.0.1)
3 |
4 | TUXBOX_APPS_DIRECTORY
5 |
6 | AC_PATH_PROG(MSGFMT, msgfmt, AC_MSG_ERROR(Could not find msgfmt))
7 |
8 | AM_PATH_PYTHON
9 | AC_PYTHON_DEVEL
10 |
11 | AC_PROG_CXX
12 |
13 | CPPFLAGS="$CPPFLAGS $PYTHON_CPPFLAGS"
14 | LDFLAGS="$LDFLAGS $PYTHON_LDFLAGS"
15 |
16 | AC_PATH_PROG(MSGFMT, msgfmt, AC_MSG_ERROR(Could not find msgfmt))
17 | AC_PATH_PROG(MSGINIT, msginit, AC_MSG_ERROR(Could not find msginit))
18 | AC_PATH_PROG(MSGMERGE, msgmerge, AC_MSG_ERROR(Could not find msgmerge))
19 | AC_PATH_PROG(MSGUNIQ, msguniq, AC_MSG_ERROR(Could not find msguniq))
20 | AC_PATH_PROG(XGETTEXT, xgettext, AC_MSG_ERROR(Could not find xgettext))
21 |
22 | AC_OUTPUT([
23 | Makefile
24 | etc/Makefile
25 | etc/cron/Makefile
26 | etc/cron/crontabs/Makefile
27 | po/Makefile
28 | src/Makefile
29 | src/images/Makefile
30 | ])
31 |
--------------------------------------------------------------------------------
/etc/Makefile.am:
--------------------------------------------------------------------------------
1 | installdir = /etc/
2 | SUBDIRS = cron
3 | install_DATA = exports
4 |
--------------------------------------------------------------------------------
/etc/cron/Makefile.am:
--------------------------------------------------------------------------------
1 | installdir = ${sysconfdir}/cron
2 | SUBDIRS = crontabs
3 | install_DATA = readme.txt
4 |
--------------------------------------------------------------------------------
/etc/cron/crontabs/Makefile.am:
--------------------------------------------------------------------------------
1 | installdir = ${sysconfdir}/cron/crontabs
2 |
--------------------------------------------------------------------------------
/etc/cron/readme.txt:
--------------------------------------------------------------------------------
1 | To use crontabs, please use the cron manager to setup your crontabs. Alternatively, manually create a file called 'root' and place your required items in there.
2 |
3 | # * * * * * command to execute
4 | # ┬ ┬ ┬ ┬ ┬
5 | # │ │ │ │ │
6 | # │ │ │ │ │
7 | # │ │ │ │ └───── day of week (0 - 7) (0 to 6 are Sunday to Saturday, or use names; 7 is Sunday, the same as 0)
8 | # │ │ │ └────────── month (1 - 12)
9 | # │ │ └─────────────── day of month (1 - 31)
10 | # │ └──────────────────── hour (0 - 23)
11 | # └───────────────────────── min (0 - 59)
12 |
--------------------------------------------------------------------------------
/etc/exports:
--------------------------------------------------------------------------------
1 | /media/hdd/ 192.168.0.0/255.255.0.0(rw,no_root_squash,sync,no_subtree_check)
2 | /media/hdd2/ 192.168.0.0/255.255.0.0(rw,no_root_squash,sync,no_subtree_check)
3 | /media/usb/ 192.168.0.0/255.255.0.0(rw,no_root_squash,sync,no_subtree_check)
4 |
--------------------------------------------------------------------------------
/m4/ax_python_devel.m4:
--------------------------------------------------------------------------------
1 | # ===========================================================================
2 | # https://www.gnu.org/software/autoconf-archive/ax_python_devel.html
3 | # ===========================================================================
4 | #
5 | # SYNOPSIS
6 | #
7 | # AX_PYTHON_DEVEL([version])
8 | #
9 | # DESCRIPTION
10 | #
11 | # Note: Defines as a precious variable "PYTHON_VERSION". Don't override it
12 | # in your configure.ac.
13 | #
14 | # This macro checks for Python and tries to get the include path to
15 | # 'Python.h'. It provides the $(PYTHON_CPPFLAGS) and $(PYTHON_LIBS) output
16 | # variables. It also exports $(PYTHON_EXTRA_LIBS) and
17 | # $(PYTHON_EXTRA_LDFLAGS) for embedding Python in your code.
18 | #
19 | # You can search for some particular version of Python by passing a
20 | # parameter to this macro, for example ">= '2.3.1'", or "== '2.4'". Please
21 | # note that you *have* to pass also an operator along with the version to
22 | # match, and pay special attention to the single quotes surrounding the
23 | # version number. Don't use "PYTHON_VERSION" for this: that environment
24 | # variable is declared as precious and thus reserved for the end-user.
25 | #
26 | # This macro should work for all versions of Python >= 2.1.0. As an end
27 | # user, you can disable the check for the python version by setting the
28 | # PYTHON_NOVERSIONCHECK environment variable to something else than the
29 | # empty string.
30 | #
31 | # If you need to use this macro for an older Python version, please
32 | # contact the authors. We're always open for feedback.
33 | #
34 | # LICENSE
35 | #
36 | # Copyright (c) 2009 Sebastian Huber
37 | # Copyright (c) 2009 Alan W. Irwin
38 | # Copyright (c) 2009 Rafael Laboissiere
39 | # Copyright (c) 2009 Andrew Collier
40 | # Copyright (c) 2009 Matteo Settenvini
41 | # Copyright (c) 2009 Horst Knorr
42 | # Copyright (c) 2013 Daniel Mullner
43 | #
44 | # This program is free software: you can redistribute it and/or modify it
45 | # under the terms of the GNU General Public License as published by the
46 | # Free Software Foundation, either version 3 of the License, or (at your
47 | # option) any later version.
48 | #
49 | # This program is distributed in the hope that it will be useful, but
50 | # WITHOUT ANY WARRANTY; without even the implied warranty of
51 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
52 | # Public License for more details.
53 | #
54 | # You should have received a copy of the GNU General Public License along
55 | # with this program. If not, see .
56 | #
57 | # As a special exception, the respective Autoconf Macro's copyright owner
58 | # gives unlimited permission to copy, distribute and modify the configure
59 | # scripts that are the output of Autoconf when processing the Macro. You
60 | # need not follow the terms of the GNU General Public License when using
61 | # or distributing such scripts, even though portions of the text of the
62 | # Macro appear in them. The GNU General Public License (GPL) does govern
63 | # all other use of the material that constitutes the Autoconf Macro.
64 | #
65 | # This special exception to the GPL applies to versions of the Autoconf
66 | # Macro released by the Autoconf Archive. When you make and distribute a
67 | # modified version of the Autoconf Macro, you may extend this special
68 | # exception to the GPL to apply to your modified version as well.
69 |
70 | #serial 21
71 |
72 | AU_ALIAS([AC_PYTHON_DEVEL], [AX_PYTHON_DEVEL])
73 | AC_DEFUN([AX_PYTHON_DEVEL],[
74 | #
75 | # Allow the use of a (user set) custom python version
76 | #
77 | AC_ARG_VAR([PYTHON_VERSION],[The installed Python
78 | version to use, for example '2.3'. This string
79 | will be appended to the Python interpreter
80 | canonical name.])
81 |
82 | AC_PATH_PROG([PYTHON],[python[$PYTHON_VERSION]])
83 | if test -z "$PYTHON"; then
84 | AC_MSG_ERROR([Cannot find python$PYTHON_VERSION in your system path])
85 | PYTHON_VERSION=""
86 | fi
87 |
88 | #
89 | # Check for a version of Python >= 2.1.0
90 | #
91 | AC_MSG_CHECKING([for a version of Python >= '2.1.0'])
92 | ac_supports_python_ver=`$PYTHON -c "import sys; \
93 | ver = sys.version.split ()[[0]]; \
94 | print (ver >= '2.1.0')"`
95 | if test "$ac_supports_python_ver" != "True"; then
96 | if test -z "$PYTHON_NOVERSIONCHECK"; then
97 | AC_MSG_RESULT([no])
98 | AC_MSG_FAILURE([
99 | This version of the AC@&t@_PYTHON_DEVEL macro
100 | doesn't work properly with versions of Python before
101 | 2.1.0. You may need to re-run configure, setting the
102 | variables PYTHON_CPPFLAGS, PYTHON_LIBS, PYTHON_SITE_PKG,
103 | PYTHON_EXTRA_LIBS and PYTHON_EXTRA_LDFLAGS by hand.
104 | Moreover, to disable this check, set PYTHON_NOVERSIONCHECK
105 | to something else than an empty string.
106 | ])
107 | else
108 | AC_MSG_RESULT([skip at user request])
109 | fi
110 | else
111 | AC_MSG_RESULT([yes])
112 | fi
113 |
114 | #
115 | # if the macro parameter ``version'' is set, honour it
116 | #
117 | if test -n "$1"; then
118 | AC_MSG_CHECKING([for a version of Python $1])
119 | ac_supports_python_ver=`$PYTHON -c "import sys; \
120 | ver = sys.version.split ()[[0]]; \
121 | print (ver $1)"`
122 | if test "$ac_supports_python_ver" = "True"; then
123 | AC_MSG_RESULT([yes])
124 | else
125 | AC_MSG_RESULT([no])
126 | AC_MSG_ERROR([this package requires Python $1.
127 | If you have it installed, but it isn't the default Python
128 | interpreter in your system path, please pass the PYTHON_VERSION
129 | variable to configure. See ``configure --help'' for reference.
130 | ])
131 | PYTHON_VERSION=""
132 | fi
133 | fi
134 |
135 | #
136 | # Check for Python include path
137 | #
138 | AC_MSG_CHECKING([for Python include path])
139 | if test -z "$PYTHON_CPPFLAGS"; then
140 | python_path=`$PYTHON -c "import distutils.sysconfig; \
141 | print (distutils.sysconfig.get_python_inc ());"`
142 | plat_python_path=`$PYTHON -c "import distutils.sysconfig; \
143 | print (distutils.sysconfig.get_python_inc (plat_specific=1));"`
144 | if test -n "${python_path}"; then
145 | if test "${plat_python_path}" != "${python_path}"; then
146 | python_path="-I$python_path -I$plat_python_path"
147 | else
148 | python_path="-I$python_path"
149 | fi
150 | fi
151 | PYTHON_CPPFLAGS=$python_path
152 | fi
153 | AC_MSG_RESULT([$PYTHON_CPPFLAGS])
154 | AC_SUBST([PYTHON_CPPFLAGS])
155 |
156 | #
157 | # Check for Python library path
158 | #
159 | AC_MSG_CHECKING([for Python library path])
160 | if test -z "$PYTHON_LIBS"; then
161 | # (makes two attempts to ensure we've got a version number
162 | # from the interpreter)
163 | ac_python_version=`cat< $@
17 |
18 | vix.pot: vix-py.pot vix-xml.pot
19 | sed --in-place vix-py.pot --expression=s/CHARSET/UTF-8/
20 | sed --in-place vix-xml.pot --expression=s/CHARSET/UTF-8/
21 | cat $^ | $(MSGUNIQ) --no-wrap --no-location -o $@ -
22 |
23 | %.po: vix.pot
24 | if [ -f $@ ]; then \
25 | $(MSGMERGE) --backup=none --no-wrap --no-location -s -N -U $@ $< && touch $@; \
26 | else \
27 | $(MSGINIT) -l $@ -o $@ -i $< --no-translator; \
28 | fi
29 |
30 | .po.mo:
31 | $(MSGFMT) -o $@ $<
32 |
33 | BUILT_SOURCES = $(LANGMO)
34 | CLEANFILES = $(LANGMO) vix-py.pot vix.pot
35 |
36 | dist-hook: $(LANGPO)
37 |
38 | install-data-local: $(LANGMO)
39 | for lang in $(LANGS); do \
40 | $(mkinstalldirs) $(DESTDIR)$(plugindir)/locale/$$lang/LC_MESSAGES; \
41 | $(INSTALL_DATA) $$lang.po $(DESTDIR)$(plugindir)/locale/vix-$$lang.po; \
42 | $(INSTALL_DATA) $$lang.mo $(DESTDIR)$(plugindir)/locale/$$lang/LC_MESSAGES/vix.mo; \
43 | done
44 |
45 | uninstall-local:
46 | for lang in $(LANGS); do \
47 | $(RM) $(DESTDIR)$(plugindir)/locale/vix-$$lang.po; \
48 | $(RM) $(DESTDIR)$(plugindir)/locale/$$lang/LC_MESSAGES/vix.mo; \
49 | done
50 |
--------------------------------------------------------------------------------
/po/fa.po:
--------------------------------------------------------------------------------
1 | # Persian translations for plugins package.
2 | # Copyright (C) 2012 THE plugins'S COPYRIGHT HOLDER
3 | # This file is distributed under the same license as the plugins package.
4 | # Automatically generated, 2012.
5 | #
6 | msgid ""
7 | msgstr ""
8 | "Project-Id-Version: plugins 0.0.1\n"
9 | "Report-Msgid-Bugs-To: \n"
10 | "POT-Creation-Date: 2021-12-18 09:16+0000\n"
11 | "PO-Revision-Date: 2013-10-20 17:17+0100\n"
12 | "Last-Translator: Andy Blackburn \n"
13 | "Language-Team: none\n"
14 | "Language: fa\n"
15 | "MIME-Version: 1.0\n"
16 | "Content-Type: text/plain; charset=UTF-8\n"
17 | "Content-Transfer-Encoding: 8bit\n"
18 |
19 | msgid "%a %e %b %-H:%M"
20 | msgstr ""
21 |
22 | #, python-format
23 | msgid "%s downloads"
24 | msgstr ""
25 |
26 | #, python-format
27 | msgid "%s: "
28 | msgstr ""
29 |
30 | msgid "- Max backups to keep (0==all)"
31 | msgstr ""
32 |
33 | msgid "- Query before backup starts"
34 | msgstr ""
35 |
36 | msgid "- Query before image backup starts"
37 | msgstr ""
38 |
39 | msgid "- Repeat how often"
40 | msgstr ""
41 |
42 | msgid "- Time of backup to start"
43 | msgstr ""
44 |
45 | msgid "128 Mb"
46 | msgstr ""
47 |
48 | msgid "16 Mb"
49 | msgstr ""
50 |
51 | msgid "256 Mb"
52 | msgstr ""
53 |
54 | msgid "30 Days"
55 | msgstr ""
56 |
57 | msgid "32 Mb"
58 | msgstr ""
59 |
60 | msgid "64 Mb"
61 | msgstr ""
62 |
63 | msgid "8 Mb"
64 | msgstr ""
65 |
66 | msgid "96 Mb"
67 | msgstr ""
68 |
69 | msgid "A background update check is in progress, please try again."
70 | msgstr ""
71 |
72 | msgid "A backup has been detected."
73 | msgstr ""
74 |
75 | msgid "Activate"
76 | msgstr ""
77 |
78 | msgid "Active"
79 | msgstr ""
80 |
81 | msgid "Active:"
82 | msgstr ""
83 |
84 | msgid "All"
85 | msgstr ""
86 |
87 | msgid "Allows the script runner to be launched from extensions."
88 | msgstr ""
89 |
90 | msgid "Allows the softcam manager to be launched from extensions."
91 | msgstr ""
92 |
93 | msgid "Allows the softcam to be checked if it stopped working, and restarted automatically if needed."
94 | msgstr ""
95 |
96 | msgid "Allows you to close the window automatically."
97 | msgstr ""
98 |
99 | msgid "Allows you to schedule your backups."
100 | msgstr ""
101 |
102 | msgid "Allows you to schedule your image backups."
103 | msgstr ""
104 |
105 | msgid "Allows you to tag your backups to a box."
106 | msgstr ""
107 |
108 | msgid "Allows you to tag your image backup to a box. (default is box name/type)"
109 | msgstr ""
110 |
111 | msgid "Are you ready to install ?"
112 | msgstr ""
113 |
114 | #, python-format
115 | msgid "Are you sure you want to delete image slot %s ?"
116 | msgstr ""
117 |
118 | msgid ""
119 | "Are you sure you want to download this image:\n"
120 | " "
121 | msgstr ""
122 |
123 | msgid ""
124 | "Are you sure you want to restore this backup:\n"
125 | " "
126 | msgstr ""
127 |
128 | msgid "Automatic settings backup"
129 | msgstr ""
130 |
131 | msgid "Automatically created"
132 | msgstr ""
133 |
134 | msgid "Autostart"
135 | msgstr ""
136 |
137 | msgid "Backing up eMMC partitions for USB flash ..."
138 | msgstr ""
139 |
140 | msgid "Backing up eMMC partitions for USB flash..."
141 | msgstr ""
142 |
143 | msgid "Backing up files..."
144 | msgstr ""
145 |
146 | msgid "Backing up kernel..."
147 | msgstr ""
148 |
149 | msgid "Backing up root file system..."
150 | msgstr ""
151 |
152 | msgid "Backup complete."
153 | msgstr ""
154 |
155 | msgid "Backup complete..."
156 | msgstr ""
157 |
158 | msgid "Backup confirmation"
159 | msgstr ""
160 |
161 | msgid "Backup created"
162 | msgstr ""
163 |
164 | msgid "Backup failed - e. g. wrong backup destination or no space left on backup device."
165 | msgstr ""
166 |
167 | msgid ""
168 | "Backup in progress,\n"
169 | "Please wait for it to finish, before trying again."
170 | msgstr ""
171 |
172 | msgid "Backup location"
173 | msgstr ""
174 |
175 | msgid "Backup manager"
176 | msgstr ""
177 |
178 | msgid "Backup manager settings"
179 | msgstr ""
180 |
181 | msgid "Backup prefix"
182 | msgstr ""
183 |
184 | msgid "Backup/Flash/ReBoot system image."
185 | msgstr ""
186 |
187 | msgid "Backups to keep"
188 | msgstr ""
189 |
190 | msgid "Backups to prune"
191 | msgstr ""
192 |
193 | msgid "CCcam can't run whilst MGcamd is running"
194 | msgstr ""
195 |
196 | msgid "CCcam can't run whilst MGcamd is running."
197 | msgstr ""
198 |
199 | msgid "Cancel"
200 | msgstr ""
201 |
202 | #, python-format
203 | msgid "Cannot unmount partition '%s'. Make sure this partition is not in use. (SWAP, record/timeshift, etc.)"
204 | msgstr ""
205 |
206 | msgid "Change location"
207 | msgstr ""
208 |
209 | msgid "Checking free RAM.."
210 | msgstr ""
211 |
212 | msgid "Checking softcams..."
213 | msgstr ""
214 |
215 | msgid "Choose IPK folder"
216 | msgstr ""
217 |
218 | msgid "Choose files"
219 | msgstr ""
220 |
221 | msgid "Choose where to mount your devices to:"
222 | msgstr ""
223 |
224 | msgid "Close"
225 | msgstr ""
226 |
227 | msgid "Close window on success"
228 | msgstr ""
229 |
230 | msgid "Comparing against backup..."
231 | msgstr ""
232 |
233 | msgid "Compress"
234 | msgstr ""
235 |
236 | msgid "Create"
237 | msgstr ""
238 |
239 | msgid "Create a settings backup before updating."
240 | msgstr ""
241 |
242 | msgid "Create and Manage your SWAP files."
243 | msgstr ""
244 |
245 | msgid "Create:"
246 | msgstr ""
247 |
248 | msgid "Creating SWAP.."
249 | msgstr ""
250 |
251 | msgid "Creating list of installed plugins..."
252 | msgstr ""
253 |
254 | msgid "Creating zip..."
255 | msgstr ""
256 |
257 | msgid "Current status:"
258 | msgstr ""
259 |
260 | msgid "Daily"
261 | msgstr ""
262 |
263 | msgid "Deactivate"
264 | msgstr ""
265 |
266 | msgid "Delete"
267 | msgstr ""
268 |
269 | msgid "Delete failure - check device available."
270 | msgstr ""
271 |
272 | msgid "Deselect"
273 | msgstr ""
274 |
275 | msgid "Developer password"
276 | msgstr ""
277 |
278 | msgid "Developer username"
279 | msgstr ""
280 |
281 | #, python-format
282 | msgid "Device %s"
283 | msgstr ""
284 |
285 | msgid "Device: "
286 | msgstr ""
287 |
288 | msgid "Device: None available"
289 | msgstr ""
290 |
291 | msgid "Device: none available"
292 | msgstr ""
293 |
294 | msgid "Disable startup"
295 | msgstr ""
296 |
297 | msgid ""
298 | "Do you want to create a full image backup?\n"
299 | "This can take about 6 minutes to complete."
300 | msgstr ""
301 |
302 | #, python-format
303 | msgid ""
304 | "Do you want to flash image\n"
305 | "%s"
306 | msgstr ""
307 |
308 | msgid "Do you want to restart GUI now ?"
309 | msgstr ""
310 |
311 | msgid "Do you want to restore your Enigma2 plugins ?"
312 | msgstr ""
313 |
314 | msgid "Do you want to restore your Enigma2 settings ?"
315 | msgstr ""
316 |
317 | msgid "Do you want to restore your enigma2 settings ?"
318 | msgstr ""
319 |
320 | msgid "DownLoad"
321 | msgstr ""
322 |
323 | msgid "Download"
324 | msgstr ""
325 |
326 | msgid "Download confirmation"
327 | msgstr ""
328 |
329 | msgid "Downloading"
330 | msgstr ""
331 |
332 | msgid "Downloads"
333 | msgstr ""
334 |
335 | msgid "ET8500 Image Restore"
336 | msgstr ""
337 |
338 | msgid ""
339 | "ET8500 Multiboot: Yes to restore OS1 No to restore OS2:\n"
340 | " "
341 | msgstr ""
342 |
343 | msgid "Empty slot"
344 | msgstr ""
345 |
346 | msgid "Enable SWAP at startup"
347 | msgstr ""
348 |
349 | msgid "Enable frozen check"
350 | msgstr ""
351 |
352 | msgid "Enable startup"
353 | msgstr ""
354 |
355 | msgid "Enough retries, delaying till next schedule."
356 | msgstr ""
357 |
358 | msgid "Enter your OpenViX developer password."
359 | msgstr ""
360 |
361 | msgid "Enter your OpenViX developer username."
362 | msgstr ""
363 |
364 | msgid "Erase"
365 | msgstr ""
366 |
367 | msgid "Exit the restore wizard"
368 | msgstr ""
369 |
370 | msgid "Expand"
371 | msgstr ""
372 |
373 | msgid "Extra IPK's"
374 | msgstr ""
375 |
376 | msgid "Flash"
377 | msgstr ""
378 |
379 | msgid "Flash image unzip successful."
380 | msgstr ""
381 |
382 | msgid "Found non-standard softcam, trying to start, this may fail."
383 | msgstr ""
384 |
385 | msgid "Free space:"
386 | msgstr ""
387 |
388 | msgid "From which image library do you want to download?"
389 | msgstr ""
390 |
391 | msgid "Frozen check interval"
392 | msgstr ""
393 |
394 | msgid "H9 SDcard manager"
395 | msgstr ""
396 |
397 | msgid "H9SDcard Manager"
398 | msgstr ""
399 |
400 | msgid "INFO"
401 | msgstr ""
402 |
403 | msgid "IPK installer"
404 | msgstr ""
405 |
406 | msgid "If you are an OpenViX developer you can enter your login details to have direct access to OpenViX developer images for your receiver. This feature is only available via 'https' connections."
407 | msgstr ""
408 |
409 | msgid "Image manager"
410 | msgstr ""
411 |
412 | msgid "Image manager settings"
413 | msgstr ""
414 |
415 | msgid "Inactive"
416 | msgstr ""
417 |
418 | msgid "Include machine name in backup name"
419 | msgstr ""
420 |
421 | msgid "Info"
422 | msgstr ""
423 |
424 | msgid "Init SDcard"
425 | msgstr ""
426 |
427 | msgid "Init USB/SDA1"
428 | msgstr ""
429 |
430 | msgid "Init Zgemma H9 SDCARD - please reboot after use."
431 | msgstr ""
432 |
433 | msgid "Init Zgemma H9 USB/SDA1 - please reboot after use."
434 | msgstr ""
435 |
436 | msgid "Install"
437 | msgstr ""
438 |
439 | msgid "Install IPK's from your tmp folder."
440 | msgstr ""
441 |
442 | msgid "Install confirmation"
443 | msgstr ""
444 |
445 | msgid "Install extensions."
446 | msgstr ""
447 |
448 | msgid "Install local extension"
449 | msgstr ""
450 |
451 | msgid "Installing..."
452 | msgstr ""
453 |
454 | msgid "Invert"
455 | msgstr ""
456 |
457 | msgid "Ipkg"
458 | msgstr ""
459 |
460 | msgid "It seems you have not setup an extra location. Please set it up in the Backup manager setup menu."
461 | msgstr ""
462 |
463 | msgid "Location of where backup should be saved."
464 | msgstr ""
465 |
466 | msgid "Location of where the image backup should be saved."
467 | msgstr ""
468 |
469 | msgid "Login as an OpenViX developer"
470 | msgstr ""
471 |
472 | msgid "Logs"
473 | msgstr ""
474 |
475 | msgid "MB"
476 | msgstr ""
477 |
478 | msgid "MENU"
479 | msgstr ""
480 |
481 | msgid "MGcamd can't run whilst CCcam is running."
482 | msgstr ""
483 |
484 | msgid "Manage settings backup."
485 | msgstr ""
486 |
487 | msgid "Manage your devices mount points."
488 | msgstr ""
489 |
490 | msgid "Max image backups to keep (0==all)"
491 | msgstr ""
492 |
493 | msgid "Maximum number of backups to keep. Older backups are given priority for removal, so the fresher ones remain."
494 | msgstr ""
495 |
496 | msgid "Mount"
497 | msgstr ""
498 |
499 | #, python-format
500 | msgid "Mount failed for '%s', error code = '%s'."
501 | msgstr ""
502 |
503 | msgid "Mount manager"
504 | msgstr ""
505 |
506 | msgid "Mount: "
507 | msgstr ""
508 |
509 | msgid "Move Nand root to SD card"
510 | msgstr ""
511 |
512 | msgid "Moving to backup Location..."
513 | msgstr ""
514 |
515 | msgid "Multiboot ERROR! - no STARTUP in boot partition."
516 | msgstr ""
517 |
518 | msgid "Multiboot image manager"
519 | msgstr ""
520 |
521 | msgid "Multiboot only able to restore this backup to mmc slot1"
522 | msgstr ""
523 |
524 | msgid "NO, do not restore plugins"
525 | msgstr ""
526 |
527 | msgid "NO, do not restore settings"
528 | msgstr ""
529 |
530 | msgid "New backup"
531 | msgstr ""
532 |
533 | msgid "Next backup: "
534 | msgstr ""
535 |
536 | msgid ""
537 | "No config files found, please setup CCcam first\n"
538 | "in /etc/CCcam.cfg."
539 | msgstr ""
540 |
541 | msgid ""
542 | "No config files found, please setup Hypercam first\n"
543 | "in /etc/hypercam.cfg."
544 | msgstr ""
545 |
546 | msgid ""
547 | "No config files found, please setup MGcamd first\n"
548 | "in /usr/keys."
549 | msgstr ""
550 |
551 | msgid ""
552 | "No config files found, please setup Ncam first\n"
553 | "in /etc/tuxbox/config"
554 | msgstr ""
555 |
556 | msgid ""
557 | "No config files found, please setup Ncam first\n"
558 | "in /etc/tuxbox/config."
559 | msgstr ""
560 |
561 | msgid ""
562 | "No config files found, please setup Oscam first\n"
563 | "in /etc/tuxbox/config"
564 | msgstr ""
565 |
566 | msgid ""
567 | "No config files found, please setup Oscam first\n"
568 | "in /etc/tuxbox/config."
569 | msgstr ""
570 |
571 | msgid "No images found on the selected download server...if password check validity"
572 | msgstr ""
573 |
574 | msgid "No plugins needed to be installed"
575 | msgstr ""
576 |
577 | msgid "None"
578 | msgstr ""
579 |
580 | msgid "Note: slot list does not show current image or empty slots."
581 | msgstr ""
582 |
583 | msgid "Now skipping restore process"
584 | msgstr ""
585 |
586 | msgid "OK"
587 | msgstr ""
588 |
589 | msgid "OK, to perform a restore"
590 | msgstr ""
591 |
592 | msgid "Only scheduled"
593 | msgstr ""
594 |
595 | #, python-format
596 | msgid "Partition: %s Mount: %s unmounted successfully; if all partitions now unmounted you can remove device."
597 | msgstr ""
598 |
599 | msgid "Please enter a folder that contains some packages."
600 | msgstr ""
601 |
602 | msgid "Please select device to use as SWAP file location."
603 | msgstr ""
604 |
605 | msgid "Please select the file to restore."
606 | msgstr ""
607 |
608 | msgid "Please wait while plugins restore completes..."
609 | msgstr ""
610 |
611 | msgid "Please wait while scanning for devices..."
612 | msgstr ""
613 |
614 | #, python-format
615 | msgid "Please wait while scanning your %s %s devices..."
616 | msgstr ""
617 |
618 | msgid "Please wait while settings restore completes..."
619 | msgstr ""
620 |
621 | msgid "Please wait while starting\n"
622 | msgstr ""
623 |
624 | msgid "Please wait while stopping\n"
625 | msgstr ""
626 |
627 | msgid "Please wait while the flash prepares."
628 | msgstr ""
629 |
630 | msgid "Please wait while the system gathers information..."
631 | msgstr ""
632 |
633 | msgid "Please wait."
634 | msgstr ""
635 |
636 | msgid "Plugin listing failed - e. g. wrong backup destination or no space left on backup device."
637 | msgstr ""
638 |
639 | msgid "Preparing extra plugins..."
640 | msgstr ""
641 |
642 | msgid "Press 'Menu' to select a storage device"
643 | msgstr ""
644 |
645 | msgid "Press OK to toggle the selection."
646 | msgstr ""
647 |
648 | msgid "Press appropiate Init to move Nand root to SDcard or USB."
649 | msgstr ""
650 |
651 | msgid "Query before starting backup."
652 | msgstr ""
653 |
654 | msgid "Query before starting image backup."
655 | msgstr ""
656 |
657 | msgid "Reboot"
658 | msgstr ""
659 |
660 | msgid "Rebooting..."
661 | msgstr ""
662 |
663 | #, python-format
664 | msgid ""
665 | "Recording(s) are in progress or coming up in few seconds!\n"
666 | "Do you still want to flash image\n"
667 | "%s?"
668 | msgstr ""
669 |
670 | #, python-format
671 | msgid "Removal of this slot will not show in %s Gui. Are you sure you want to delete image slot %s ?"
672 | msgstr ""
673 |
674 | msgid "Remove confirmation"
675 | msgstr ""
676 |
677 | msgid "Removing temp mounts..."
678 | msgstr ""
679 |
680 | msgid "Restart"
681 | msgstr ""
682 |
683 | #, python-format
684 | msgid "Restart %s %s."
685 | msgstr ""
686 |
687 | msgid "Restart GUI."
688 | msgstr ""
689 |
690 | msgid "Restore"
691 | msgstr ""
692 |
693 | msgid "Restore Confirmation"
694 | msgstr ""
695 |
696 | msgid "Restore wizard"
697 | msgstr ""
698 |
699 | msgid "Restoring backup..."
700 | msgstr ""
701 |
702 | msgid "Restoring plugins, this can take a long time..."
703 | msgstr ""
704 |
705 | msgid "Restoring plugins..."
706 | msgstr ""
707 |
708 | msgid "Retrieving image slots - Please wait..."
709 | msgstr ""
710 |
711 | msgid "Run"
712 | msgstr ""
713 |
714 | msgid "Run your shell scripts."
715 | msgstr ""
716 |
717 | msgid "SWAP file not found. You have to create the file before you try to activate it."
718 | msgstr ""
719 |
720 | msgid "SWAP manager"
721 | msgstr ""
722 |
723 | msgid "SWAP place:"
724 | msgstr ""
725 |
726 | msgid "SWAP size:"
727 | msgstr ""
728 |
729 | msgid "Save"
730 | msgstr ""
731 |
732 | msgid "Schedule backups"
733 | msgstr ""
734 |
735 | msgid "Script runner"
736 | msgstr ""
737 |
738 | msgid "Script runner settings"
739 | msgstr ""
740 |
741 | msgid "Select"
742 | msgstr ""
743 |
744 | msgid "Select a backup to restore:"
745 | msgstr ""
746 |
747 | msgid "Select a package to install:"
748 | msgstr ""
749 |
750 | #, python-format
751 | msgid "Select an image to download for %s:"
752 | msgstr ""
753 |
754 | msgid "Select an image to flash:"
755 | msgstr ""
756 |
757 | msgid "Select extra packages folder"
758 | msgstr ""
759 |
760 | msgid "Select files/folders to backup"
761 | msgstr ""
762 |
763 | msgid "Select folder that contains plugins"
764 | msgstr ""
765 |
766 | msgid "Select the SWAP file size:"
767 | msgstr ""
768 |
769 | msgid "Select:"
770 | msgstr ""
771 |
772 | msgid "Set the interval to be checked in mins."
773 | msgstr ""
774 |
775 | msgid "Set the repeat interval of backup schedule."
776 | msgstr ""
777 |
778 | msgid "Set the time of backup to start."
779 | msgstr ""
780 |
781 | msgid "Setting up..."
782 | msgstr ""
783 |
784 | msgid "Setup mounts"
785 | msgstr ""
786 |
787 | msgid "Show in extensions"
788 | msgstr ""
789 |
790 | msgid "Size: "
791 | msgstr ""
792 |
793 | #, python-format
794 | msgid "Size: %sGB"
795 | msgstr ""
796 |
797 | #, python-format
798 | msgid "Size: %sMB"
799 | msgstr ""
800 |
801 | #, python-format
802 | msgid "Size: %sTB"
803 | msgstr ""
804 |
805 | msgid "Size: unavailable"
806 | msgstr ""
807 |
808 | msgid "Softcam manager"
809 | msgstr ""
810 |
811 | msgid "Softcam manager settings"
812 | msgstr ""
813 |
814 | msgid "Softcam starting..."
815 | msgstr ""
816 |
817 | msgid "Softcam stopping..."
818 | msgstr ""
819 |
820 | msgid "SoftcamCheck"
821 | msgstr ""
822 |
823 | msgid "Sorry but that location does not exist or is not setup. Please set it up in the Backup manager setup menu."
824 | msgstr ""
825 |
826 | msgid "Sorry the feeds are down for maintenance. Please try again later."
827 | msgstr ""
828 |
829 | msgid "Sorry the feeds are down for maintenance. Please try using Backup manager to restore plugins later."
830 | msgstr ""
831 |
832 | msgid "Sorry the feeds are down for maintenance. Please try using the Backup manager to restore plugins later."
833 | msgstr ""
834 |
835 | msgid "Sorry, but the file is not compatible with this image version."
836 | msgstr ""
837 |
838 | msgid "Sorry, but the restore failed."
839 | msgstr ""
840 |
841 | msgid "Sorry, no physical devices that supports SWAP attached. Can't create SWAP file on network or fat32 file-systems."
842 | msgstr ""
843 |
844 | msgid "Sorry, not enough free RAM found, and no physical devices that supports SWAP attached. Can't create SWAP file on network or fat32 file-systems, unable to make backup."
845 | msgstr ""
846 |
847 | msgid "Start"
848 | msgstr ""
849 |
850 | msgid "Starting..."
851 | msgstr ""
852 |
853 | msgid "Status:"
854 | msgstr ""
855 |
856 | msgid "Stop"
857 | msgstr ""
858 |
859 | msgid "Temp folder"
860 | msgstr ""
861 |
862 | msgid "The backup location does not have enough free space."
863 | msgstr ""
864 |
865 | msgid "The backup location does not have enough free space.\n"
866 | msgstr ""
867 |
868 | #, python-format
869 | msgid ""
870 | "The changes need a system restart to take effect.\n"
871 | "Restart your %s %s now?"
872 | msgstr ""
873 |
874 | msgid "The chosen location does not exist, using /media/hdd."
875 | msgstr ""
876 |
877 | msgid "The name of the receiver can be included in the backup filename, but makes the filename lengthy."
878 | msgstr ""
879 |
880 | msgid "The wizard is finished now, and will reboot."
881 | msgstr ""
882 |
883 | msgid "The wizard is finished now."
884 | msgstr ""
885 |
886 | msgid "There is a problem with this device. Please reformat it and try again."
887 | msgstr ""
888 |
889 | msgid "There is no backup to restore."
890 | msgstr ""
891 |
892 | msgid "There is no image to flash."
893 | msgstr ""
894 |
895 | msgid "This device is already mounted as HDD."
896 | msgstr ""
897 |
898 | msgid "Type: "
899 | msgstr ""
900 |
901 | msgid "Types of backups to remove when stale."
902 | msgstr ""
903 |
904 | msgid "Un-mount"
905 | msgstr ""
906 |
907 | #, python-format
908 | msgid ""
909 | "Unzip error (also sent to any debug log):\n"
910 | "%s"
911 | msgstr ""
912 |
913 | msgid "Updating mount locations..."
914 | msgstr ""
915 |
916 | msgid "Use as HDD"
917 | msgstr ""
918 |
919 | msgid "Use the cursor keys to select an installed image and then Erase button."
920 | msgstr ""
921 |
922 | msgid "ViX"
923 | msgstr ""
924 |
925 | msgid "ViX Backup manager"
926 | msgstr ""
927 |
928 | msgid "ViX Image Management"
929 | msgstr ""
930 |
931 | msgid "ViX Image manager"
932 | msgstr ""
933 |
934 | msgid "ViX Mount manager"
935 | msgstr ""
936 |
937 | msgid "ViX SWAP manager"
938 | msgstr ""
939 |
940 | msgid "ViX Script runner"
941 | msgstr ""
942 |
943 | msgid "View progress"
944 | msgstr ""
945 |
946 | msgid "Wait please while creating SWAP file..."
947 | msgstr ""
948 |
949 | msgid ""
950 | "Wait please while scanning\n"
951 | "for softcam's..."
952 | msgstr ""
953 |
954 | msgid "Wait please while scanning..."
955 | msgstr ""
956 |
957 | msgid "Weekly"
958 | msgstr ""
959 |
960 | msgid ""
961 | "Welcome to the restore wizard.\n"
962 | "\n"
963 | "A backup has been detected.\n"
964 | "You can use this wizard to restore your settings and any extra plugins that were installed when the backup was created.\n"
965 | msgstr ""
966 |
967 | msgid "YES, to restore plugins"
968 | msgstr ""
969 |
970 | msgid "YES, to restore settings"
971 | msgstr ""
972 |
973 | msgid "You have decided not to flash image."
974 | msgstr ""
975 |
976 | msgid "You have to create a SWAP file before trying to activate the autostart."
977 | msgstr ""
978 |
979 | #, python-format
980 | msgid "Your %s %s could not connect to the plugin feeds at this time. Please try using the Backup manager to restore plugins later."
981 | msgstr ""
982 |
983 | #, python-format
984 | msgid ""
985 | "Your %s %s is about to create a full image backup, this can take about 6 minutes to complete.\n"
986 | "Do you want to allow this?"
987 | msgstr ""
988 |
989 | #, python-format
990 | msgid ""
991 | "Your %s %s is about to run a backup of your settings and to detect your plugins.\n"
992 | "Do you want to allow this?"
993 | msgstr ""
994 |
995 | #, python-format
996 | msgid "Your %s %s is not connected to a network. Please check your network settings and try again."
997 | msgstr ""
998 |
999 | #, python-format
1000 | msgid "Your %s %s is not connected to a network. Please try using the Backup manager to restore plugins later when a network connection is available."
1001 | msgstr ""
1002 |
1003 | #, python-format
1004 | msgid "Your %s %s is not connected to the Internet. Please check your network settings and try again."
1005 | msgstr ""
1006 |
1007 | #, python-format
1008 | msgid "Your %s %s is not connected to the Internet. Please try using Backup manager to restore plugins later."
1009 | msgstr ""
1010 |
1011 | #, python-format
1012 | msgid "Your %s %s is not connected to the Internet. Please try using the Backup manager to restore plugins later."
1013 | msgstr ""
1014 |
1015 | #, python-format
1016 | msgid ""
1017 | "ofgwrite error (also sent to any debug log):\n"
1018 | "%s"
1019 | msgstr ""
1020 |
1021 | #, python-format
1022 | msgid "slot%s - %s"
1023 | msgstr ""
1024 |
1025 | #, python-format
1026 | msgid "slot%s - %s "
1027 | msgstr ""
1028 |
1029 | #, python-format
1030 | msgid "slot%s - %s (current image)"
1031 | msgstr ""
1032 |
1033 | msgid "unavailable"
1034 | msgstr ""
1035 |
--------------------------------------------------------------------------------
/po/updateallpo-multiOS.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # Script to generate po and pot files
3 | # Author: Pr2
4 | # Version: 1.0
5 | #
6 | # This script is derivated from updateallpo.sh it is intended to all you
7 | # create the updated version of the pot and po files on different environment:
8 | # For Windows, please download and install the following program:
9 | # Python:
10 | # https://www.python.org/
11 | # GitForWindows:
12 | # https://gitforwindows.org/
13 | #
14 | # Pre-requisite for Windows:
15 | # -> install python on your PC
16 | # -> install Git for Windows, you can keep all default installation settings.
17 | # -> Start the installed: git-bash you will see a command prompt.
18 | # -> At the git-bash command prompt we will clone the repository (see below):
19 | #
20 | # For Mac OSX download and install homebrew following explanation from:
21 | # https://brew.sh/
22 | #
23 | # For Mac OSX with homebrew and also Linux users:
24 | # The following tools must be installed on your system and accessible from path:
25 | # gawk, find, gettext, gnu-sed, python
26 | # Start and terminal and clone OpenPLi repository (see below):
27 | #
28 | # On All platforms please download and install:
29 | #
30 | # PoEdit: https://poedit.net/
31 | #
32 | # -------------------------------------------------------------------------------------
33 | # Run this script from within the locale folder.
34 | #
35 | remote="origin"
36 | branch="master"
37 | python="python"
38 | localgsed="sed"
39 | findoptions=""
40 | delete=1
41 | plugin="vix"
42 |
43 | function this_help () {
44 | printf "Possible options are:\n"
45 | printf " -r | --remote to specify the remote git to use, default[origin]\n"
46 | printf " -b | --branch to specify the branch to translate, default[develop]\n"
47 | printf " -p | --python to specify the python runtime name, default[python]\n"
48 | printf " -h | --help this text\n\n"
49 | printf "To translate for the develop branch simply run this script without any option.\n"
50 | printf "To translate for the rc branch simply specify:\n"
51 | printf "%s -branch rc \nor\n%s -b rc\n" $0 $0
52 | printf "\n\n"
53 | printf "Pre-requisites:\n\n"
54 | printf "Please read the OpenPLi translators wiki page:\n"
55 | printf "https://wiki.openpli.org/Information_for_Translators\n"
56 | return 0
57 | }
58 |
59 | while [ "$1" != "" ]; do
60 | case "$1" in
61 | -b|--branch)
62 | shift
63 | branch="$1"
64 | ;;
65 | -r|--remote)
66 | shift
67 | remote="$1"
68 | ;;
69 | -p|--python)
70 | shift
71 | python="$1"
72 | ;;
73 | -h|--help)
74 | this_help
75 | exit 0
76 | ;;
77 | *)
78 | printf "Error: unknown parameter [%s]\n\n" "$1"
79 | this_help
80 | exit 1
81 | esac
82 | shift
83 | done
84 | #
85 | # Checking if defined remote exist
86 | #
87 |
88 | (git remote -v | grep -q "$remote\s") \
89 | && { printf "Remote git : [%s]\n" $remote; } \
90 | || { printf "Sorry this remote doesn't exist: [%s]\n Valid remotes are:\n" $remote; \
91 | git remote -v ; exit 1; }
92 | #
93 | # Checking if remote branch exist on the defined remote
94 | #
95 |
96 | (git branch -r | grep -q "$remote/""$branch""$") \
97 | && { printf "Remote branch : [%s]\n" $branch; } \
98 | || { printf "Sorry this branch doesn't exist: [%s]\n Valid branches are:\n" $branch; \
99 | git branch -r | grep $remote | sed 's/"$remote"\///'; exit 1; }
100 | #
101 | # Checking for Python version number to select the right python script to use
102 | #
103 | command -v "$python" >/dev/null 2>&1 || { printf >&2 "Script requires python but it's not installed. Aborting."; \
104 | printf "Please download latest version and install it from: https://www.python.org/\n"; exit 1; }
105 | printf "Python used [%s]: " "$python"
106 | "$python" --version
107 | #
108 | # Checking for gettext component
109 | #
110 | command -v xgettext --version >/dev/null 2>&1 || { printf "Please install gettext package on your system. Aborting.\n"; exit 1; }
111 | command -v msguniq --version >/dev/null 2>&1 || { printf "Please install gettext package on your system. Aborting.\n"; exit 1; }
112 | #
113 | # On Mac OSX find option are specific
114 | #
115 | if [[ "$OSTYPE" == "darwin"* ]]
116 | then
117 | # Mac OSX
118 | printf "Script running on Mac OSX [%s]\n" "$OSTYPE"
119 | findoptions=" -s -X "
120 | fi
121 | #
122 | # Script only run with sed but on some distro normal sed is already sed so checking it.
123 | #
124 | sed --version 2> /dev/null | grep -q "GNU"
125 | if [ $? -eq 0 ]; then
126 | localgsed="sed"
127 | else
128 | "$localgsed" --version | grep -q "GNU"
129 | if [ $? -eq 0 ]; then
130 | printf "GNU sed found: [%s]\n" $localgsed
131 | fi
132 | fi
133 | #
134 | # Needed when run in git-bash for Windows
135 | #
136 | export PYTHONIOENCODING=utf-8
137 | #
138 | # To fix the LF (Linux, Mac) and CRLF (Windows) conflict
139 | #
140 | git config core.eol lf
141 | git config core.autocrlf input
142 | git config core.safecrlf true
143 | #
144 | # Git commands to sync with origin and create the branch MyTranslation to work on.
145 | #
146 | git pull
147 | #
148 | # Retrieve all existing languages to update
149 | #
150 | printf "Po files update/creation from script starting.\n"
151 | languages=($(ls *.po | tr "\n" " " | sed 's/.po//g'))
152 |
153 | # If you want to define the language locally in this script uncomment and defined languages
154 | #languages=("ar" "bg" "ca" "cs" "da" "de" "el" "en" "es" "et" "fa" "fi" "fr" "fy" "he" "hk" "hr" "hu" "id" "is" "it" "ku" "lt" "lv" "nl" "nb" "nn" "pl" "pt" "pt_BR" "ro" "ru" "sk" "sl" "sr" "sv" "th" "tr" "uk" "zh")
155 |
156 | printf "Creating temporary file %s-py.pot\n" $plugin
157 | find $findoptions .. -name "*.py" -exec xgettext --no-wrap -L Python --from-code=UTF-8 -kpgettext:1c,2 --add-comments="TRANSLATORS:" -d enigma2 -s -o "$plugin"-py.pot {} \+
158 | "$localgsed" --in-place "$plugin"-py.pot --expression=s/CHARSET/UTF-8/
159 | printf "Merging pot files to create: %s.pot\n" "$plugin"
160 | cat "$plugin"-py.pot | msguniq --no-wrap -o "$plugin".pot -
161 | OLDIFS=$IFS
162 | IFS=" "
163 | for lang in "${languages[@]}" ; do
164 | if [ -f $lang.po ]; then \
165 | printf "Updating existing translation file %s.po\n" $lang
166 | msgmerge --backup=none --no-wrap -s -U $lang.po "$plugin".pot && touch $lang.po; \
167 | msgattrib --no-wrap --no-obsolete $lang.po -o $lang.po; \
168 | msgfmt -o $lang.mo $lang.po; \
169 | else \
170 | printf "New file created: %s.po, please add it to github before commit\n" $lang
171 | msginit -l $lang.po -o $lang.po -i "$plugin".pot --no-translator; \
172 | msgfmt -o $lang.mo $lang.po; \
173 | fi
174 | done
175 | if [ $delete -eq 1 ]; then \
176 | rm "$plugin"-py.pot
177 | fi
178 | IFS=$OLDIFS
179 | printf "Po files update/creation from script finished!\n"
180 | printf "Edit with PoEdit the po file that you want to translate located in:\n\n"
181 | command -v cygpath > /dev/null && { cygpath -w "$PWD"; } || { pwd; }
182 | printf "\n\n"
183 | printf "PoEdit: https://poedit.net/\n"
184 | printf "IMPORTANT: in PoEdit go into Files-Preferences menu select the advanced tab\n"
185 | printf " 1) select Unix(recommended) for carriage return\n"
186 | printf " 2) unselect wrap text\n"
187 | printf " 3) unselect keep original file format\n"
188 | printf "You only need to do this once in PoEdit.\n\n"
189 | printf "Please read the translators wiki page:\n"
190 | printf "\nhttps://wiki.openpli.org/Information_for_Translators\n"
191 | rm -rf *.mo
192 | chmod 644 *.po
193 |
--------------------------------------------------------------------------------
/po/xml2po.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | # -*- coding: utf-8 -*-
3 | from __future__ import print_function
4 | try:
5 | import builtins
6 | except ImportError:
7 | import __builtin__ as builtins
8 |
9 | import sys
10 | import os
11 | import re
12 | from xml.sax import make_parser
13 | from xml.sax.handler import ContentHandler, property_lexical_handler
14 |
15 | try:
16 | from _xmlplus.sax.saxlib import LexicalHandler
17 | no_comments = False
18 | except ImportError:
19 | class LexicalHandler:
20 | def __init__(self):
21 | pass
22 |
23 | no_comments = True
24 |
25 |
26 | class parseXML(ContentHandler, LexicalHandler):
27 | def __init__(self, attrlist):
28 | self.isPointsElement, self.isReboundsElement = 0, 0
29 | self.attrlist = attrlist
30 | self.last_comment = None
31 | self.ishex = re.compile('#[0-9a-fA-F]+\Z')
32 |
33 | def comment(self, comment):
34 | if "TRANSLATORS:" in comment:
35 | self.last_comment = comment
36 |
37 | def startElement(self, name, attrs):
38 | for x in ["text", "title", "value", "caption", "summary", "description"]:
39 | try:
40 | k = builtins.str(attrs[x])
41 | if k.strip() != "" and not self.ishex.match(k):
42 | attrlist.add((k, self.last_comment))
43 | self.last_comment = None
44 | except KeyError:
45 | pass
46 |
47 |
48 | parser = make_parser()
49 |
50 | attrlist = set()
51 |
52 | contentHandler = parseXML(attrlist)
53 | parser.setContentHandler(contentHandler)
54 | if not no_comments:
55 | parser.setProperty(property_lexical_handler, contentHandler)
56 |
57 | for arg in sys.argv[1:]:
58 | if os.path.isdir(arg):
59 | for file in os.listdir(arg):
60 | if file.endswith(".xml"):
61 | parser.parse(os.path.join(arg, file))
62 | else:
63 | parser.parse(arg)
64 |
65 | attrlist = list(attrlist)
66 | attrlist.sort(key=lambda a: a[0])
67 |
68 | for (k, c) in attrlist:
69 | print()
70 | print('#: ' + arg)
71 | k.replace("\\n", "\"\n\"")
72 | if c:
73 | for l in c.split('\n'):
74 | print("#. ", l)
75 | print('msgid "' + builtins.str(k) + '"')
76 | print('msgstr ""')
77 |
78 | attrlist = set()
79 |
--------------------------------------------------------------------------------
/src/H9SDmanager.py:
--------------------------------------------------------------------------------
1 | from __future__ import print_function, absolute_import
2 |
3 | from boxbranding import getMachineBuild
4 | from Components.ActionMap import ActionMap
5 | from Components.ChoiceList import ChoiceList, ChoiceEntryComponent
6 | from Components.config import config
7 | from Components.Label import Label
8 | from Components.Sources.StaticText import StaticText
9 | from Components.SystemInfo import SystemInfo
10 | from Screens.Console import Console
11 | from Screens.Screen import Screen
12 | from Screens.MessageBox import MessageBox
13 | from Screens.Standby import TryQuitMainloop
14 | from Tools.BoundFunction import boundFunction
15 |
16 |
17 | class H9SDmanager(Screen):
18 |
19 | skin = """
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 | """
35 |
36 | def __init__(self, session):
37 | Screen.__init__(self, session)
38 | self.skinName = "H9SDmanager"
39 | self.setTitle(_("H9 SDcard manager"))
40 | self["labe14"] = StaticText(_("Press appropiate Init to move Nand root to SDcard or USB."))
41 | self["key_red"] = StaticText(_("Reboot"))
42 | self["key_green"] = StaticText(_("Init SDcard"))
43 | self["key_yellow"] = StaticText(_("Init USB/SDA1"))
44 | self["actions"] = ActionMap(["OkCancelActions", "ColorActions"],
45 | {
46 | "red": self.reboot,
47 | "green": self.SDInit,
48 | "yellow": self.USBInit,
49 | "ok": boundFunction(self.close, None),
50 | "cancel": boundFunction(self.close, None),
51 | }, -1)
52 | self.onLayoutFinish.append(self.layoutFinished)
53 |
54 | def layoutFinished(self):
55 | self.setTitle(_("H9 SDcard manager"))
56 |
57 | def SDInit(self):
58 | if SystemInfo["HasH9SD"]:
59 | self.TITLE = _("Init Zgemma H9 SDCARD - please reboot after use.")
60 | cmdlist = []
61 | cmdlist.append("opkg update")
62 | cmdlist.append("opkg install rsync")
63 | cmdlist.append("umount /dev/mmcblk0p1")
64 | cmdlist.append("dd if=/dev/zero of=/dev/mmcblk0p1 bs=1M count=150")
65 | cmdlist.append("mkfs.ext4 -L 'H9-ROOTFS' /dev/mmcblk0p1")
66 | # cmdlist.append("parted -s /dev/mmcblk0 rm 1")
67 | # cmdlist.append("parted -s /dev/mmcblk0 mklabel gpt")
68 | # cmdlist.append("parted -s /dev/mmcblk0 mkpart rootfs2 ext4 0% 100%")
69 | cmdlist.append("mkdir /tmp/mmc")
70 | cmdlist.append("mount /dev/mmcblk0p1 /tmp/mmc")
71 | cmdlist.append("mkdir /tmp/root")
72 | cmdlist.append("mount --bind / /tmp/root")
73 | cmdlist.append("rsync -aAX /tmp/root/ /tmp/mmc/")
74 | cmdlist.append("umount /tmp/root")
75 | cmdlist.append("umount /tmp/mmc")
76 | cmdlist.append("rmdir /tmp/root")
77 | cmdlist.append("rmdir /tmp/mmc")
78 | self.session.open(Console, title=self.TITLE, cmdlist=cmdlist, closeOnSuccess=True)
79 | else:
80 | self.close()
81 |
82 | def reboot(self):
83 | self.session.open(TryQuitMainloop, 2)
84 |
85 | def USBInit(self):
86 | self.TITLE = _("Init Zgemma H9 USB/SDA1 - please reboot after use.")
87 | cmdlist = []
88 | cmdlist.append("opkg update")
89 | cmdlist.append("opkg install rsync")
90 | cmdlist.append("umount /dev/mmcblk0p1")
91 | cmdlist.append("dd if=/dev/zero of=/dev/sda1 bs=1M count=150")
92 | cmdlist.append("mkfs.ext4 -L 'H9-ROOTFS' /dev/sda1")
93 | # cmdlist.append("mkfs.ext4 -L 'rootfs2' /dev/sda1")
94 | cmdlist.append("mkdir /tmp/mmc")
95 | cmdlist.append("mount /dev/mmcblk0p1 /tmp/mmc")
96 | cmdlist.append("mkdir /tmp/root")
97 | cmdlist.append("mount --bind / /tmp/root")
98 | cmdlist.append("rsync -aAX /tmp/root/ /tmp/mmc/")
99 | cmdlist.append("umount /tmp/root")
100 | cmdlist.append("umount /tmp/mmc")
101 | cmdlist.append("rmdir /tmp/root")
102 | cmdlist.append("rmdir /tmp/mmc")
103 | self.session.open(Console, title=self.TITLE, cmdlist=cmdlist, closeOnSuccess=True)
104 |
--------------------------------------------------------------------------------
/src/IPKInstaller.py:
--------------------------------------------------------------------------------
1 | from os import listdir, path
2 |
3 | from . import _
4 |
5 | from Components.ActionMap import ActionMap
6 | from Components.Button import Button
7 | from Components.config import config
8 | from Components.Ipkg import IpkgComponent
9 | from Components.Label import Label
10 | from Components.MenuList import MenuList
11 | from Components.SelectionList import SelectionList
12 | from Components.Sources.StaticText import StaticText
13 | from Screens.Console import Console
14 | from Screens.Ipkg import Ipkg
15 | from Screens.MessageBox import MessageBox
16 | from Screens.Screen import Screen
17 | from Screens.Standby import TryQuitMainloop
18 |
19 |
20 | class VIXIPKInstaller(Screen):
21 | skin = ["""
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
34 | """,
35 | 560, 400, # screen
36 | 0, 0, 140, 40, #colors
37 | 140, 0, 140, 40,
38 | 280, 0, 140, 40,
39 | 0, 0, 140, 40, 20,
40 | 140, 0, 140, 40, 20,
41 | 280, 0, 140, 40, 20,
42 | 0, 50, 560, 50, 18, # lab1
43 | 10, 105, 540, 260, 20, # list
44 | 26,
45 | ]
46 |
47 | def __init__(self, session):
48 | Screen.__init__(self, session)
49 | self.setTitle(_("IPK installer"))
50 |
51 | self["lab1"] = Label()
52 | self.defaultDir = "/tmp"
53 | self.onChangedEntry = []
54 | self["myactions"] = ActionMap(["ColorActions", "OkCancelActions", "DirectionActions", "MenuActions"],
55 | {
56 | "cancel": self.close,
57 | "red": self.close,
58 | "green": self.keyInstall,
59 | "yellow": self.changelocation,
60 | "ok": self.keyInstall,
61 | "menu": self.close,
62 | }, -1)
63 |
64 | self["key_red"] = Button(_("Close"))
65 | self["key_green"] = Button(_("Install"))
66 | self["key_yellow"] = Button()
67 |
68 | self.list = []
69 | self["list"] = MenuList(self.list)
70 | self.populate_List()
71 |
72 | if not self.selectionChanged in self["list"].onSelectionChanged:
73 | self["list"].onSelectionChanged.append(self.selectionChanged)
74 |
75 | def createSummary(self):
76 | from Screens.PluginBrowser import PluginBrowserSummary
77 |
78 | return PluginBrowserSummary
79 |
80 | def selectionChanged(self):
81 | item = self["list"].getCurrent()
82 | if item:
83 | name = item
84 | desc = ""
85 | else:
86 | name = ""
87 | desc = ""
88 | for cb in self.onChangedEntry:
89 | cb(name, desc)
90 |
91 | def changelocation(self):
92 | if self.defaultDir == "/tmp":
93 | self["key_yellow"].setText(_("Extra IPK's"))
94 | self.defaultDir = config.backupmanager.xtraplugindir.value
95 | if not self.defaultDir:
96 | message = _("It seems you have not setup an extra location. Please set it up in the Backup manager setup menu.")
97 | ybox = self.session.open(MessageBox, message, MessageBox.TYPE_INFO)
98 | ybox.setTitle(_("Change location"))
99 | elif self.defaultDir and not path.exists(self.defaultDir):
100 | message = _("Sorry but that location does not exist or is not setup. Please set it up in the Backup manager setup menu.")
101 | ybox = self.session.open(MessageBox, message, MessageBox.TYPE_INFO)
102 | ybox.setTitle(_("Change location"))
103 | else:
104 | self.populate_List()
105 | else:
106 | self["key_yellow"].setText(_("Temp folder"))
107 | self.defaultDir = "/tmp"
108 | self.populate_List()
109 |
110 | def populate_List(self):
111 | if self.defaultDir == "/tmp":
112 | self["key_yellow"].setText(_("Extra IPK's"))
113 | else:
114 | self["key_yellow"].setText(_("Temp folder"))
115 |
116 | self["lab1"].setText(_("Select a package to install:"))
117 |
118 | del self.list[:]
119 | f = listdir(self.defaultDir)
120 | for line in f:
121 | if line.find(".ipk") != -1:
122 | self.list.append(line)
123 |
124 | if path.ismount("/media/usb"):
125 | f = listdir("/media/usb")
126 | for line in f:
127 | if line.find(".ipk") != -1:
128 | self.list.append(line)
129 |
130 | self.list.sort()
131 | self["list"].l.setList(self.list)
132 |
133 | def keyInstall(self):
134 | message = _("Are you ready to install ?")
135 | ybox = self.session.openWithCallback(self.Install, MessageBox, message, MessageBox.TYPE_YESNO)
136 | ybox.setTitle(_("Install confirmation"))
137 |
138 | def Install(self, answer):
139 | if answer is True:
140 | sel = self["list"].getCurrent()
141 | if sel:
142 | self.defaultDir = self.defaultDir.replace(" ", "%20")
143 | cmd1 = "/usr/bin/opkg install " + path.join(self.defaultDir, sel)
144 | self.session.openWithCallback(self.installFinished(sel), Console, title=_("Installing..."), cmdlist=[cmd1], closeOnSuccess=True)
145 |
146 | def installFinished(self, sel):
147 | message = _("Do you want to restart GUI now ?")
148 | ybox = self.session.openWithCallback(self.restBox, MessageBox, message, MessageBox.TYPE_YESNO)
149 | ybox.setTitle(_("Restart GUI."))
150 |
151 | def restBox(self, answer):
152 | if answer is True:
153 | self.session.open(TryQuitMainloop, 3)
154 | else:
155 | self.populate_List()
156 | self.close()
157 |
158 | def myclose(self):
159 | self.close()
160 |
161 |
162 | class IpkgInstaller(Screen):
163 | skin = ["""
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 | """,
177 | 560, 450, # screen
178 | 0, 0, 140, 40, #colors
179 | 140, 0, 140, 40,
180 | 280, 0, 140, 40,
181 | 420, 0, 140, 40,
182 | 0, 0, 140, 40, 20,
183 | 140, 0, 140, 40, 20,
184 | 280, 0, 140, 40, 20,
185 | 420, 0, 140, 40, 20,
186 | 5, 50, 540, 360, 20, # list
187 | 0, 410, 560, 2,
188 | 5, 420, 550, 30, 22,
189 | ]
190 |
191 | def __init__(self, session, list):
192 | Screen.__init__(self, session)
193 | Screen.setTitle(self, _("IPK installer"))
194 | self.list = SelectionList()
195 | self["list"] = self.list
196 | for listindex in range(len(list)):
197 | if not list[listindex].split("/")[-1].startswith("._"):
198 | self.list.addSelection(list[listindex].split("/")[-1], list[listindex], listindex, False)
199 |
200 | self["key_red"] = StaticText(_("Close"))
201 | self["key_green"] = StaticText(_("Install"))
202 | self["key_yellow"] = StaticText()
203 | self["key_blue"] = StaticText(_("Invert"))
204 | self["introduction"] = StaticText(_("Press OK to toggle the selection."))
205 |
206 | self["actions"] = ActionMap(["OkCancelActions", "ColorActions"],
207 | {
208 | "ok": self.list.toggleSelection,
209 | "cancel": self.close,
210 | "red": self.close,
211 | "green": self.install,
212 | "blue": self.list.toggleAllSelection
213 | }, -1)
214 |
215 | def install(self):
216 | list = self.list.getSelectionsList()
217 | cmdList = []
218 | for item in list:
219 | cmdList.append((IpkgComponent.CMD_INSTALL, {"package": item[1]}))
220 | self.session.open(Ipkg, cmdList=cmdList)
221 |
--------------------------------------------------------------------------------
/src/LICENSE:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 2, June 1991
3 |
4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
6 | Everyone is permitted to copy and distribute verbatim copies
7 | of this license document, but changing it is not allowed.
8 |
9 | Preamble
10 |
11 | The licenses for most software are designed to take away your
12 | freedom to share and change it. By contrast, the GNU General Public
13 | License is intended to guarantee your freedom to share and change free
14 | software--to make sure the software is free for all its users. This
15 | General Public License applies to most of the Free Software
16 | Foundation's software and to any other program whose authors commit to
17 | using it. (Some other Free Software Foundation software is covered by
18 | the GNU Lesser General Public License instead.) You can apply it to
19 | your programs, too.
20 |
21 | When we speak of free software, we are referring to freedom, not
22 | price. Our General Public Licenses are designed to make sure that you
23 | have the freedom to distribute copies of free software (and charge for
24 | this service if you wish), that you receive source code or can get it
25 | if you want it, that you can change the software or use pieces of it
26 | in new free programs; and that you know you can do these things.
27 |
28 | To protect your rights, we need to make restrictions that forbid
29 | anyone to deny you these rights or to ask you to surrender the rights.
30 | These restrictions translate to certain responsibilities for you if you
31 | distribute copies of the software, or if you modify it.
32 |
33 | For example, if you distribute copies of such a program, whether
34 | gratis or for a fee, you must give the recipients all the rights that
35 | you have. You must make sure that they, too, receive or can get the
36 | source code. And you must show them these terms so they know their
37 | rights.
38 |
39 | We protect your rights with two steps: (1) copyright the software, and
40 | (2) offer you this license which gives you legal permission to copy,
41 | distribute and/or modify the software.
42 |
43 | Also, for each author's protection and ours, we want to make certain
44 | that everyone understands that there is no warranty for this free
45 | software. If the software is modified by someone else and passed on, we
46 | want its recipients to know that what they have is not the original, so
47 | that any problems introduced by others will not reflect on the original
48 | authors' reputations.
49 |
50 | Finally, any free program is threatened constantly by software
51 | patents. We wish to avoid the danger that redistributors of a free
52 | program will individually obtain patent licenses, in effect making the
53 | program proprietary. To prevent this, we have made it clear that any
54 | patent must be licensed for everyone's free use or not licensed at all.
55 |
56 | The precise terms and conditions for copying, distribution and
57 | modification follow.
58 |
59 | GNU GENERAL PUBLIC LICENSE
60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
61 |
62 | 0. This License applies to any program or other work which contains
63 | a notice placed by the copyright holder saying it may be distributed
64 | under the terms of this General Public License. The "Program", below,
65 | refers to any such program or work, and a "work based on the Program"
66 | means either the Program or any derivative work under copyright law:
67 | that is to say, a work containing the Program or a portion of it,
68 | either verbatim or with modifications and/or translated into another
69 | language. (Hereinafter, translation is included without limitation in
70 | the term "modification".) Each licensee is addressed as "you".
71 |
72 | Activities other than copying, distribution and modification are not
73 | covered by this License; they are outside its scope. The act of
74 | running the Program is not restricted, and the output from the Program
75 | is covered only if its contents constitute a work based on the
76 | Program (independent of having been made by running the Program).
77 | Whether that is true depends on what the Program does.
78 |
79 | 1. You may copy and distribute verbatim copies of the Program's
80 | source code as you receive it, in any medium, provided that you
81 | conspicuously and appropriately publish on each copy an appropriate
82 | copyright notice and disclaimer of warranty; keep intact all the
83 | notices that refer to this License and to the absence of any warranty;
84 | and give any other recipients of the Program a copy of this License
85 | along with the Program.
86 |
87 | You may charge a fee for the physical act of transferring a copy, and
88 | you may at your option offer warranty protection in exchange for a fee.
89 |
90 | 2. You may modify your copy or copies of the Program or any portion
91 | of it, thus forming a work based on the Program, and copy and
92 | distribute such modifications or work under the terms of Section 1
93 | above, provided that you also meet all of these conditions:
94 |
95 | a) You must cause the modified files to carry prominent notices
96 | stating that you changed the files and the date of any change.
97 |
98 | b) You must cause any work that you distribute or publish, that in
99 | whole or in part contains or is derived from the Program or any
100 | part thereof, to be licensed as a whole at no charge to all third
101 | parties under the terms of this License.
102 |
103 | c) If the modified program normally reads commands interactively
104 | when run, you must cause it, when started running for such
105 | interactive use in the most ordinary way, to print or display an
106 | announcement including an appropriate copyright notice and a
107 | notice that there is no warranty (or else, saying that you provide
108 | a warranty) and that users may redistribute the program under
109 | these conditions, and telling the user how to view a copy of this
110 | License. (Exception: if the Program itself is interactive but
111 | does not normally print such an announcement, your work based on
112 | the Program is not required to print an announcement.)
113 |
114 | These requirements apply to the modified work as a whole. If
115 | identifiable sections of that work are not derived from the Program,
116 | and can be reasonably considered independent and separate works in
117 | themselves, then this License, and its terms, do not apply to those
118 | sections when you distribute them as separate works. But when you
119 | distribute the same sections as part of a whole which is a work based
120 | on the Program, the distribution of the whole must be on the terms of
121 | this License, whose permissions for other licensees extend to the
122 | entire whole, and thus to each and every part regardless of who wrote it.
123 |
124 | Thus, it is not the intent of this section to claim rights or contest
125 | your rights to work written entirely by you; rather, the intent is to
126 | exercise the right to control the distribution of derivative or
127 | collective works based on the Program.
128 |
129 | In addition, mere aggregation of another work not based on the Program
130 | with the Program (or with a work based on the Program) on a volume of
131 | a storage or distribution medium does not bring the other work under
132 | the scope of this License.
133 |
134 | 3. You may copy and distribute the Program (or a work based on it,
135 | under Section 2) in object code or executable form under the terms of
136 | Sections 1 and 2 above provided that you also do one of the following:
137 |
138 | a) Accompany it with the complete corresponding machine-readable
139 | source code, which must be distributed under the terms of Sections
140 | 1 and 2 above on a medium customarily used for software interchange; or,
141 |
142 | b) Accompany it with a written offer, valid for at least three
143 | years, to give any third party, for a charge no more than your
144 | cost of physically performing source distribution, a complete
145 | machine-readable copy of the corresponding source code, to be
146 | distributed under the terms of Sections 1 and 2 above on a medium
147 | customarily used for software interchange; or,
148 |
149 | c) Accompany it with the information you received as to the offer
150 | to distribute corresponding source code. (This alternative is
151 | allowed only for noncommercial distribution and only if you
152 | received the program in object code or executable form with such
153 | an offer, in accord with Subsection b above.)
154 |
155 | The source code for a work means the preferred form of the work for
156 | making modifications to it. For an executable work, complete source
157 | code means all the source code for all modules it contains, plus any
158 | associated interface definition files, plus the scripts used to
159 | control compilation and installation of the executable. However, as a
160 | special exception, the source code distributed need not include
161 | anything that is normally distributed (in either source or binary
162 | form) with the major components (compiler, kernel, and so on) of the
163 | operating system on which the executable runs, unless that component
164 | itself accompanies the executable.
165 |
166 | If distribution of executable or object code is made by offering
167 | access to copy from a designated place, then offering equivalent
168 | access to copy the source code from the same place counts as
169 | distribution of the source code, even though third parties are not
170 | compelled to copy the source along with the object code.
171 |
172 | 4. You may not copy, modify, sublicense, or distribute the Program
173 | except as expressly provided under this License. Any attempt
174 | otherwise to copy, modify, sublicense or distribute the Program is
175 | void, and will automatically terminate your rights under this License.
176 | However, parties who have received copies, or rights, from you under
177 | this License will not have their licenses terminated so long as such
178 | parties remain in full compliance.
179 |
180 | 5. You are not required to accept this License, since you have not
181 | signed it. However, nothing else grants you permission to modify or
182 | distribute the Program or its derivative works. These actions are
183 | prohibited by law if you do not accept this License. Therefore, by
184 | modifying or distributing the Program (or any work based on the
185 | Program), you indicate your acceptance of this License to do so, and
186 | all its terms and conditions for copying, distributing or modifying
187 | the Program or works based on it.
188 |
189 | 6. Each time you redistribute the Program (or any work based on the
190 | Program), the recipient automatically receives a license from the
191 | original licensor to copy, distribute or modify the Program subject to
192 | these terms and conditions. You may not impose any further
193 | restrictions on the recipients' exercise of the rights granted herein.
194 | You are not responsible for enforcing compliance by third parties to
195 | this License.
196 |
197 | 7. If, as a consequence of a court judgment or allegation of patent
198 | infringement or for any other reason (not limited to patent issues),
199 | conditions are imposed on you (whether by court order, agreement or
200 | otherwise) that contradict the conditions of this License, they do not
201 | excuse you from the conditions of this License. If you cannot
202 | distribute so as to satisfy simultaneously your obligations under this
203 | License and any other pertinent obligations, then as a consequence you
204 | may not distribute the Program at all. For example, if a patent
205 | license would not permit royalty-free redistribution of the Program by
206 | all those who receive copies directly or indirectly through you, then
207 | the only way you could satisfy both it and this License would be to
208 | refrain entirely from distribution of the Program.
209 |
210 | If any portion of this section is held invalid or unenforceable under
211 | any particular circumstance, the balance of the section is intended to
212 | apply and the section as a whole is intended to apply in other
213 | circumstances.
214 |
215 | It is not the purpose of this section to induce you to infringe any
216 | patents or other property right claims or to contest validity of any
217 | such claims; this section has the sole purpose of protecting the
218 | integrity of the free software distribution system, which is
219 | implemented by public license practices. Many people have made
220 | generous contributions to the wide range of software distributed
221 | through that system in reliance on consistent application of that
222 | system; it is up to the author/donor to decide if he or she is willing
223 | to distribute software through any other system and a licensee cannot
224 | impose that choice.
225 |
226 | This section is intended to make thoroughly clear what is believed to
227 | be a consequence of the rest of this License.
228 |
229 | 8. If the distribution and/or use of the Program is restricted in
230 | certain countries either by patents or by copyrighted interfaces, the
231 | original copyright holder who places the Program under this License
232 | may add an explicit geographical distribution limitation excluding
233 | those countries, so that distribution is permitted only in or among
234 | countries not thus excluded. In such case, this License incorporates
235 | the limitation as if written in the body of this License.
236 |
237 | 9. The Free Software Foundation may publish revised and/or new versions
238 | of the General Public License from time to time. Such new versions will
239 | be similar in spirit to the present version, but may differ in detail to
240 | address new problems or concerns.
241 |
242 | Each version is given a distinguishing version number. If the Program
243 | specifies a version number of this License which applies to it and "any
244 | later version", you have the option of following the terms and conditions
245 | either of that version or of any later version published by the Free
246 | Software Foundation. If the Program does not specify a version number of
247 | this License, you may choose any version ever published by the Free Software
248 | Foundation.
249 |
250 | 10. If you wish to incorporate parts of the Program into other free
251 | programs whose distribution conditions are different, write to the author
252 | to ask for permission. For software which is copyrighted by the Free
253 | Software Foundation, write to the Free Software Foundation; we sometimes
254 | make exceptions for this. Our decision will be guided by the two goals
255 | of preserving the free status of all derivatives of our free software and
256 | of promoting the sharing and reuse of software generally.
257 |
258 | NO WARRANTY
259 |
260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
268 | REPAIR OR CORRECTION.
269 |
270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
278 | POSSIBILITY OF SUCH DAMAGES.
279 |
280 | END OF TERMS AND CONDITIONS
281 |
282 | How to Apply These Terms to Your New Programs
283 |
284 | If you develop a new program, and you want it to be of the greatest
285 | possible use to the public, the best way to achieve this is to make it
286 | free software which everyone can redistribute and change under these terms.
287 |
288 | To do so, attach the following notices to the program. It is safest
289 | to attach them to the start of each source file to most effectively
290 | convey the exclusion of warranty; and each file should have at least
291 | the "copyright" line and a pointer to where the full notice is found.
292 |
293 |
294 | Copyright (C)
295 |
296 | This program is free software; you can redistribute it and/or modify
297 | it under the terms of the GNU General Public License as published by
298 | the Free Software Foundation; either version 2 of the License, or
299 | (at your option) any later version.
300 |
301 | This program is distributed in the hope that it will be useful,
302 | but WITHOUT ANY WARRANTY; without even the implied warranty of
303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
304 | GNU General Public License for more details.
305 |
306 | You should have received a copy of the GNU General Public License along
307 | with this program; if not, write to the Free Software Foundation, Inc.,
308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
309 |
310 | Also add information on how to contact you by electronic and paper mail.
311 |
312 | If the program is interactive, make it output a short notice like this
313 | when it starts in an interactive mode:
314 |
315 | Gnomovision version 69, Copyright (C) year name of author
316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
317 | This is free software, and you are welcome to redistribute it
318 | under certain conditions; type `show c' for details.
319 |
320 | The hypothetical commands `show w' and `show c' should show the appropriate
321 | parts of the General Public License. Of course, the commands you use may
322 | be called something other than `show w' and `show c'; they could even be
323 | mouse-clicks or menu items--whatever suits your program.
324 |
325 | You should also get your employer (if you work as a programmer) or your
326 | school, if any, to sign a "copyright disclaimer" for the program, if
327 | necessary. Here is a sample; alter the names:
328 |
329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program
330 | `Gnomovision' (which makes passes at compilers) written by James Hacker.
331 |
332 | , 1 April 1989
333 | Ty Coon, President of Vice
334 |
335 | This General Public License does not permit incorporating your program into
336 | proprietary programs. If your program is a subroutine library, you may
337 | consider it more useful to permit linking proprietary applications with the
338 | library. If this is what you want to do, use the GNU Lesser General
339 | Public License instead of this License.
--------------------------------------------------------------------------------
/src/Makefile.am:
--------------------------------------------------------------------------------
1 | SUBDIRS = images
2 |
3 | installdir = $(libdir)/enigma2/python/Plugins/SystemPlugins/ViX
4 | install_PYTHON = *.py
5 |
6 | install_DATA = *.png \
7 | *.xml \
8 | LICENSE \
9 | maintainer.info
10 |
--------------------------------------------------------------------------------
/src/MountManager.py:
--------------------------------------------------------------------------------
1 | import errno
2 | from os import mkdir, path, remove, rename, statvfs, system
3 | import re
4 | from time import sleep
5 |
6 | from boxbranding import getMachineBrand, getMachineName, getMachineBuild
7 | from enigma import eTimer, getDesktop
8 |
9 | from . import _
10 |
11 | from Components.ActionMap import ActionMap
12 | from Components.Label import Label
13 | from Components.ConfigList import ConfigListScreen
14 | from Components.config import config, getConfigListEntry, ConfigSelection, NoSave
15 | from Components.Console import Console
16 | from Components.Sources.List import List
17 | from Components.Sources.StaticText import StaticText
18 | from Components.SystemInfo import SystemInfo
19 | from Screens.MessageBox import MessageBox
20 | from Screens.Screen import Screen
21 | from Screens.Standby import QUIT_REBOOT, TryQuitMainloop
22 | from Tools.LoadPixmap import LoadPixmap
23 | from Tools.Directories import SCOPE_CURRENT_SKIN, resolveFilename
24 |
25 | blacklistedDisks = [
26 | 1, # RAM disk (/dev/ram0=0, /dev/initrd=250 [250=Initial RAM disk for old systems, new systems use 0])
27 | 7, # Loopback devices (/dev/loop0=0)
28 | 31, # ROM/flash memory card (/dev/rom0=0, /dev/rrom0=8, /dev/flash0=16, /dev/rflash0=24 [r=Read Only])
29 | 240, # ROM/flash memory card (/dev/rom0=0, /dev/rrom0=8, /dev/flash0=16, /dev/rflash0=24 [r=Read Only])
30 | 253, # LOCAL/EXPERIMENTAL USE
31 | 254, # LOCAL/EXPERIMENTAL USE
32 | 259 # MMC block devices (/dev/mmcblk0=0, /dev/mmcblk0p1=1, /dev/mmcblk1=8)
33 | ]
34 |
35 |
36 | def readFile(filename):
37 | try:
38 | with open(filename, "r") as fd:
39 | data = fd.read().strip()
40 | except (IOError, OSError) as err:
41 | if err.errno != errno.ENOENT: # No such file or directory.
42 | print("[MountManager] Error: Failed to read file! ", err)
43 | data = None
44 | return data
45 |
46 |
47 | def getProcPartitions(partitionList):
48 | partitions = []
49 | with open("/proc/partitions", "r") as fd:
50 | for line in fd.readlines():
51 | line = line.strip()
52 | if line == "": # Skip empty lines.
53 | continue
54 | (devmajor, devminor, blocks, device) = line.split()
55 | if devmajor == "major": # Skip label line.
56 | continue
57 | # print("[MountManager] device='%s', devmajor='%s', devminor='%s'." % (device, devmajor, devminor))
58 | devMajor = int(devmajor)
59 | if devMajor in blacklistedDisks: # Ignore all blacklisted devices.
60 | continue
61 | if devMajor == 179:
62 | if not SystemInfo["HasSDnomount"]: # Only interested in h9/i55/h9combo(+dups) mmc partitions. h9combo(+dups) uses mmcblk1p[0-3].
63 | continue
64 | if SystemInfo["HasH9SD"]:
65 | if not re.search("mmcblk0p1", device): # h9/i55 only mmcblk0p1 mmc partition
66 | continue
67 | if SystemInfo["HasMMC"]: # With h9/i55 reject mmcblk0p1 mmc partition if root device.
68 | continue
69 | if SystemInfo["HasSDnomount"][0] and not re.search("mmcblk1p[0-3]", device): # h9combo(+dups) uses mmcblk1p[0-3] include
70 | continue
71 | if devMajor == 8:
72 | if not re.search("sd[a-z][1-9]", device): # If storage use partitions only.
73 | continue
74 | if SystemInfo["HasHiSi"] and path.exists("/dev/sda4") and re.search("sd[a][1-4]", device): # Sf8008 using SDcard for slots ---> exclude
75 | continue
76 | if device in partitions: # If device is already in partition list ignore it.
77 | continue
78 | buildPartitionInfo(device, partitionList)
79 | partitions.append(device)
80 |
81 |
82 | def buildPartitionInfo(partition, partitionList):
83 | if re.search("mmcblk[0-1]p[0-3]", partition):
84 | device = re.sub("p[0-9]", "", partition)
85 | else:
86 | device = re.sub("[0-9]", "", partition)
87 | physicalDevice = path.realpath(path.join("/sys/block", device, "device"))
88 |
89 | # print("[MountManager] MachineBuild: %s" % getMachineBuild())
90 | # print("[MountManager] partition: %s" % partition)
91 | # print("[MountManager] device: %s" % device)
92 | # print("[MountManager] physicalDevice: %s" % physicalDevice)
93 | # print("[MountManager] Type: %s" % SystemInfo["MountManager"])
94 |
95 | description = readFile(path.join(physicalDevice, "model"))
96 | if description is None:
97 | description = readFile(path.join(physicalDevice, "name"))
98 | if description is None:
99 | description = _("Device %s") % partition
100 | description = str(description).replace("\n", "")
101 |
102 | hotplugBuses = ("usb", "mmc", "ata")
103 | busTranslate = ("usb", "sd", "hdd")
104 | count = -1
105 | for bus in hotplugBuses:
106 | count += 1
107 | if "/%s" % bus in physicalDevice:
108 | break
109 | # print("[MountManager1]bus: %s count : %s" % (bus, count))
110 | pngType = busTranslate[count]
111 | name = _("%s: " % pngType.upper())
112 | name += description
113 |
114 | if path.exists(resolveFilename(SCOPE_CURRENT_SKIN, "vixcore/dev_%s.png" % pngType)):
115 | mypixmap = resolveFilename(SCOPE_CURRENT_SKIN, "vixcore/dev_%s.png" % pngType)
116 | else:
117 | mypixmap = "/usr/lib/enigma2/python/Plugins/SystemPlugins/ViX/images/dev_%s.png" % pngType
118 |
119 | description = ""
120 | mediamount = _("None")
121 | _format = _("unavailable")
122 | rw = _("None")
123 |
124 | with open("/proc/mounts", "r") as f:
125 | for line in f.readlines():
126 | if line.find(partition) != -1:
127 | parts = line.strip().split()
128 | mediamount = parts[1] # media mount e.g. /media/xxxxx
129 | _format = parts[2] # _format e.g. ext4
130 | # Also, map any fuseblk fstype to the real file-system behind it...
131 | # Use blkid to get the info we need....
132 | #
133 | if _format == 'fuseblk':
134 | import subprocess
135 | res = subprocess.run(['blkid', '-sTYPE', '-ovalue', parts[0]], capture_output=True)
136 | if res.returncode == 0:
137 | _format = res.stdout.decode().strip()
138 | rw = parts[3] # read/write
139 | break
140 | print("[MountManager1][buildPartitionInfo] mediamount", mediamount)
141 | if mediamount == "/" and SystemInfo["HasKexecMultiboot"]:
142 | return
143 | if mediamount == _("None") or mediamount is None:
144 | description = _("Size: ") + _("unavailable")
145 | else:
146 | stat = statvfs(mediamount)
147 | # print("[MountManager1]mediamount: %s" % mediamount)
148 | size = (stat.f_blocks * stat.f_bsize) / (1000 * 1000) # get size in MB
149 | if size < 1: # is condition ever fulfilled?
150 | description = _("Size: unavailable")
151 | if size < 1000:
152 | description = _("Size: %sMB") % str(int(size))
153 | elif size < 1000 * 1000:
154 | description = _("Size: %sGB") % format(size / 1000, '.2f')
155 | else:
156 | description = _("Size: %sTB") % format(size / (1000 * 1000), '.2f')
157 |
158 | if SystemInfo["MountManager"]: # called by VIXDevicesPanel else DeviceMountSetup
159 | if rw.startswith("rw"):
160 | rw = " R/W"
161 | elif rw.startswith("ro"):
162 | rw = " R/O"
163 | else:
164 | rw = ""
165 | description += "\t" + _("Mount: ") + mediamount + "\n" + _("Device: ") + "/dev/" + partition + "\t" + _("Type: ") + _format + rw
166 | png = LoadPixmap(mypixmap)
167 | partitionInfo = (name, description, png)
168 | else:
169 | Gmedia = [
170 | ("/media/" + device, "/media/" + device),
171 | ("/media/hdd", "/media/hdd"),
172 | ("/media/hdd2", "/media/hdd2"),
173 | ("/media/hdd3", "/media/hdd3"),
174 | ("/media/usb", "/media/usb"),
175 | ("/media/usb2", "/media/usb2"),
176 | ("/media/usb3", "/media/usb3"),
177 | ("/media/sdcard", "/media/sdcard")
178 | ]
179 | item = NoSave(ConfigSelection(default="/media/%s" % partition, choices=Gmedia))
180 | if _format == "Linux":
181 | _format = "ext4"
182 | else:
183 | _format = "auto"
184 | item.value = mediamount.strip()
185 | text = name + " " + description + " /dev/" + partition
186 | partitionInfo = getConfigListEntry(text, item, partition, _format)
187 | partitionList.append(partitionInfo)
188 |
189 |
190 | class VIXDevicesPanel(Screen):
191 | skin = ["""
192 |
193 |
194 |
195 | {
196 | "template":
197 | [
198 | MultiContentEntryText(pos = (%d, %d), size = (%d, %d), font = 0, flags = RT_HALIGN_LEFT | RT_VALIGN_CENTER, text = 0),
199 | MultiContentEntryText(pos = (%d, %d), size = (%d, %d), font = 1, flags = RT_HALIGN_LEFT | RT_VALIGN_TOP, text = 1),
200 | MultiContentEntryPixmapAlphaBlend(pos = (%d, %d), size = (%d, %d), flags = BT_SCALE, png = 2),
201 | ],
202 | "fonts": [gFont("Regular",%d), gFont("Regular",%d)],
203 | "itemHeight": %d
204 | }
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 | """,
217 | 560, 495, # screen
218 | 10, 50, 540, 400, # Listbox
219 | 100, 0, 520, 30,
220 | 120, 30, 500, 50,
221 | 10, 0, 80, 80,
222 | 24, 20, # fonts
223 | 80,
224 | 10, 10, 540, 425, 25,
225 | 0, 0, 140, 40, #colors
226 | 140, 0, 140, 40,
227 | 280, 0, 140, 40,
228 | 420, 0, 140, 40,
229 | 0, 0, 140, 40, 20,
230 | 140, 0, 140, 40, 20,
231 | 280, 0, 140, 40, 20,
232 | 420, 0, 140, 40, 20,
233 | ]
234 |
235 | def __init__(self, session):
236 | Screen.__init__(self, session)
237 | self.setTitle(_("Mount manager"))
238 | self["key_red"] = Label("")
239 | self["key_green"] = Label(_("Setup mounts"))
240 | self["key_yellow"] = Label(_("Un-mount"))
241 | self["key_blue"] = Label(_("Mount"))
242 | self["lab1"] = Label(_("Please wait while scanning for devices..."))
243 | self.onChangedEntry = []
244 | self.partitionlist = []
245 | self["list"] = List(self.partitionlist)
246 | self["list"].onSelectionChanged.append(self.selectionChanged)
247 | self["actions"] = ActionMap(["WizardActions", "ColorActions", "MenuActions"], {
248 | "back": self.close,
249 | "green": self.setupMounts,
250 | "red": self.saveMounts,
251 | "yellow": self.unmount,
252 | "blue": self.mount,
253 | "menu": self.close
254 | })
255 | self.Console = Console()
256 | self.activityTimer = eTimer()
257 | self.activityTimer.timeout.get().append(self.findPartitions)
258 | self.setTimer()
259 |
260 | def selectionChanged(self):
261 | # print("[MountManager][selectionChanged] self.partitionList=%s" % self.partitionList)
262 | if len(self.partitionList) == 0:
263 | return
264 | sel = self["list"].getCurrent() # partitionInfo = (name, description, png)
265 | # print("[MountManager][selectionChanged] sel1=%s sel2=%s" % (sel[0], sel[1]))
266 | line = sel[1]
267 | # print("[MountManager1][selectionChanged] line=%s" % line)
268 | if line.find("Mount") >= 0:
269 | if line.find("/media/hdd") < 0:
270 | self["key_red"].setText(_("Use as HDD"))
271 | else:
272 | self["key_red"].setText("")
273 | name = description = ""
274 | if sel:
275 | try:
276 | name = str(sel[0])
277 | description = str(sel[1].replace("\t", " "))
278 | except Exception:
279 | pass
280 | for cb in self.onChangedEntry:
281 | cb(name, description)
282 |
283 | def setTimer(self, result=None, retval=None, extra_args=None):
284 | self["lab1"].show()
285 | self.activityTimer.start(10)
286 |
287 | def findPartitions(self):
288 | self.activityTimer.stop()
289 | self.partitionList = []
290 | SystemInfo["MountManager"] = True
291 | getProcPartitions(self.partitionList)
292 | self["list"].list = self.partitionList
293 | self["lab1"].hide()
294 |
295 | def setupMounts(self):
296 | self.session.openWithCallback(self.setTimer, DeviceMountSetup) # print("[MountManager][setupMounts")
297 |
298 | def unmount(self):
299 | sel = self["list"].getCurrent()
300 | # print("[MountManager][unmount] sel1=%s sel2=%s" % (sel[0], sel[1]))
301 | if sel:
302 | des = sel[1]
303 | des = des.replace("\n", "\t")
304 | parts = des.strip().split("\t")
305 | mountp = parts[1].replace(_("Mount: "), "")
306 | device = parts[2].replace(_("Device: "), "")
307 | # print("[MountManager][unmount] mountp=%s device=%s" % (mountp, device))
308 | exitStatus = system("umount %s" % mountp)
309 | if exitStatus == 0:
310 | self.session.open(MessageBox, _("Partition: %s Mount: %s unmounted successfully; if all partitions now unmounted you can remove device.") % (device, mountp), MessageBox.TYPE_INFO)
311 | self.setTimer()
312 | else:
313 | self.session.open(MessageBox, _("Cannot unmount partition '%s'. Make sure this partition is not in use. (SWAP, record/timeshift, etc.)") % mountp, MessageBox.TYPE_INFO)
314 | return -1
315 |
316 | def mount(self):
317 | sel = self["list"].getCurrent()
318 | # print("[MountManager][mount] sel1=%s sel2=%s" % (sel[0], sel[1]))
319 | if sel:
320 | des = sel[1]
321 | des = des.replace("\n", "\t")
322 | parts = des.strip().split("\t")
323 | mountp = parts[1].replace(_("Mount: "), "")
324 | device = parts[2].replace(_("Device: "), "")
325 | # print("[MountManager][mount] mountp=%s device=%s" % (mountp, device))
326 | exitStatus = system("mount %s" % device)
327 | if exitStatus != 0:
328 | self.session.open(MessageBox, _("Mount failed for '%s', error code = '%s'.") % (sel, exitStatus), MessageBox.TYPE_INFO, timeout=10)
329 | self.setTimer()
330 |
331 | def saveMounts(self):
332 | sel = self["list"].getCurrent()
333 | # print("[MountManager][saveMounts] selection=%s" % sel)
334 | if sel:
335 | parts = sel[1].split()
336 | self.device = parts[5]
337 | self.mountp = parts[3]
338 | # print("[MountManager1]saveMounts: device = %s, mountp = %s" %(self.device, self.mountp))
339 | self.Console.ePopen("umount " + self.device)
340 | if self.mountp.find("/media/hdd") < 0:
341 | self.Console.ePopen("umount /media/hdd")
342 | self.Console.ePopen("/sbin/blkid | grep " + self.device, self.addFstab, [self.device, self.mountp])
343 | else:
344 | self.session.open(MessageBox, _("This device is already mounted as HDD."), MessageBox.TYPE_INFO, timeout=10, close_on_any_key=True)
345 |
346 | def addFstab(self, result=None, retval=None, extra_args=None):
347 | # print("[MountManager] RESULT:", result)
348 | if result:
349 | self.device = extra_args[0]
350 | self.mountp = extra_args[1]
351 | self.device_uuid = "UUID=" + result.split("UUID=")[1].split(" ")[0].replace('"', '')
352 | # print("[MountManager1][addFstab1]: device = %s, mountp=%s, UUID=%s" %(self.device, self.mountp, self.device_uuid))
353 | if not path.exists(self.mountp):
354 | mkdir(self.mountp, 0o755)
355 | open("/etc/fstab.tmp", "w").writelines([l for l in open("/etc/fstab").readlines() if "/media/hdd" not in l])
356 | rename("/etc/fstab.tmp", "/etc/fstab")
357 | open("/etc/fstab.tmp", "w").writelines([l for l in open("/etc/fstab").readlines() if self.device not in l])
358 | rename("/etc/fstab.tmp", "/etc/fstab")
359 | open("/etc/fstab.tmp", "w").writelines([l for l in open("/etc/fstab").readlines() if self.device_uuid not in l])
360 | rename("/etc/fstab.tmp", "/etc/fstab")
361 | with open("/etc/fstab", "a") as fd:
362 | line = self.device_uuid + "\t/media/hdd\tauto\tdefaults\t0 0\n"
363 | fd.write(line)
364 | self.Console.ePopen("mount -a", self.setTimer)
365 |
366 |
367 | class DeviceMountSetup(Screen, ConfigListScreen):
368 | skin = ["""
369 |
370 |
371 |
372 |
373 |
374 |
375 |
376 | """,
377 | 560, 450, # screen
378 | 0, 0, 140, 40, #colors
379 | 140, 0, 140, 40,
380 | 0, 0, 140, 40, 20,
381 | 140, 0, 140, 40, 20,
382 | 0, 50, 560, 275, 26, 20, # config
383 | 0, 365, 560, 20, 18,
384 | ]
385 |
386 | def __init__(self, session):
387 | Screen.__init__(self, session)
388 | self.partitionList = []
389 | ConfigListScreen.__init__(self, self.partitionList)
390 | self.setTitle(_("Choose where to mount your devices to:"))
391 | self["key_green"] = Label(_("Save"))
392 | self["key_red"] = Label(_("Cancel"))
393 | self["lab1"] = Label()
394 | self["actions"] = ActionMap(["WizardActions", "ColorActions"], {
395 | "red": self.close,
396 | "green": self.saveconfMounts,
397 | "back": self.close
398 | })
399 | self.Console = Console()
400 | self.activityTimer = eTimer()
401 | self.activityTimer.timeout.get().append(self.findconfPartitions)
402 | self.setconfTimer()
403 |
404 | def setconfTimer(self, result=None, retval=None, extra_args=None):
405 | scanning = _("Please wait while scanning your %s %s devices...") % (getMachineBrand(), getMachineName())
406 | self["lab1"].setText(scanning)
407 | self.activityTimer.start(10)
408 |
409 | def findconfPartitions(self):
410 | self.activityTimer.stop()
411 | self.partitionList = []
412 | SystemInfo["MountManager"] = False
413 | getProcPartitions(self.partitionList)
414 | self["config"].list = self.partitionList
415 | self["config"].l.setList(self.partitionList)
416 | self["lab1"].hide()
417 |
418 | def saveconfMounts(self):
419 | for x in self["config"].list: # partitionInfo = getConfigListEntry(text, item, partition, _format)
420 | self.device = x[2]
421 | self.mountp = x[1].value
422 | self.type = x[3]
423 | # print("[MountManager][saveconfMount] mountp=%s device=%s type=%s" % (self.mountp, self.device, self.type))
424 | self.Console.ePopen("umount %s" % self.device)
425 | self.Console.ePopen("/sbin/blkid | grep " + self.device + " && opkg list-installed ntfs-3g", self.addconfFstab, [self.device, self.mountp])
426 | message = _("Updating mount locations...")
427 | ybox = self.session.openWithCallback(self.delay, MessageBox, message, type=MessageBox.TYPE_INFO, timeout=5, enable_input=False)
428 | ybox.setTitle(_("Please wait."))
429 |
430 | def delay(self, val):
431 | message = _("The changes need a system restart to take effect.\nRestart your %s %s now?") % (getMachineBrand(), getMachineName())
432 | ybox = self.session.openWithCallback(self.restartBox, MessageBox, message, MessageBox.TYPE_YESNO)
433 | ybox.setTitle(_("Restart %s %s.") % (getMachineBrand(), getMachineName()))
434 |
435 | def addconfFstab(self, result=None, retval=None, extra_args=None):
436 | # print("[MountManager] RESULT:", result)
437 | if result:
438 | self.device = extra_args[0]
439 | self.mountp = extra_args[1]
440 | uuid = re.search('UUID=\"([^\"]+)\"', result)
441 | type = re.search('TYPE=\"([^\"]+)\"', result)
442 | if uuid and type:
443 | self.device_uuid = "UUID=" + uuid.group(1)
444 | self.device_type = type.group(1)
445 | # print("[MountManager][addFstab2] device_uuid:%s device_type:%s" % (self.device_uuid, self.device_type))
446 | if self.device_type.startswith("ext"):
447 | self.device_type = "auto"
448 | elif self.device_type.startswith("ntfs") and result.find("ntfs-3g") != -1:
449 | self.device_type = "ntfs-3g"
450 | elif self.device_type.startswith("ntfs") and result.find("ntfs-3g") == -1:
451 | self.device_type = "ntfs"
452 | if not path.exists(self.mountp):
453 | mkdir(self.mountp, 0o755)
454 | open("/etc/fstab.tmp", "w").writelines([l for l in open("/etc/fstab").readlines() if self.device not in l])
455 | rename("/etc/fstab.tmp", "/etc/fstab")
456 | open("/etc/fstab.tmp", "w").writelines([l for l in open("/etc/fstab").readlines() if self.device_uuid not in l])
457 | rename("/etc/fstab.tmp", "/etc/fstab")
458 | with open("/etc/fstab", "a") as fd:
459 | line = self.device_uuid + "\t" + self.mountp + "\t" + self.device_type + "\tdefaults\t0 0\n"
460 | fd.write(line)
461 |
462 | def restartBox(self, answer):
463 | if answer is True:
464 | self.session.open(TryQuitMainloop, QUIT_REBOOT)
465 | else:
466 | self.close()
467 |
--------------------------------------------------------------------------------
/src/Multibootmgr.py:
--------------------------------------------------------------------------------
1 | from os import statvfs
2 | from boxbranding import getMachineBuild
3 | from Components.ActionMap import ActionMap
4 | from Components.ChoiceList import ChoiceList, ChoiceEntryComponent
5 | from Components.config import config
6 | from Components.Label import Label
7 | from Components.Sources.StaticText import StaticText
8 | from Components.SystemInfo import SystemInfo
9 | from Screens.Console import Console
10 | from Screens.MessageBox import MessageBox
11 | from Screens.Screen import Screen
12 | from Screens.Standby import TryQuitMainloop
13 | from Tools.BoundFunction import boundFunction
14 | from Tools.Directories import pathExists
15 | from Tools.Multiboot import GetImagelist, GetCurrentImage, GetCurrentImageMode, EmptySlot
16 |
17 |
18 | class MultiBoot(Screen):
19 |
20 | skin = """
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 | """
36 |
37 | def __init__(self, session):
38 | Screen.__init__(self, session)
39 | self.skinName = "MultiBoot"
40 | self.setTitle(_("Multiboot image manager"))
41 | self.title = screentitle
42 | self["key_red"] = StaticText(_("Cancel"))
43 | self["labe14"] = StaticText(_("Use the cursor keys to select an installed image and then Erase button."))
44 | self["labe15"] = StaticText(_("Note: slot list does not show current image or empty slots."))
45 | self["key_green"] = StaticText(_("Erase"))
46 | self["key_yellow"] = StaticText("")
47 | self["config"] = ChoiceList(list=[ChoiceEntryComponent('', ((_("Retrieving image slots - Please wait...")), "Queued"))])
48 | imagedict = []
49 | self.getImageList = None
50 | self.startit()
51 |
52 | self["actions"] = ActionMap(["OkCancelActions", "ColorActions", "DirectionActions", "KeyboardInputActions", "MenuActions"],
53 | {
54 | "red": boundFunction(self.close, None),
55 | "green": self.erase,
56 | "yellow": boundFunction(self.close, None),
57 | "ok": self.erase,
58 | "cancel": boundFunction(self.close, None),
59 | "up": self.keyUp,
60 | "down": self.keyDown,
61 | "left": self.keyLeft,
62 | "right": self.keyRight,
63 | "upRepeated": self.keyUp,
64 | "downRepeated": self.keyDown,
65 | "leftRepeated": self.keyLeft,
66 | "rightRepeated": self.keyRight,
67 | "menu": boundFunction(self.close, True),
68 | }, -1)
69 | self.onLayoutFinish.append(self.layoutFinished)
70 |
71 | def layoutFinished(self):
72 | self.setTitle(self.title)
73 |
74 | def startit(self):
75 | self.getImageList = GetImagelist(self.ImageList)
76 |
77 | def ImageList(self, imagedict):
78 | list = []
79 | mode = GetCurrentImageMode() or 0
80 | currentimageslot = GetCurrentImage()
81 | for x in sorted(imagedict.keys()):
82 | if imagedict[x]["imagename"] != _("Empty slot") and x != currentimageslot:
83 | list.append(ChoiceEntryComponent('', ((_("slot%s - %s ")) % (x, imagedict[x]['imagename']), x)))
84 | self["config"].setList(list)
85 |
86 | def erase(self):
87 | self.currentSelected = self["config"].l.getCurrentSelection()
88 | if self.currentSelected != None:
89 | if self.currentSelected[0][1] != "Queued":
90 | if SystemInfo["HasRootSubdir"]:
91 | message = _("Removal of this slot will not show in %s Gui. Are you sure you want to delete image slot %s ?" % (getMachineBuild(), self.currentSelected[0][1]))
92 | ybox = self.session.openWithCallback(self.doErase, MessageBox, message, MessageBox.TYPE_YESNO, default=True)
93 | ybox.setTitle(_("Remove confirmation"))
94 | else:
95 | message = _("Are you sure you want to delete image slot %s ?" % self.currentSelected[0][1])
96 | ybox = self.session.openWithCallback(self.doErase, MessageBox, message, MessageBox.TYPE_YESNO, default=True)
97 | ybox.setTitle(_("Remove confirmation"))
98 |
99 | def doErase(self, answer):
100 | if answer is True:
101 | sloterase = EmptySlot(self.currentSelected[0][1], self.startit)
102 |
103 | def selectionChanged(self):
104 | pass
105 |
106 | def keyLeft(self):
107 | self["config"].instance.moveSelection(self["config"].instance.moveUp)
108 | self.selectionChanged()
109 |
110 | def keyRight(self):
111 | self["config"].instance.moveSelection(self["config"].instance.moveDown)
112 | self.selectionChanged()
113 |
114 | def keyUp(self):
115 | self["config"].instance.moveSelection(self["config"].instance.moveUp)
116 | self.selectionChanged()
117 |
118 | def keyDown(self):
119 | self["config"].instance.moveSelection(self["config"].instance.moveDown)
120 | self.selectionChanged()
121 |
--------------------------------------------------------------------------------
/src/RestoreWizard.py:
--------------------------------------------------------------------------------
1 | from os import listdir, path, stat
2 | from boxbranding import getMachineBrand, getMachineName, getImageDistro
3 | from . import _
4 | from .BackupManager import isRestorableSettings, isRestorablePlugins, isRestorableKernel
5 |
6 | from Components.About import about
7 | from Components.config import config, configfile
8 | from Components.Console import Console
9 | from Components.Pixmap import Pixmap
10 | from Components.SystemInfo import SystemInfo
11 | from Screens.MessageBox import MessageBox
12 | from Screens.Rc import Rc
13 | from Screens.WizardLanguage import WizardLanguage
14 | from Tools.Directories import fileExists, fileHas, resolveFilename, SCOPE_PLUGINS
15 | from Tools.Multiboot import bootmviSlot, createInfo
16 |
17 |
18 | class RestoreWizard(WizardLanguage, Rc):
19 | def __init__(self, session):
20 | self.xmlfile = resolveFilename(SCOPE_PLUGINS, "SystemPlugins/ViX/restorewizard.xml")
21 | WizardLanguage.__init__(self, session, showSteps=False, showStepSlider=False)
22 | Rc.__init__(self)
23 | self.session = session
24 | self.skinName = "StartWizard"
25 | self.skin = "StartWizard.skin"
26 | self["wizard"] = Pixmap()
27 | self.selectedAction = None
28 | self.NextStep = None
29 | self.Text = None
30 | self.buildListRef = None
31 | self.didSettingsRestore = False
32 | self.didPluginRestore = False
33 | self.PluginsRestore = False
34 | self.fullbackupfilename = None
35 | self.delaymess = None
36 | self.selectedDevice = None
37 | self.Console = Console()
38 |
39 | def getTranslation(self, text):
40 | return _(text).replace("%s %s", "%s %s" % (getMachineBrand(), getMachineName()))
41 |
42 | def listDevices(self):
43 | devmounts = []
44 | list = []
45 | files = []
46 | mtimes = []
47 | defaultprefix = getImageDistro()[4:]
48 |
49 | for dir in ["/media/%s/backup" % media for media in listdir("/media/") if path.isdir(path.join("/media/", media))]:
50 | devmounts.append(dir)
51 | if len(devmounts):
52 | for devpath in devmounts:
53 | if path.exists(devpath):
54 | try:
55 | files = listdir(devpath)
56 | except:
57 | files = []
58 | else:
59 | files = []
60 | if len(files):
61 | for file in files:
62 | if file.endswith(".tar.gz") and "vix" in file.lower() or file.startswith("%s" % defaultprefix):
63 | mtimes.append((path.join(devpath, file), stat(path.join(devpath, file)).st_mtime)) # (filname, mtime)
64 | for file in [x[0] for x in sorted(mtimes, key=lambda x: x[1], reverse=True)]: # sort by mtime
65 | list.append((file, file))
66 | return list
67 |
68 | def settingsdeviceSelectionMade(self, index):
69 | self.selectedAction = index
70 | self.settingsdeviceSelect(index)
71 |
72 | def settingsdeviceSelect(self, index):
73 | self.selectedDevice = index
74 | self.fullbackupfilename = index
75 | self.NextStep = "settingrestorestarted"
76 |
77 | def settingsdeviceSelectionMoved(self):
78 | self.settingsdeviceSelect(self.selection)
79 |
80 | def pluginsdeviceSelectionMade(self, index):
81 | self.selectedAction = index
82 | self.pluginsdeviceSelect(index)
83 |
84 | def pluginsdeviceSelect(self, index):
85 | self.selectedDevice = index
86 | self.fullbackupfilename = index
87 | self.NextStep = "plugindetection"
88 |
89 | def pluginsdeviceSelectionMoved(self):
90 | self.pluginsdeviceSelect(self.selection)
91 |
92 | def markDone(self):
93 | pass
94 |
95 | def listAction(self):
96 | list = [(_("OK, to perform a restore"), "settingsquestion"), (_("Exit the restore wizard"), "end")]
97 | return list
98 |
99 | def listAction2(self):
100 | list = [(_("YES, to restore settings"), "settingsrestore"), (_("NO, do not restore settings"), "pluginsquestion")]
101 | return list
102 |
103 | def listAction3(self):
104 | list = []
105 | if self.didSettingsRestore:
106 | list.append((_("YES, to restore plugins"), "pluginrestore"))
107 | list.append((_("NO, do not restore plugins"), "reboot"))
108 | else:
109 | list.append((_("YES, to restore plugins"), "pluginsrestoredevice"))
110 | list.append((_("NO, do not restore plugins"), "end"))
111 | return list
112 |
113 | def rebootAction(self):
114 | list = [(_("OK"), "reboot")]
115 | return list
116 |
117 | def ActionSelectionMade(self, index):
118 | self.selectedAction = index
119 | self.ActionSelect(index)
120 |
121 | def ActionSelect(self, index):
122 | self.NextStep = index
123 |
124 | def ActionSelectionMoved(self):
125 | self.ActionSelect(self.selection)
126 |
127 | def buildList(self, action):
128 | if self.NextStep == "reboot":
129 | if fileHas("/proc/cmdline", "kexec=1") and config.usage.bootlogo_identify.value:
130 | slot = SystemInfo["MultiBootSlot"]
131 | text = createInfo(slot)
132 | bootmviSlot(text=text, slot=slot)
133 | if self.didSettingsRestore:
134 | self.Console.ePopen("tar -xzvf " + self.fullbackupfilename + " -C /" + " etc/enigma2/settings")
135 | self.Console.ePopen("killall -9 enigma2 && init 6")
136 | elif self.NextStep == "settingsquestion" or self.NextStep == "settingsrestore" or self.NextStep == "pluginsquestion" or self.NextStep == "pluginsrestoredevice" or self.NextStep == "end" or self.NextStep == "noplugins":
137 | self.buildListfinishedCB(False)
138 | elif self.NextStep == "settingrestorestarted":
139 | self.Console.ePopen("tar -xzvf " + self.fullbackupfilename + " -C / tmp/ExtraInstalledPlugins tmp/backupkernelversion tmp/backupimageversion", self.settingsRestore_Started)
140 | self.buildListRef = self.session.openWithCallback(self.buildListfinishedCB, MessageBox, _("Please wait while the system gathers information..."), type=MessageBox.TYPE_INFO, enable_input=False, wizard=True)
141 | self.buildListRef.setTitle(_("Restore wizard"))
142 | elif self.NextStep == "plugindetection":
143 | print("[RestoreWizard] Stage 2: Restoring plugins")
144 | self.Console.ePopen("tar -xzvf " + self.fullbackupfilename + " -C / tmp/ExtraInstalledPlugins tmp/backupkernelversion tmp/backupimageversion", self.pluginsRestore_Started)
145 | self.buildListRef = self.session.openWithCallback(self.buildListfinishedCB, MessageBox, _("Please wait while the system gathers information..."), type=MessageBox.TYPE_INFO, enable_input=False, wizard=True)
146 | self.buildListRef.setTitle(_("Restore wizard"))
147 | elif self.NextStep == "pluginrestore":
148 | if self.feeds == "OK":
149 | print("[RestoreWizard] Stage 6: Feeds OK, Restoring Plugins")
150 | print("[RestoreWizard] Console command: ", "opkg install " + self.pluginslist + " " + self.pluginslist2)
151 | self.Console.ePopen("opkg install " + self.pluginslist + " " + self.pluginslist2, self.pluginsRestore_Finished)
152 | self.buildListRef = self.session.openWithCallback(self.buildListfinishedCB, MessageBox, _("Please wait while plugins restore completes..."), type=MessageBox.TYPE_INFO, enable_input=False, wizard=True)
153 | self.buildListRef.setTitle(_("Restore wizard"))
154 | elif self.feeds == "DOWN":
155 | print("[RestoreWizard] Stage 6: Feeds Down")
156 | self.didPluginRestore = True
157 | self.NextStep = "reboot"
158 | self.buildListRef = self.session.openWithCallback(self.buildListfinishedCB, MessageBox, _("Sorry the feeds are down for maintenance. Please try using Backup manager to restore plugins later."), type=MessageBox.TYPE_INFO, timeout=30, wizard=True)
159 | self.buildListRef.setTitle(_("Restore wizard"))
160 | elif self.feeds == "BAD":
161 | print("[RestoreWizard] Stage 6: No Network")
162 | self.didPluginRestore = True
163 | self.NextStep = "reboot"
164 | self.buildListRef = self.session.openWithCallback(self.buildListfinishedCB, MessageBox, _("Your %s %s is not connected to the Internet. Please try using Backup manager to restore plugins later.") % (getMachineBrand(), getMachineName()), type=MessageBox.TYPE_INFO, timeout=30, wizard=True)
165 | self.buildListRef.setTitle(_("Restore wizard"))
166 | elif self.feeds == "ERROR":
167 | self.NextStep = "pluginrestore"
168 | self.buildListRef = self.session.openWithCallback(self.buildListfinishedCB, MessageBox, _("A background update check is in progress, please try again."), type=MessageBox.TYPE_INFO, timeout=10, wizard=True)
169 | self.buildListRef.setTitle(_("Restore wizard"))
170 |
171 | def buildListfinishedCB(self, data):
172 | # self.buildListRef = None
173 | if data is True:
174 | self.currStep = self.getStepWithID(self.NextStep)
175 | self.afterAsyncCode()
176 | else:
177 | self.currStep = self.getStepWithID(self.NextStep)
178 | self.afterAsyncCode()
179 |
180 | def settingsRestore_Started(self, result, retval, extra_args=None):
181 | self.doRestoreSettings1()
182 |
183 | def doRestoreSettings1(self):
184 | print("[RestoreWizard] Stage 1: Check Version")
185 | if fileExists("/tmp/backupimageversion"):
186 | imageversion = open("/tmp/backupimageversion").read()
187 | print("[RestoreWizard] Backup Image:", imageversion)
188 | print("[RestoreWizard] Current Image:", about.getVersionString())
189 | if imageversion == about.getVersionString() or isRestorableSettings(imageversion):
190 | print("[RestoreWizard] Stage 1: Image ver OK")
191 | self.doRestoreSettings2()
192 | else:
193 | print("[RestoreWizard] Stage 1: Image ver different")
194 | self.noVersion = self.session.openWithCallback(self.doNoVersion, MessageBox, _("Sorry, but the file is not compatible with this image version."), type=MessageBox.TYPE_INFO, timeout=30, wizard=True)
195 | self.noVersion.setTitle(_("Restore wizard"))
196 | else:
197 | print("[RestoreWizard] Stage 1: No Image ver to check")
198 | self.noVersion = self.session.openWithCallback(self.doNoVersion, MessageBox, _("Sorry, but the file is not compatible with this image version."), type=MessageBox.TYPE_INFO, timeout=30, wizard=True)
199 | self.noVersion.setTitle(_("Restore wizard"))
200 |
201 | def doNoVersion(self, result=None, retval=None, extra_args=None):
202 | self.buildListRef.close(True)
203 |
204 | def doRestoreSettings2(self):
205 | print("[RestoreWizard] Stage 2: Restoring settings")
206 | self.Console.ePopen("tar -xzvf " + self.fullbackupfilename + " -C /", self.settingRestore_Finished)
207 | self.pleaseWait = self.session.open(MessageBox, _("Please wait while settings restore completes..."), type=MessageBox.TYPE_INFO, enable_input=False, wizard=True)
208 | self.pleaseWait.setTitle(_("Restore wizard"))
209 |
210 | def settingRestore_Finished(self, result, retval, extra_args=None):
211 | self.didSettingsRestore = True
212 | network = [x.split(" ")[3] for x in open("/etc/network/interfaces").read().splitlines() if x.startswith("iface eth0")]
213 | self.pleaseWait.close()
214 | self.doRestorePlugins1()
215 |
216 | def pluginsRestore_Started(self, result, retval, extra_args=None):
217 | self.doRestorePlugins1()
218 |
219 | def pluginsRestore_Finished(self, result, retval, extra_args=None):
220 | if result:
221 | print("[RestoreWizard] opkg install result:\n", result)
222 | self.didPluginRestore = True
223 | self.NextStep = "reboot"
224 | self.buildListRef.close(True)
225 |
226 | def doRestorePlugins1(self):
227 | print("[RestoreWizard] Stage 3: Check Kernel")
228 | if fileExists("/tmp/backupkernelversion") and fileExists("/tmp/backupimageversion"):
229 | imageversion = open("/tmp/backupimageversion").read()
230 | kernelversion = open("/tmp/backupkernelversion").read()
231 | print("[RestoreWizard] Backup Image:", imageversion)
232 | print("[RestoreWizard] Current Image:", about.getVersionString())
233 | print("[RestoreWizard] Backup Kernel:", kernelversion)
234 | print("[RestoreWizard] Current Kernel:", about.getKernelVersionString())
235 | if isRestorableKernel(kernelversion) and (imageversion == about.getVersionString() or isRestorablePlugins(imageversion)):
236 | print("[RestoreWizard] Stage 3: Kernel and image ver OK")
237 | self.doRestorePluginsTest()
238 | else:
239 | print("[RestoreWizard] Stage 3: Kernel or image ver Different")
240 | if self.didSettingsRestore:
241 | self.NextStep = "reboot"
242 | else:
243 | self.NextStep = "noplugins"
244 | self.buildListRef.close(True)
245 | else:
246 | print("[RestoreWizard] Stage 3: No Kernel to check")
247 | if self.didSettingsRestore:
248 | self.NextStep = "reboot"
249 | else:
250 | self.NextStep = "noplugins"
251 | self.buildListRef.close(True)
252 |
253 | def doRestorePluginsTest(self, result=None, retval=None, extra_args=None):
254 | if self.delaymess:
255 | self.delaymess.close()
256 | print("[RestoreWizard] Stage 4: Feeds Test")
257 | self.Console.ePopen("opkg update", self.doRestorePluginsTestComplete)
258 |
259 | def doRestorePluginsTestComplete(self, result='', retval=None, extra_args=None):
260 | print("[RestoreWizard] Stage 4: Feeds Test Result", result)
261 | if result.find("wget returned 4") != -1:
262 | self.NextStep = "reboot"
263 | self.buildListRef = self.session.openWithCallback(self.buildListfinishedCB, MessageBox, _("Your %s %s is not connected to a network. Please try using the Backup manager to restore plugins later when a network connection is available.") % (getMachineBrand(), getMachineName()), type=MessageBox.TYPE_INFO, timeout=30, wizard=True)
264 | self.buildListRef.setTitle(_("Restore wizard"))
265 | elif result.find("wget returned 8") != -1:
266 | self.NextStep = "reboot"
267 | self.buildListRef = self.session.openWithCallback(self.buildListfinishedCB, MessageBox, _("Your %s %s could not connect to the plugin feeds at this time. Please try using the Backup manager to restore plugins later.") % (getMachineBrand(), getMachineName()), type=MessageBox.TYPE_INFO, timeout=30, wizard=True)
268 | self.buildListRef.setTitle(_("Restore wizard"))
269 | elif result.find("bad address") != -1:
270 | self.NextStep = "reboot"
271 | self.buildListRef = self.session.openWithCallback(self.buildListfinishedCB, MessageBox, _("Your %s %s is not connected to the Internet. Please try using the Backup manager to restore plugins later.") % (getMachineBrand(), getMachineName()), type=MessageBox.TYPE_INFO, timeout=30, wizard=True)
272 | self.buildListRef.setTitle(_("Restore wizard"))
273 | elif result.find("wget returned 1") != -1 or result.find("wget returned 255") != -1 or result.find("404 Not Found") != -1:
274 | self.NextStep = "reboot"
275 | self.buildListRef = self.session.openWithCallback(self.buildListfinishedCB, MessageBox, _("Sorry the feeds are down for maintenance. Please try using the Backup manager to restore plugins later."), type=MessageBox.TYPE_INFO, timeout=30, wizard=True)
276 | self.buildListRef.setTitle(_("Restore wizard"))
277 | elif result.find("Collected errors") != -1:
278 | print("[RestoreWizard] Stage 4: Update is in progress, delaying")
279 | self.delaymess = self.session.openWithCallback(self.doRestorePluginsTest, MessageBox, _("A background update check is in progress, please try again."), type=MessageBox.TYPE_INFO, timeout=10, wizard=True)
280 | self.delaymess.setTitle(_("Restore wizard"))
281 | else:
282 | print("[RestoreWizard] Stage 4: Feeds OK")
283 | self.feeds = "OK"
284 | self.doListPlugins()
285 |
286 | def doListPlugins(self):
287 | print("[RestoreWizard] Stage 4: Feeds Test")
288 | self.Console.ePopen("opkg list-installed", self.doRestorePlugins2)
289 |
290 | def doRestorePlugins2(self, result, retval, extra_args):
291 | print("[RestoreWizard] Stage 5: Build list of plugins to restore")
292 | self.pluginslist = ""
293 | self.pluginslist2 = ""
294 | plugins = []
295 | if path.exists("/tmp/ExtraInstalledPlugins"):
296 | self.pluginslist = []
297 | for line in result.split("\n"):
298 | if line:
299 | parts = line.strip().split()
300 | plugins.append(parts[0])
301 | tmppluginslist = open("/tmp/ExtraInstalledPlugins", "r").readlines()
302 | for line in tmppluginslist:
303 | if line:
304 | parts = line.strip().split()
305 | if len(parts) > 0 and parts[0] not in plugins:
306 | self.pluginslist.append(parts[0])
307 |
308 | if path.exists("/tmp/3rdPartyPlugins"):
309 | self.pluginslist2 = []
310 | if path.exists("/tmp/3rdPartyPluginsLocation"):
311 | self.thirdpartyPluginsLocation = open("/tmp/3rdPartyPluginsLocation", "r").readlines()
312 | self.thirdpartyPluginsLocation = "".join(self.thirdpartyPluginsLocation)
313 | self.thirdpartyPluginsLocation = self.thirdpartyPluginsLocation.replace("\n", "")
314 | self.thirdpartyPluginsLocation = self.thirdpartyPluginsLocation.replace(" ", "%20")
315 | self.plugfiles = self.thirdpartyPluginsLocation.split("/", 3)
316 | else:
317 | self.thirdpartyPluginsLocation = " "
318 |
319 | tmppluginslist2 = open("/tmp/3rdPartyPlugins", "r").readlines()
320 | available = None
321 | for line in tmppluginslist2:
322 | if line:
323 | parts = line.strip().split("_")
324 | if parts[0] not in plugins:
325 | ipk = parts[0]
326 | if path.exists(self.thirdpartyPluginsLocation):
327 | available = listdir(self.thirdpartyPluginsLocation)
328 | else:
329 | devmounts = []
330 | files = []
331 | self.plugfile = self.plugfiles[3]
332 | for dir in ["/media/%s/%s" % (media, self.plugfile) for media in listdir("/media/") if path.isdir(path.join("/media/", media)) and path.exists("/media/%s/%s" % (media, self.plugfile))]:
333 | if media not in ("autofs", "net"):
334 | devmounts.append(dir)
335 | if len(devmounts):
336 | for x in devmounts:
337 | print("[BackupManager] search dir = %s" % devmounts)
338 | if path.exists(x):
339 | self.thirdpartyPluginsLocation = x
340 | try:
341 | available = listdir(self.thirdpartyPluginsLocation)
342 | break
343 | except:
344 | continue
345 | if available:
346 | for file in available:
347 | if file:
348 | fileparts = file.strip().split("_")
349 | if fileparts[0] == ipk:
350 | self.thirdpartyPluginsLocation = self.thirdpartyPluginsLocation.replace(" ", "%20")
351 | ipk = path.join(self.thirdpartyPluginsLocation, file)
352 | if path.exists(ipk):
353 | self.pluginslist2.append(ipk)
354 |
355 | if len(self.pluginslist) or len(self.pluginslist2):
356 | self.doRestorePluginsQuestion()
357 | else:
358 | if self.didSettingsRestore:
359 | self.NextStep = "reboot"
360 | else:
361 | self.NextStep = "noplugins"
362 | self.buildListRef.close(True)
363 |
364 | def doRestorePluginsQuestion(self):
365 | if len(self.pluginslist) or len(self.pluginslist2):
366 | if len(self.pluginslist):
367 | self.pluginslist = " ".join(self.pluginslist)
368 | else:
369 | self.pluginslist = ""
370 | if len(self.pluginslist2):
371 | self.pluginslist2 = " ".join(self.pluginslist2)
372 | else:
373 | self.pluginslist2 = ""
374 | print("[RestoreWizard] Stage 6: Plugins to restore in feeds", self.pluginslist)
375 | print("[RestoreWizard] Stage 6: Plugins to restore in extra location", self.pluginslist2)
376 | if self.didSettingsRestore:
377 | print("[RestoreWizard] Stage 6: proceed to question")
378 | self.NextStep = "pluginsquestion"
379 | self.buildListRef.close(True)
380 | else:
381 | print("[RestoreWizard] Stage 6: proceed to restore")
382 | self.NextStep = "pluginrestore"
383 | self.buildListRef.close(True)
384 | else:
385 | print("[RestoreWizard] Stage 6: NO Plugins to restore")
386 | if self.didSettingsRestore:
387 | self.NextStep = "reboot"
388 | else:
389 | self.NextStep = "noplugins"
390 | self.buildListRef.close(True)
391 |
--------------------------------------------------------------------------------
/src/ScriptRunner.py:
--------------------------------------------------------------------------------
1 | from os import path, mkdir, listdir, rename
2 |
3 | from . import _, PluginLanguageDomain
4 | from Components.ActionMap import ActionMap
5 | from Components.config import config, ConfigSubsection, ConfigYesNo
6 | from Components.PluginComponent import plugins
7 | from Components.Sources.StaticText import StaticText
8 | from .IPKInstaller import IpkgInstaller
9 | from Screens.Console import Console
10 | from Screens.Screen import Screen
11 | from Screens.Setup import Setup
12 | from Tools.Directories import resolveFilename, SCOPE_PLUGINS
13 |
14 | config.scriptrunner = ConfigSubsection()
15 | config.scriptrunner.close = ConfigYesNo(default=False)
16 | config.scriptrunner.showinextensions = ConfigYesNo(default=False)
17 |
18 |
19 | def updateExtensions(configElement):
20 | plugins.clearPluginList()
21 | plugins.readPluginList(resolveFilename(SCOPE_PLUGINS))
22 |
23 |
24 | config.scriptrunner.showinextensions.addNotifier(updateExtensions, initial_call=False)
25 |
26 |
27 | def ScriptRunnerAutostart(reason, session=None, **kwargs):
28 | pass
29 |
30 |
31 | class VIXScriptRunner(IpkgInstaller):
32 | def __init__(self, session, list=None):
33 | if not list:
34 | list = []
35 | if path.exists("/usr/scripts") and not path.exists("/usr/script"):
36 | rename("/usr/scripts", "/usr/script")
37 | if not path.exists("/usr/script"):
38 | mkdir("/usr/script", 0o755)
39 | f = listdir("/usr/script")
40 | for line in f:
41 | parts = line.split()
42 | pkg = parts[0]
43 | if pkg.find(".sh") >= 0:
44 | list.append(pkg)
45 | IpkgInstaller.__init__(self, session, list)
46 | self.setTitle(_("Script runner"))
47 |
48 | self.skinName = ["VIXScriptRunner", "IpkgInstaller"]
49 | self["key_green"] = StaticText(_("Run"))
50 |
51 | self["myactions"] = ActionMap(["MenuActions"],
52 | {
53 | "menu": self.createSetup,
54 | }, -1)
55 |
56 | def createSetup(self):
57 | self.session.open(Setup, "vixscriptrunner", "SystemPlugins/ViX", PluginLanguageDomain)
58 |
59 | def install(self):
60 | list = self.list.getSelectionsList()
61 | cmdList = []
62 | for item in list:
63 | cmdList.append("chmod +x /usr/script/" + item[0] + " && . " + "/usr/script/" + str(item[0]))
64 | if len(cmdList) < 1 and len(self.list.list):
65 | cmdList.append("chmod +x /usr/script/" + self.list.getCurrent()[0][0] + " && . " + "/usr/script/" + str(self.list.getCurrent()[0][0]))
66 | if len(cmdList) > 0:
67 | self.session.open(Console, cmdlist=cmdList, closeOnSuccess=config.scriptrunner.close.value)
68 |
--------------------------------------------------------------------------------
/src/SwapManager.py:
--------------------------------------------------------------------------------
1 | from os import system, stat as mystat, path, remove, rename
2 | from glob import glob
3 | import stat
4 |
5 | from enigma import eTimer
6 |
7 | from . import _
8 |
9 | from Components.config import config, configfile, ConfigSubsection, ConfigYesNo
10 | from Components.ActionMap import ActionMap
11 | from Components.Console import Console
12 | from Components.Harddisk import harddiskmanager, getProcMounts
13 | from Components.Label import Label
14 | from Components.Pixmap import Pixmap
15 | from Components.Sources.StaticText import StaticText
16 | from Screens.ChoiceBox import ChoiceBox
17 | from Screens.MessageBox import MessageBox
18 | from Screens.Screen import Screen
19 |
20 | config.swapmanager = ConfigSubsection()
21 | config.swapmanager.swapautostart = ConfigYesNo(default=False)
22 |
23 | startswap = None
24 |
25 |
26 | def SwapAutostart(reason, session=None, **kwargs):
27 | global startswap
28 | if reason == 0:
29 | print("[SwapManager] autostart", config.swapmanager.swapautostart.value)
30 | if config.swapmanager.swapautostart.value:
31 | print("[SwapManager] autostart")
32 | startswap = StartSwap()
33 | startswap.start()
34 |
35 |
36 | class StartSwap:
37 | def __init__(self):
38 | self.Console = Console()
39 |
40 | def start(self):
41 | self.Console.ePopen("parted -l /dev/sd? | grep swap", self.startSwap2)
42 |
43 | def startSwap2(self, result=None, retval=None, extra_args=None): # lets find swap partitions(normally receiver specific and part of image build or user swap files
44 | swap_Pname = ""
45 | swap_Fname = ""
46 | # print("[SwapManager][StartSwap] Found a SWAP partition:", result)
47 | if result and result.find("swap") > 0: # so much garbage from parted command with eMMC partitions need further exclude.
48 | for line in result.split("\n"):
49 | # print("[SwapManager][StartSwap] grep lines in result", line)
50 | if "swap" not in line:
51 | continue
52 | parts = line.strip().split()
53 | swap_Pname = line.strip().rsplit(" ", 1)[-1]
54 | print("[SwapManager][StartSwap] Found a SWAP partition:", swap_Pname)
55 | devicelist = []
56 | for p in harddiskmanager.getMountedPartitions():
57 | d = path.normpath(p.mountpoint)
58 | if (path.exists(p.mountpoint) and p.mountpoint != "/"
59 | and not p.mountpoint.startswith("/media/net/")
60 | and not p.mountpoint.startswith("/media/autofs/")):
61 | devicelist.append((p.description, d))
62 | if len(devicelist):
63 | for device in devicelist:
64 | for filename in glob(device[1] + "/swap*"):
65 | if path.exists(filename):
66 | swap_Fname = filename
67 | print("[SwapManager][StartSwap] Found a SWAP file on ", swap_Fname)
68 | # basically a swap file if created, is now given higher priority than system swap partition if built in image.
69 | # swapmanager can now set a user swap file to be active, or deleted and if present system swap partition will be used.
70 | # if both are present, then swap file is used ahead of swap partition (based on priority) in /proc/swaps.
71 | f = open("/proc/swaps")
72 | swapfile = f.read()
73 | f.close()
74 | print("[SwapManager][StartSwap] partition/filename", swap_Fname, " ", swap_Pname)
75 | if swap_Fname and swapfile.find(swap_Fname) == -1:
76 | system("swapon -p 10 " + swap_Fname)
77 | print("[SwapManager][StartSwap] SWAP file active on ", swap_Fname)
78 | if swap_Pname and not swap_Fname:
79 | print("[SwapManager][StartSwap] SWAP partition active on ", swap_Pname)
80 | if swap_Pname and swap_Fname:
81 | print("[SwapManager][StartSwap] SWAP file %s chosen before swap partition on %s by priority" % (swap_Fname, swap_Pname))
82 |
83 |
84 | class VIXSwap(Screen):
85 | skin = ["""
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 | """,
106 | 560, 250, # screen
107 | 0, 0, 140, 40, #colors
108 | 140, 0, 140, 40,
109 | 280, 0, 140, 40,
110 | 420, 0, 140, 40,
111 | 0, 0, 140, 40, 20,
112 | 140, 0, 140, 40, 20,
113 | 280, 0, 140, 40, 20,
114 | 420, 0, 140, 40, 20,
115 | 10, 50, 32, 32, # lock off
116 | 10, 50, 32, 32, # lock on
117 | 50, 50, 360, 30, 20,
118 | 10, 100, 150, 30, 20,
119 | 10, 150, 150, 30, 20,
120 | 10, 200, 150, 30, 20,
121 | 160, 100, 220, 30, 20,
122 | 160, 150, 220, 30, 20,
123 | 160, 200, 100, 30, 20,
124 | 160, 200, 100, 30, 20,
125 | ]
126 |
127 | def __init__(self, session):
128 | Screen.__init__(self, session)
129 | self.setTitle(_("SWAP manager"))
130 |
131 | self["lab1"] = Label()
132 | self["autostart_on"] = Pixmap()
133 | self["autostart_off"] = Pixmap()
134 | self["lab2"] = Label(_("SWAP name:"))
135 | self["labplace"] = Label()
136 | self["lab3"] = Label(_("SWAP size:"))
137 | self["labsize"] = Label()
138 | self["lab4"] = Label(_("Status:"))
139 | self["inactive"] = Label(_("Inactive"))
140 | self["active"] = Label(_("Active"))
141 | self["key_red"] = Label(_("Close"))
142 | self["key_green"] = Label(_("Activate"))
143 | self["key_yellow"] = Label(_("Autostart"))
144 | self["key_blue"] = Label(_("Create"))
145 | self["swapname_summary"] = StaticText()
146 | self["swapactive_summary"] = StaticText()
147 | self.Console = Console()
148 | self.swap_name = ""
149 | self.new_name = ""
150 | self.creatingswap = False
151 | self.swap_active = False
152 | self["actions"] = ActionMap(["WizardActions", "ColorActions", "MenuActions"],
153 | {
154 | "back": self.close,
155 | "red": self.close,
156 | "green": self.actDeact,
157 | "yellow": self.autoSsWap,
158 | "blue": self.createDel,
159 | "menu": self.close,
160 | })
161 | self.activityTimer = eTimer()
162 | self.activityTimer.timeout.get().append(self.getSwapDevice)
163 | self.updateSwap()
164 |
165 | def updateSwap(self, result=None, retval=None, extra_args=None):
166 | self["actions"].setEnabled(False)
167 | self.swap_active = False
168 | self.swap_name = None
169 | self["autostart_on"].hide()
170 | self["autostart_off"].show()
171 | self["active"].hide()
172 | self["inactive"].show()
173 | self["labplace"].hide()
174 | self["labsize"].hide()
175 | self["swapactive_summary"].setText(_("Current status:"))
176 | scanning = _("Wait please while scanning...")
177 | self["lab1"].setText(scanning)
178 | self.activityTimer.start(10)
179 |
180 | def getSwapDevice(self):
181 | self.activityTimer.stop()
182 | if path.exists("/etc/rcS.d/S98SwapManager"):
183 | remove("/etc/rcS.d/S98SwapManager")
184 | config.swapmanager.swapautostart.value = True
185 | config.swapmanager.swapautostart.save()
186 | if path.exists("/tmp/swapdevices.tmp"):
187 | remove("/tmp/swapdevices.tmp")
188 | self.Console.ePopen("parted -l /dev/sd? | grep swap", self.updateSwap2)
189 |
190 | def updateSwap2(self, result=None, retval=None, extra_args=None):
191 | self.swap_active = False
192 | self.swap_Pname = ""
193 | self.Pswapsize = 0
194 | self.swap_Pactive = False
195 | self.swap_Fname = ""
196 | self.Fswapsize = 0
197 | self.swap_Factive = False
198 | self.MMCdevice = False
199 | self.swapdevice = 0
200 | self.swapcount = 0
201 | self.swapsize = 0
202 | if result.find("swap") > 0: # lets find swap partition
203 | for line in result.split("\n"):
204 | if "swap" not in line: # so much garbage from parted command with eMMC partitions need further exclude.
205 | continue
206 | parts = line.strip().split()
207 | # print("[SwapManager][updateSwap2] parts = ", parts, " ", parts[3])
208 | self.swap_Pname = line.strip().split(" ", 1)[-1]
209 | self.Pswapsize = parts[3]
210 | if self.swap_Pname == "sfdisk:":
211 | self.swap_Pname = ""
212 | f = open("/proc/swaps", "r")
213 | for line2 in f.readlines():
214 | parts = line2.strip().split()
215 | if line2.find("partition") != -1:
216 | if "mmc" in parts[0]:
217 | self.MMCdevice = True
218 | self.swap_Pname = parts[0]
219 | # self["key_blue"].setText("")
220 | self.swap_name = _("manufacturer defined swap")
221 | self.swap_Pactive = True
222 | f.close()
223 | self["key_blue"].setText(_("Create"))
224 | devicelist = [] # lets find swap file
225 | for p in harddiskmanager.getMountedPartitions():
226 | d = path.normpath(p.mountpoint)
227 | if path.exists(p.mountpoint) and p.mountpoint != "/" and not p.mountpoint.startswith("/media/net"):
228 | devicelist.append((p.description, d))
229 | if len(devicelist):
230 | print("[SwapManager][{updateSwap2] devicelist = ", devicelist)
231 | for device in devicelist:
232 | print("[SwapManager][{updateSwap2] device = ", device, device[1])
233 | for filename in glob(device[1] + "/swap*"):
234 | self.swap_name = self.swap_Fname = filename
235 | self["key_blue"].setText(_("Delete"))
236 | info = mystat(self.swap_name)
237 | self.Fswapsize = info[stat.ST_SIZE]
238 |
239 | if self.swap_Fname: # if swap file
240 | self["labplace"].setText(self.swap_Fname)
241 | self["autostart_on"].hide()
242 | self["autostart_off"].show()
243 | elif self.swap_Pname: # if only swap partition
244 | self["labplace"].setText(self.swap_name)
245 | else:
246 | self["labplace"].setText("")
247 | self["labplace"].show()
248 |
249 | f = open("/proc/swaps", "r")
250 | for line in f.readlines():
251 | parts = line.strip().split()
252 | if line.find("file") != -1: # if swap file - takes precedence over swap parition
253 | self["autostart_on"].show()
254 | self["autostart_off"].hide()
255 | self.swap_active = self.swap_Factive = True
256 | continue
257 | elif line.find("partition") != -1 and not self.swap_Fname: # only swap partition
258 | self.swap_active = self.swap_Pactive = True
259 | continue
260 |
261 | f.close()
262 | if self.swap_Fname:
263 | self.swapsize = int(self.Fswapsize)
264 | if self.swapsize > 0:
265 | if self.swapsize >= 1024:
266 | self.swapsize = self.swapsize // 1000
267 | if self.swapsize >= 1024:
268 | self.swapsize = self.swapsize // 1000
269 | self.swapsize = str(self.swapsize) + " " + "MB"
270 | else:
271 | self.swapsize = str(self.swapsize) + " " + "KB"
272 | else:
273 | self.swapsize = ""
274 | elif self.swap_Pname:
275 | self.swapsize = self.Pswapsize # picked up from parted command
276 | self["labsize"].setText(self.swapsize)
277 | self["labsize"].show()
278 |
279 | if self.swap_active:
280 | self["inactive"].hide()
281 | self["active"].show()
282 | self["key_green"].setText(_("Deactivate"))
283 | self["swapactive_summary"].setText(_("Current status:") + " " + _("Active"))
284 | else:
285 | self["inactive"].show()
286 | self["active"].hide()
287 | self["key_green"].setText(_("Activate"))
288 | self["swapactive_summary"].setText(_("Current status:") + " " + _("Inactive"))
289 | if self.swap_name == _("manufacturer defined swap"):
290 | self["key_green"].setText("")
291 | scanning = _("manufacturer defined swap enabled at startup")
292 | else:
293 | scanning = _("Enable SWAP at startup")
294 |
295 | if config.swapmanager.swapautostart.value or self.swap_name == _("manufacturer defined swap"):
296 | # if config.swapmanager.swapautostart.value:
297 | self["autostart_off"].hide()
298 | self["autostart_on"].show()
299 | self["key_yellow"].setText("")
300 | else:
301 | config.swapmanager.swapautostart.setValue(False)
302 | config.swapmanager.swapautostart.save()
303 | configfile.save()
304 | self["autostart_on"].hide()
305 | self["autostart_off"].show()
306 | self["lab1"].setText(scanning)
307 | self["lab1"].show()
308 | self["actions"].setEnabled(True)
309 |
310 | name = self["labplace"].text
311 | self["swapname_summary"].setText(name)
312 |
313 | def actDeact(self):
314 | if self.swap_Factive:
315 | self.Console.ePopen("swapoff " + self.swap_Fname, self.updateSwap)
316 | self.swap_Factive = False
317 | else:
318 | if self.swap_Fname:
319 | self.Console.ePopen("swapon -p 10 " + self.swap_Fname, self.updateSwap)
320 | self.swap_Factive = True
321 | config.swapmanager.swapautostart.setValue(True)
322 | config.swapmanager.swapautostart.save()
323 | configfile.save()
324 | else:
325 | mybox = self.session.open(MessageBox, _("SWAP file not found. You have to create the file before you try to activate it."), MessageBox.TYPE_INFO)
326 | mybox.setTitle(_("Info"))
327 | self.updateSwap()
328 |
329 | def createDel(self):
330 | if self.swap_Fname:
331 | if self.swap_Factive:
332 | self.Console.ePopen("swapoff " + self.swap_Fname, self.createDel2)
333 | else:
334 | self.createDel2(None, 0)
335 | else:
336 | self.doCreateSwap()
337 |
338 | def createDel2(self, result, retval, extra_args=None):
339 | if self.swap_name == _("manufacturer defined swap"):
340 | self.updateSwap()
341 | if retval == 0:
342 | # print("[SwapManager][createDel2] delete swap = ", self.swap_Fname)
343 | self.Console.ePopen("rm " + self.swap_Fname, self.createDel3)
344 |
345 | def createDel3(self, result, retval, extra_args=None):
346 | print("[SwapManager][createDel3] delete swap, retval, result", retval, " ", result)
347 | if config.swapmanager.swapautostart.value:
348 | config.swapmanager.swapautostart.setValue(False)
349 | config.swapmanager.swapautostart.save()
350 | configfile.save()
351 | self.updateSwap()
352 |
353 | def doCreateSwap(self):
354 | parts = []
355 | supported_filesystems = frozenset(("ext4", "ext3"))
356 | candidates = []
357 | mounts = getProcMounts()
358 | for partition in harddiskmanager.getMountedPartitions(False, mounts):
359 | if partition.filesystem(mounts) in supported_filesystems:
360 | candidates.append((partition.description, partition.mountpoint))
361 | if len(candidates):
362 | self.session.openWithCallback(self.doCSname, ChoiceBox, title=_("Please select device to use as SWAP file location."), list=candidates)
363 | else:
364 | self.session.open(MessageBox, _("Sorry, no physical devices that supports SWAP attached. Can't create SWAP file on network or fat32 file-systems."), MessageBox.TYPE_INFO, timeout=10)
365 |
366 | def doCSname(self, name):
367 | if name:
368 | self.new_name = name[1]
369 | myoptions = [[_("8 Mb"), "8192"], [_("16 Mb"), "16384"], [_("32 Mb"), "32768"], [_("64 Mb"), "65536"], [_("96 Mb"), "98304"], [_("128 Mb"), "131072"], [_("256 Mb"), "262144"], [_("512 Mb"), "524288"], [_("756 Mb"), "774144"], [_("1024 Mb"), "1048576"]]
370 | self.session.openWithCallback(self.doCSsize, ChoiceBox, title=_("Select the SWAP file size:"), list=myoptions)
371 |
372 | def doCSsize(self, swapsize):
373 | if swapsize:
374 | self["actions"].setEnabled(False)
375 | scanning = _("Wait please while creating SWAP file...")
376 | self["lab1"].setText(scanning)
377 | self["lab1"].show()
378 | swapsize = swapsize[1]
379 | myfile = self.new_name + "swapfile"
380 | self.commands = []
381 | self.commands.append("dd if=/dev/zero of=" + myfile + " bs=1024 count=" + swapsize + " 2>/dev/null")
382 | self.commands.append("mkswap " + myfile)
383 | self.Console.eBatch(self.commands, self.updateSwap, debug=True)
384 |
385 | def autoSsWap(self):
386 | if self.swap_name:
387 | if config.swapmanager.swapautostart.value:
388 | config.swapmanager.swapautostart.setValue(False)
389 | config.swapmanager.swapautostart.save()
390 | else:
391 | config.swapmanager.swapautostart.setValue(True)
392 | config.swapmanager.swapautostart.save()
393 | configfile.save()
394 | else:
395 | mybox = self.session.open(MessageBox, _("You have to create a SWAP file before trying to activate the autostart."), MessageBox.TYPE_INFO)
396 | mybox.setTitle(_("Info"))
397 | self.updateSwap()
398 |
--------------------------------------------------------------------------------
/src/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import print_function, absolute_import
3 | import gettext
4 |
5 | from Components.Language import language
6 | from Tools.Directories import resolveFilename, SCOPE_PLUGINS
7 |
8 |
9 | PluginLanguageDomain = "vix"
10 | PluginLanguagePath = "SystemPlugins/ViX/locale"
11 |
12 |
13 | def pluginlanguagedomain():
14 | return PluginLanguageDomain
15 |
16 |
17 | def localeInit():
18 | gettext.bindtextdomain(PluginLanguageDomain, resolveFilename(SCOPE_PLUGINS, PluginLanguagePath))
19 |
20 |
21 | def _(txt):
22 | if gettext.dgettext(PluginLanguageDomain, txt):
23 | return gettext.dgettext(PluginLanguageDomain, txt)
24 | else:
25 | print("[" + PluginLanguageDomain + "] fallback to default translation for " + txt)
26 | return gettext.gettext(txt)
27 |
28 |
29 | language.addCallback(localeInit())
30 |
--------------------------------------------------------------------------------
/src/images/Makefile.am:
--------------------------------------------------------------------------------
1 | installdir = $(libdir)/enigma2/python/Plugins/SystemPlugins/ViX/images
2 |
3 | install_DATA = *.png
--------------------------------------------------------------------------------
/src/images/busy1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenViX/vix-core/11356134d3a0e0bfb92474e6a079dd2818376e09/src/images/busy1.png
--------------------------------------------------------------------------------
/src/images/busy10.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenViX/vix-core/11356134d3a0e0bfb92474e6a079dd2818376e09/src/images/busy10.png
--------------------------------------------------------------------------------
/src/images/busy11.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenViX/vix-core/11356134d3a0e0bfb92474e6a079dd2818376e09/src/images/busy11.png
--------------------------------------------------------------------------------
/src/images/busy12.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenViX/vix-core/11356134d3a0e0bfb92474e6a079dd2818376e09/src/images/busy12.png
--------------------------------------------------------------------------------
/src/images/busy13.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenViX/vix-core/11356134d3a0e0bfb92474e6a079dd2818376e09/src/images/busy13.png
--------------------------------------------------------------------------------
/src/images/busy14.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenViX/vix-core/11356134d3a0e0bfb92474e6a079dd2818376e09/src/images/busy14.png
--------------------------------------------------------------------------------
/src/images/busy15.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenViX/vix-core/11356134d3a0e0bfb92474e6a079dd2818376e09/src/images/busy15.png
--------------------------------------------------------------------------------
/src/images/busy16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenViX/vix-core/11356134d3a0e0bfb92474e6a079dd2818376e09/src/images/busy16.png
--------------------------------------------------------------------------------
/src/images/busy17.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenViX/vix-core/11356134d3a0e0bfb92474e6a079dd2818376e09/src/images/busy17.png
--------------------------------------------------------------------------------
/src/images/busy18.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenViX/vix-core/11356134d3a0e0bfb92474e6a079dd2818376e09/src/images/busy18.png
--------------------------------------------------------------------------------
/src/images/busy19.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenViX/vix-core/11356134d3a0e0bfb92474e6a079dd2818376e09/src/images/busy19.png
--------------------------------------------------------------------------------
/src/images/busy2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenViX/vix-core/11356134d3a0e0bfb92474e6a079dd2818376e09/src/images/busy2.png
--------------------------------------------------------------------------------
/src/images/busy20.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenViX/vix-core/11356134d3a0e0bfb92474e6a079dd2818376e09/src/images/busy20.png
--------------------------------------------------------------------------------
/src/images/busy21.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenViX/vix-core/11356134d3a0e0bfb92474e6a079dd2818376e09/src/images/busy21.png
--------------------------------------------------------------------------------
/src/images/busy22.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenViX/vix-core/11356134d3a0e0bfb92474e6a079dd2818376e09/src/images/busy22.png
--------------------------------------------------------------------------------
/src/images/busy23.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenViX/vix-core/11356134d3a0e0bfb92474e6a079dd2818376e09/src/images/busy23.png
--------------------------------------------------------------------------------
/src/images/busy24.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenViX/vix-core/11356134d3a0e0bfb92474e6a079dd2818376e09/src/images/busy24.png
--------------------------------------------------------------------------------
/src/images/busy3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenViX/vix-core/11356134d3a0e0bfb92474e6a079dd2818376e09/src/images/busy3.png
--------------------------------------------------------------------------------
/src/images/busy4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenViX/vix-core/11356134d3a0e0bfb92474e6a079dd2818376e09/src/images/busy4.png
--------------------------------------------------------------------------------
/src/images/busy5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenViX/vix-core/11356134d3a0e0bfb92474e6a079dd2818376e09/src/images/busy5.png
--------------------------------------------------------------------------------
/src/images/busy6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenViX/vix-core/11356134d3a0e0bfb92474e6a079dd2818376e09/src/images/busy6.png
--------------------------------------------------------------------------------
/src/images/busy7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenViX/vix-core/11356134d3a0e0bfb92474e6a079dd2818376e09/src/images/busy7.png
--------------------------------------------------------------------------------
/src/images/busy8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenViX/vix-core/11356134d3a0e0bfb92474e6a079dd2818376e09/src/images/busy8.png
--------------------------------------------------------------------------------
/src/images/busy9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenViX/vix-core/11356134d3a0e0bfb92474e6a079dd2818376e09/src/images/busy9.png
--------------------------------------------------------------------------------
/src/images/dev_cdrom.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenViX/vix-core/11356134d3a0e0bfb92474e6a079dd2818376e09/src/images/dev_cdrom.png
--------------------------------------------------------------------------------
/src/images/dev_cf.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenViX/vix-core/11356134d3a0e0bfb92474e6a079dd2818376e09/src/images/dev_cf.png
--------------------------------------------------------------------------------
/src/images/dev_hdd.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenViX/vix-core/11356134d3a0e0bfb92474e6a079dd2818376e09/src/images/dev_hdd.png
--------------------------------------------------------------------------------
/src/images/dev_mmc.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenViX/vix-core/11356134d3a0e0bfb92474e6a079dd2818376e09/src/images/dev_mmc.png
--------------------------------------------------------------------------------
/src/images/dev_sd.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenViX/vix-core/11356134d3a0e0bfb92474e6a079dd2818376e09/src/images/dev_sd.png
--------------------------------------------------------------------------------
/src/images/dev_usb.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenViX/vix-core/11356134d3a0e0bfb92474e6a079dd2818376e09/src/images/dev_usb.png
--------------------------------------------------------------------------------
/src/install.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenViX/vix-core/11356134d3a0e0bfb92474e6a079dd2818376e09/src/install.png
--------------------------------------------------------------------------------
/src/installable.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenViX/vix-core/11356134d3a0e0bfb92474e6a079dd2818376e09/src/installable.png
--------------------------------------------------------------------------------
/src/installed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenViX/vix-core/11356134d3a0e0bfb92474e6a079dd2818376e09/src/installed.png
--------------------------------------------------------------------------------
/src/maintainer.info:
--------------------------------------------------------------------------------
1 | andyblac@icloud.com
2 | ViX core plugins
--------------------------------------------------------------------------------
/src/noprev.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenViX/vix-core/11356134d3a0e0bfb92474e6a079dd2818376e09/src/noprev.png
--------------------------------------------------------------------------------
/src/plugin.py:
--------------------------------------------------------------------------------
1 | from os import listdir, path, stat
2 |
3 | from . import _
4 | from Plugins.Plugin import PluginDescriptor
5 | from Components.config import config, ConfigBoolean, configfile
6 | from Components.SystemInfo import SystemInfo
7 |
8 | from .BackupManager import BackupManagerautostart
9 | from .ImageManager import ImageManagerautostart
10 | from .IPKInstaller import IpkgInstaller
11 | from .ScriptRunner import ScriptRunnerAutostart
12 | from .SoftcamManager import SoftcamAutostart
13 | from .SwapManager import SwapAutostart
14 | from .IPKInstaller import IpkgInstaller
15 |
16 | config.misc.restorewizardrun = ConfigBoolean(default=False)
17 |
18 | # On plugin initialisation (called by StartEnigma). language will be assigned as follows if config.misc.firstrun.value:
19 | # Default language en_GB (OpenViX) is set by SetupDevices called by StartEnigma
20 | # If no backup, the languagewizard will be inserted by Plugin into the wizards.
21 | # If backup, then language will be set here from config.osd.language if in backup, else default language
22 | #
23 |
24 |
25 | def setLanguageFromBackup(backupfile):
26 | print("[ViX plugin][setLanguageFromBackup] backupfile", backupfile)
27 | import tarfile
28 |
29 | try:
30 | tar = tarfile.open(backupfile)
31 | member = tar.getmember("etc/enigma2/settings")
32 | except KeyError:
33 | print("[ViX plugin][setLanguageFromBackup] language selected failed")
34 | tar.close()
35 | return
36 |
37 | for line in tar.extractfile(member):
38 | line = line.decode()
39 | if line.startswith("config.osd.language"):
40 | languageToSelect = line.strip().split("=")[1]
41 | print("[ViX plugin][setLanguageFromBackup] language selected", languageToSelect)
42 | from Components.Language import language
43 | language.InitLang()
44 | language.activateLanguage(languageToSelect)
45 | config.misc.languageselected.value = 0 # 0 means found
46 | config.misc.languageselected.save()
47 | break
48 | tar.close()
49 |
50 |
51 | def checkConfigBackup():
52 | backups = []
53 | for dir in ["/media/%s/backup" % media for media in listdir("/media/") if path.isdir(path.join("/media/", media))]:
54 | try:
55 | backups += [{"name": f, "mtime": stat(f).st_mtime} for x in listdir(dir) if (f := path.join(dir, x)) and path.isfile(f) and f.endswith(".tar.gz") and "vix" in f.lower()]
56 | except FileNotFoundError: # e.g. /media/autofs/xxx will crash listdir if "xxx" is inactive
57 | pass
58 | if backups:
59 | backupfile = next(iter(sorted(backups, key=lambda x: x["mtime"], reverse=True)))["name"] # select the most recent
60 | print("[RestoreWizard] Backup Image:", backupfile)
61 | return backupfile
62 | return None
63 |
64 |
65 | if config.misc.firstrun.value and not config.misc.restorewizardrun.value:
66 | backupAvailable = checkConfigBackup()
67 | if backupAvailable:
68 | setLanguageFromBackup(backupAvailable)
69 |
70 |
71 | def VIXMenu(session):
72 | from .import ui
73 | return ui.VIXMenu(session)
74 |
75 |
76 | def UpgradeMain(session, **kwargs):
77 | session.open(VIXMenu)
78 |
79 |
80 | def startSetup(menuid):
81 | if menuid != "setup":
82 | return []
83 | return [(_("ViX"), UpgradeMain, "vix_menu", 1010)]
84 |
85 |
86 | def RestoreWizard(*args, **kwargs):
87 | from .RestoreWizard import RestoreWizard
88 | return RestoreWizard(*args, **kwargs)
89 |
90 |
91 | def LanguageWizard(*args, **kwargs):
92 | from Screens.LanguageSelection import LanguageWizard
93 | return LanguageWizard(*args, **kwargs)
94 |
95 |
96 | def SoftcamManager(session):
97 | from .SoftcamManager import VIXSoftcamManager
98 | return VIXSoftcamManager(session)
99 |
100 |
101 | def SoftcamMenu(session, **kwargs):
102 | session.open(SoftcamManager)
103 |
104 |
105 | def SoftcamSetup(menuid):
106 | if menuid == "cam":
107 | return [(_("Softcam manager"), SoftcamMenu, "softcamsetup", 1005)]
108 | return []
109 |
110 |
111 | def BackupManager(session):
112 | from .BackupManager import VIXBackupManager
113 | return VIXBackupManager(session)
114 |
115 |
116 | def BackupManagerMenu(session, **kwargs):
117 | session.open(BackupManager)
118 |
119 |
120 | def ImageManager(session):
121 | from .ImageManager import VIXImageManager
122 | return VIXImageManager(session)
123 |
124 |
125 | def ImageManagerMenu(session, **kwargs):
126 | session.open(ImageManager)
127 |
128 |
129 | def ImageManagerStart(menuid, **kwargs):
130 | if menuid == "mainmenu":
131 | return [(_("Image Manager"), ImageManagerMenu, "image_manager", -1)]
132 | return []
133 |
134 |
135 | def H9SDmanager(session):
136 | from .H9SDmanager import H9SDmanager
137 | return H9SDmanager(session)
138 |
139 |
140 | def H9SDmanagerMenu(session, **kwargs):
141 | session.open(H9SDmanager)
142 |
143 |
144 | def MountManager(session):
145 | from .MountManager import VIXDevicesPanel
146 | return VIXDevicesPanel(session)
147 |
148 |
149 | def MountManagerMenu(session, **kwargs):
150 | session.open(MountManager)
151 |
152 |
153 | def ScriptRunner(session):
154 | from .ScriptRunner import VIXScriptRunner
155 | return VIXScriptRunner(session)
156 |
157 |
158 | def ScriptRunnerMenu(session, **kwargs):
159 | session.open(ScriptRunner)
160 |
161 |
162 | def SwapManager(session):
163 | from .SwapManager import VIXSwap
164 | return VIXSwap(session)
165 |
166 |
167 | def SwapManagerMenu(session, **kwargs):
168 | session.open(SwapManager)
169 |
170 |
171 | def filescan_open(list, session, **kwargs):
172 | filelist = [x.path for x in list]
173 | session.open(IpkgInstaller, filelist) # list
174 |
175 |
176 | def filescan(**kwargs):
177 | from Components.Scanner import Scanner, ScanPath
178 | return Scanner(mimetypes=["application/x-debian-package"],
179 | paths_to_scan=[
180 | ScanPath(path="ipk", with_subdirs=True),
181 | ScanPath(path="", with_subdirs=False),
182 | ],
183 | name="Ipkg",
184 | description=_("Install extensions."),
185 | openfnc=filescan_open)
186 |
187 |
188 | def Plugins(**kwargs):
189 | if SystemInfo["MultiBootSlot"] == 0: # only in recovery image
190 | plist = [PluginDescriptor(name=_("Image Manager"), where=PluginDescriptor.WHERE_MENU, needsRestart=False, fnc=ImageManagerStart)]
191 | if not config.misc.firstrun.value:
192 | plist.append(PluginDescriptor(name=_("Vu+ ImageManager wizard"), where=PluginDescriptor.WHERE_WIZARD, needsRestart=False, fnc=(30, ImageManager)))
193 | return plist
194 |
195 | plist = [PluginDescriptor(where=PluginDescriptor.WHERE_MENU, needsRestart=False, fnc=startSetup),
196 | PluginDescriptor(name=_("ViX Image Management"), where=PluginDescriptor.WHERE_EXTENSIONSMENU, fnc=UpgradeMain),
197 | PluginDescriptor(where=PluginDescriptor.WHERE_MENU, fnc=SoftcamSetup)]
198 | if config.softcammanager.showinextensions.value:
199 | plist.append(PluginDescriptor(name=_("Softcam manager"), where=PluginDescriptor.WHERE_EXTENSIONSMENU, fnc=SoftcamMenu))
200 | if config.scriptrunner.showinextensions.value:
201 | plist.append(PluginDescriptor(name=_("Script runner"), where=PluginDescriptor.WHERE_EXTENSIONSMENU, fnc=ScriptRunnerMenu))
202 | plist.append(PluginDescriptor(where=PluginDescriptor.WHERE_AUTOSTART, fnc=SoftcamAutostart))
203 | plist.append(PluginDescriptor(where=PluginDescriptor.WHERE_AUTOSTART, fnc=SwapAutostart))
204 | plist.append(PluginDescriptor(where=PluginDescriptor.WHERE_SESSIONSTART, fnc=ImageManagerautostart))
205 | plist.append(PluginDescriptor(where=PluginDescriptor.WHERE_SESSIONSTART, fnc=BackupManagerautostart))
206 | plist.append(PluginDescriptor(where=PluginDescriptor.WHERE_SESSIONSTART, fnc=ScriptRunnerAutostart))
207 | if config.misc.firstrun.value and not config.misc.restorewizardrun.value:
208 | if backupAvailable: # skip langauge wizard as it was set from the backup
209 | plist.append(PluginDescriptor(name=_("Restore wizard"), where=PluginDescriptor.WHERE_WIZARD, needsRestart=False, fnc=(4, RestoreWizard)))
210 | else:
211 | plist.append(PluginDescriptor(name=_("Language Wizard"), where=PluginDescriptor.WHERE_WIZARD, needsRestart=False, fnc=(1, LanguageWizard)))
212 | plist.append(PluginDescriptor(name=_("Ipkg"), where=PluginDescriptor.WHERE_FILESCAN, needsRestart=False, fnc=filescan))
213 | plist.append(PluginDescriptor(name=_("ViX Backup manager"), where=PluginDescriptor.WHERE_VIXMENU, fnc=BackupManagerMenu))
214 | plist.append(PluginDescriptor(name=_("ViX Image manager"), where=PluginDescriptor.WHERE_VIXMENU, fnc=ImageManagerMenu))
215 | plist.append(PluginDescriptor(name=_("ViX Mount manager"), where=PluginDescriptor.WHERE_VIXMENU, fnc=MountManagerMenu))
216 | plist.append(PluginDescriptor(name=_("ViX Script runner"), where=PluginDescriptor.WHERE_VIXMENU, fnc=ScriptRunnerMenu))
217 | plist.append(PluginDescriptor(name=_("ViX SWAP manager"), where=PluginDescriptor.WHERE_VIXMENU, fnc=SwapManagerMenu))
218 | return plist
219 |
--------------------------------------------------------------------------------
/src/remove.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenViX/vix-core/11356134d3a0e0bfb92474e6a079dd2818376e09/src/remove.png
--------------------------------------------------------------------------------
/src/restorewizard.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | self.clearSelectedKeys()
9 | self.selectKey("OK")
10 |
11 |
12 | self.buildList(self.selectedAction)
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | self.clearSelectedKeys()
22 | self.selectKey("OK")
23 |
24 |
25 | self.buildList(self.selectedAction)
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 | self.clearSelectedKeys()
35 | self.selectKey("OK")
36 |
37 |
38 | self.buildList(self.selectedAction)
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 | self.clearSelectedKeys()
48 | self.selectKey("OK")
49 |
50 |
51 | self.buildList(self.selectedAction)
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 | self.clearSelectedKeys()
61 | self.selectKey("OK")
62 |
63 |
64 | self.buildList(self.selectedAction)
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 | self.buildList(None)
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 | self.buildList(None)
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/src/setup.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | config.softcammanager.showinextensions
5 | config.softcammanager.softcamtimerenabled
6 | config.softcammanager.softcamtimer
7 |
8 |
9 | config.backupmanager.backuplocation
10 | config.backupmanager.folderprefix
11 | config.backupmanager.showboxname
12 | config.backupmanager.schedule
13 | config.backupmanager.scheduletime
14 | config.backupmanager.repeattype
15 | config.backupmanager.query
16 | config.backupmanager.types_to_prune
17 |
18 | config.backupmanager.number_to_keep
19 |
20 |
21 |
22 | config.imagemanager.autosettingsbackup
23 | config.imagemanager.extensive_location_search
24 | config.imagemanager.backuplocation
25 | config.imagemanager.folderprefix
26 | config.imagemanager.schedule
27 | config.imagemanager.scheduletime
28 | config.imagemanager.repeattype
29 | config.imagemanager.query
30 | config.imagemanager.number_to_keep
31 | config.imagemanager.login_as_ViX_developer
32 |
33 | config.imagemanager.developer_username
34 | config.imagemanager.developer_password
35 |
36 | config.imagemanager.imagefeed_MyBuild
37 |
38 |
39 | config.scriptrunner.close
40 | config.scriptrunner.showinextensions
41 |
42 |
43 |
--------------------------------------------------------------------------------
/src/ui.py:
--------------------------------------------------------------------------------
1 | from os import listdir, path, mkdir
2 |
3 | from . import _
4 |
5 | from Components.ActionMap import NumberActionMap
6 | from Components.config import config
7 | from Components.Sources.StaticText import StaticText
8 | from Components.Sources.List import List
9 | from Components.SystemInfo import SystemInfo
10 | from Screens.ParentalControlSetup import ProtectedScreen
11 | from Screens.Screen import Screen
12 |
13 |
14 | class VIXMenu(Screen, ProtectedScreen):
15 | skin = ["""
16 |
17 |
18 |
19 |
20 |
21 | {"template": [
22 | MultiContentEntryText(pos = (%d,%d), size = (%d,%d), flags = RT_HALIGN_LEFT, text = 1), # index 0 is the MenuText,
23 | ],
24 | "fonts": [gFont("Regular",%d)],
25 | "itemHeight":%d
26 | }
27 |
28 |
29 |
30 |
31 | {"template": [
32 | MultiContentEntryText(pos = (%d,%d), size = (%d,%d), flags = RT_HALIGN_CENTER|RT_VALIGN_CENTER|RT_WRAP, text = 2), # index 2 is the Description,
33 | ],
34 | "fonts": [gFont("Regular",%d)],
35 | "itemHeight":%d
36 | }
37 |
38 |
39 |
40 | """,
41 | 610, 410, # screen
42 | 0, 0, 140, 40, # key red image
43 | 0, 0, 140, 40, 20, # key red text
44 | 15, 60, 330, 286, # first menu Listbox
45 | 2, 0, 330, 26, # template one
46 | 22, # fonts
47 | 26, # ItemHeight
48 | 360, 50, 240, 300, # second menu Listbox
49 | 2, 2, 240, 300, # template two
50 | 22, # fonts
51 | 300, # itemHeight
52 | 5, 360, 600, 50, 22, # status
53 | ]
54 |
55 | def __init__(self, session, args=0):
56 | Screen.__init__(self, session)
57 | ProtectedScreen.__init__(self)
58 | self.setTitle(_("ViX"))
59 | self.menu = args
60 | self.list = []
61 | if self.menu == 0:
62 | self.list.append(("backup-manager", _("Backup manager"), _("Manage settings backup."), None))
63 | self.list.append(("image-manager", _("Image manager"), _("Backup/Flash/ReBoot system image."), None))
64 | self.list.append(("ipkg-install", _("Install local extension"), _("Install IPK's from your tmp folder."), None))
65 | self.list.append(("mount-manager", _("Mount manager"), _("Manage your devices mount points."), None))
66 | self.list.append(("script-runner", _("Script runner"), _("Run your shell scripts."), None))
67 | self.list.append(("swap-manager", _("SWAP manager"), _("Create and Manage your SWAP files."), None))
68 | if SystemInfo["HasH9SD"]:
69 | self.list.append(("H9SDcard manager", _("H9SDcard Manager"), _("Move Nand root to SD card"), None))
70 | self["menu"] = List(self.list)
71 | self["key_red"] = StaticText(_("Close"))
72 |
73 | self["shortcuts"] = NumberActionMap(["ShortcutActions", "WizardActions", "InfobarEPGActions", "MenuActions", "NumberActions"],
74 | {
75 | "ok": self.go,
76 | "back": self.close,
77 | "red": self.close,
78 | "menu": self.closeRecursive,
79 | "1": self.go,
80 | "2": self.go,
81 | "3": self.go,
82 | "4": self.go,
83 | "5": self.go,
84 | "6": self.go,
85 | "7": self.go,
86 | "8": self.go,
87 | "9": self.go,
88 | }, -1)
89 | self.onLayoutFinish.append(self.layoutFinished)
90 | self.onChangedEntry = []
91 | self["menu"].onSelectionChanged.append(self.selectionChanged)
92 |
93 | def isProtected(self):
94 | return config.ParentalControl.setuppinactive.value and config.ParentalControl.config_sections.vixmenu.value
95 |
96 | def createSummary(self):
97 | from Screens.PluginBrowser import PluginBrowserSummary
98 | return PluginBrowserSummary
99 |
100 | def selectionChanged(self):
101 | item = self["menu"].getCurrent()
102 | if item:
103 | name = item[1]
104 | desc = item[2]
105 | else:
106 | name = "-"
107 | desc = ""
108 | for cb in self.onChangedEntry:
109 | cb(name, desc)
110 |
111 | def layoutFinished(self):
112 | idx = 0
113 | self["menu"].index = idx
114 |
115 | def go(self, num=None):
116 | if num is not None:
117 | num -= 1
118 | if not num < self["menu"].count():
119 | return
120 | self["menu"].setIndex(num)
121 | current = self["menu"].getCurrent()
122 | if current:
123 | currentEntry = current[0]
124 | if self.menu == 0:
125 | if currentEntry == "backup-manager":
126 | from .BackupManager import VIXBackupManager
127 | self.session.open(VIXBackupManager)
128 | elif currentEntry == "image-manager":
129 | from .ImageManager import VIXImageManager
130 | self.session.open(VIXImageManager)
131 | elif currentEntry == "H9SDcard manager":
132 | from .H9SDmanager import H9SDmanager
133 | self.session.open(H9SDmanager)
134 | elif currentEntry == "ipkg-install":
135 | from .IPKInstaller import VIXIPKInstaller
136 | self.session.open(VIXIPKInstaller)
137 | elif currentEntry == "mount-manager":
138 | from .MountManager import VIXDevicesPanel
139 | self.session.open(VIXDevicesPanel)
140 | elif currentEntry == "script-runner":
141 | from .ScriptRunner import VIXScriptRunner
142 | self.session.open(VIXScriptRunner, None)
143 | elif currentEntry == "swap-manager":
144 | from .SwapManager import VIXSwap
145 | self.session.open(VIXSwap)
146 |
147 | def closeRecursive(self):
148 | self.close(True)
149 |
--------------------------------------------------------------------------------
/src/update.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenViX/vix-core/11356134d3a0e0bfb92474e6a079dd2818376e09/src/update.png
--------------------------------------------------------------------------------
/src/upgrade.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenViX/vix-core/11356134d3a0e0bfb92474e6a079dd2818376e09/src/upgrade.png
--------------------------------------------------------------------------------
/src/upgradeable.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenViX/vix-core/11356134d3a0e0bfb92474e6a079dd2818376e09/src/upgradeable.png
--------------------------------------------------------------------------------