├── .github
└── workflows
│ └── sync-addon-metadata-translations.yml
├── COPYING
├── LICENSES
├── GPL-2.0-only.txt
└── GPL-2.0-or-later.txt
├── Makefile
├── addon.xml
├── default.py
├── requirements-dev.txt
├── resources
├── __init__.py
├── language
│ ├── resource.language.af_za
│ │ └── strings.po
│ ├── resource.language.am_et
│ │ └── strings.po
│ ├── resource.language.ar_sa
│ │ └── strings.po
│ ├── resource.language.ast_es
│ │ └── strings.po
│ ├── resource.language.az_az
│ │ └── strings.po
│ ├── resource.language.be_by
│ │ └── strings.po
│ ├── resource.language.bg_bg
│ │ └── strings.po
│ ├── resource.language.bs_ba
│ │ └── strings.po
│ ├── resource.language.ca_es
│ │ └── strings.po
│ ├── resource.language.cs_cz
│ │ └── strings.po
│ ├── resource.language.cy_gb
│ │ └── strings.po
│ ├── resource.language.da_dk
│ │ └── strings.po
│ ├── resource.language.de_de
│ │ └── strings.po
│ ├── resource.language.el_gr
│ │ └── strings.po
│ ├── resource.language.en_au
│ │ └── strings.po
│ ├── resource.language.en_gb
│ │ └── strings.po
│ ├── resource.language.en_nz
│ │ └── strings.po
│ ├── resource.language.en_us
│ │ └── strings.po
│ ├── resource.language.eo
│ │ └── strings.po
│ ├── resource.language.es_ar
│ │ └── strings.po
│ ├── resource.language.es_es
│ │ └── strings.po
│ ├── resource.language.es_mx
│ │ └── strings.po
│ ├── resource.language.et_ee
│ │ └── strings.po
│ ├── resource.language.eu_es
│ │ └── strings.po
│ ├── resource.language.fa_af
│ │ └── strings.po
│ ├── resource.language.fa_ir
│ │ └── strings.po
│ ├── resource.language.fi_fi
│ │ └── strings.po
│ ├── resource.language.fo_fo
│ │ └── strings.po
│ ├── resource.language.fr_ca
│ │ └── strings.po
│ ├── resource.language.fr_fr
│ │ └── strings.po
│ ├── resource.language.gl_es
│ │ └── strings.po
│ ├── resource.language.he_il
│ │ └── strings.po
│ ├── resource.language.hi_in
│ │ └── strings.po
│ ├── resource.language.hr_hr
│ │ └── strings.po
│ ├── resource.language.hu_hu
│ │ └── strings.po
│ ├── resource.language.hy_am
│ │ └── strings.po
│ ├── resource.language.id_id
│ │ └── strings.po
│ ├── resource.language.is_is
│ │ └── strings.po
│ ├── resource.language.it_it
│ │ └── strings.po
│ ├── resource.language.ja_jp
│ │ └── strings.po
│ ├── resource.language.kn_in
│ │ └── strings.po
│ ├── resource.language.ko_kr
│ │ └── strings.po
│ ├── resource.language.lt_lt
│ │ └── strings.po
│ ├── resource.language.lv_lv
│ │ └── strings.po
│ ├── resource.language.mi
│ │ └── strings.po
│ ├── resource.language.mk_mk
│ │ └── strings.po
│ ├── resource.language.ml_in
│ │ └── strings.po
│ ├── resource.language.mn_mn
│ │ └── strings.po
│ ├── resource.language.ms_my
│ │ └── strings.po
│ ├── resource.language.mt_mt
│ │ └── strings.po
│ ├── resource.language.my_mm
│ │ └── strings.po
│ ├── resource.language.nb_no
│ │ └── strings.po
│ ├── resource.language.nl_nl
│ │ └── strings.po
│ ├── resource.language.os_os
│ │ └── strings.po
│ ├── resource.language.pl_pl
│ │ └── strings.po
│ ├── resource.language.pt_br
│ │ └── strings.po
│ ├── resource.language.pt_pt
│ │ └── strings.po
│ ├── resource.language.ro_ro
│ │ └── strings.po
│ ├── resource.language.ru_ru
│ │ └── strings.po
│ ├── resource.language.si_lk
│ │ └── strings.po
│ ├── resource.language.sk_sk
│ │ └── strings.po
│ ├── resource.language.sl_si
│ │ └── strings.po
│ ├── resource.language.sq_al
│ │ └── strings.po
│ ├── resource.language.sr_rs
│ │ └── strings.po
│ ├── resource.language.sr_rs@latin
│ │ └── strings.po
│ ├── resource.language.sv_se
│ │ └── strings.po
│ ├── resource.language.szl
│ │ └── strings.po
│ ├── resource.language.ta_in
│ │ └── strings.po
│ ├── resource.language.tg_tj
│ │ └── strings.po
│ ├── resource.language.th_th
│ │ └── strings.po
│ ├── resource.language.tr_tr
│ │ └── strings.po
│ ├── resource.language.uk_ua
│ │ └── strings.po
│ ├── resource.language.uz_uz
│ │ └── strings.po
│ ├── resource.language.vi_vn
│ │ └── strings.po
│ ├── resource.language.zh_cn
│ │ └── strings.po
│ └── resource.language.zh_tw
│ │ └── strings.po
├── lib
│ ├── config.py
│ ├── dbus_bluez.py
│ ├── dbus_connman.py
│ ├── dbus_obex.py
│ ├── dbus_utils.py
│ ├── debug_utils.py
│ ├── defaults.py
│ ├── hostname.py
│ ├── log.py
│ ├── modules.py
│ ├── modules
│ │ ├── about.py
│ │ ├── bluetooth.py
│ │ ├── connman.py
│ │ ├── services.py
│ │ ├── system.py
│ │ └── updates.py
│ ├── oe.py
│ ├── oeWindows.py
│ ├── os_tools.py
│ ├── regdomain.py
│ ├── timezone.py
│ └── ui_tools.py
└── skins
│ └── Default
│ ├── 1080i
│ ├── service-LibreELEC-Settings-getPasskey.xml
│ ├── service-LibreELEC-Settings-mainWindow.xml
│ └── service-LibreELEC-Settings-wizard.xml
│ └── media
│ ├── arrowdown.png
│ ├── bg.jpg
│ ├── black-back.png
│ ├── bt-audio-card.png
│ ├── bt-camera-photo.png
│ ├── bt-camera-video.png
│ ├── bt-computer.png
│ ├── bt-input-gaming.png
│ ├── bt-input-keyboard.png
│ ├── bt-input-mouse.png
│ ├── bt-input-tablet.png
│ ├── bt-modem.png
│ ├── bt-phone.png
│ ├── bt-printer.png
│ ├── bt.png
│ ├── button-fo.png
│ ├── button-nofo.png
│ ├── connected.png
│ ├── dialog-bg-solid.png
│ ├── dialog-bg.png
│ ├── do.png
│ ├── eth.png
│ ├── fanart.png
│ ├── favorite.png
│ ├── floor.png
│ ├── focus.png
│ ├── icon.png
│ ├── icon_button_back.png
│ ├── key.png
│ ├── logo.png
│ ├── radio-button-off.png
│ ├── radio-button-on.png
│ ├── separator-grey.png
│ ├── separator.png
│ ├── unlock.png
│ ├── vpn.png
│ ├── wizard.png
│ └── wlan.png
├── service.py
└── syspath.py
/.github/workflows/sync-addon-metadata-translations.yml:
--------------------------------------------------------------------------------
1 | name: Sync addon metadata translations
2 |
3 | on:
4 | push:
5 | branches: [ master, main ]
6 | paths:
7 | - '**addon.xml'
8 | - '**resource.language.**strings.po'
9 |
10 | jobs:
11 | default:
12 | if: github.repository == 'LibreELEC/service.libreelec.settings'
13 | runs-on: ubuntu-latest
14 |
15 | steps:
16 |
17 | - name: Checkout repository
18 | uses: actions/checkout@v2
19 | with:
20 | path: project
21 |
22 | - name: Set up Python
23 | uses: actions/setup-python@v2
24 | with:
25 | python-version: '3.9'
26 |
27 | - name: Install dependencies
28 | run: |
29 | python -m pip install --upgrade pip
30 | python -m pip install git+https://github.com/xbmc/sync_addon_metadata_translations.git
31 |
32 | - name: Run sync-addon-metadata-translations
33 | run: |
34 | sync-addon-metadata-translations
35 | working-directory: ./project
36 |
37 | - name: Create PR for sync-addon-metadata-translations changes
38 | uses: peter-evans/create-pull-request@v3.10.0
39 | with:
40 | commit-message: Sync of addon metadata translations
41 | title: Sync of addon metadata translations
42 | body: Sync of addon metadata translations triggered by ${{ github.sha }}
43 | branch: amt-sync
44 | delete-branch: true
45 | path: ./project
--------------------------------------------------------------------------------
/COPYING:
--------------------------------------------------------------------------------
1 | This program is provided under a mix of the following licenses:
2 |
3 | SPDX-License-Identifier: GPL-2.0-only
4 | SPDX-License-Identifier: GPL-2.0-or-later
5 |
6 | Being under the terms of the GNU General Public License version 2 only, or
7 | the GNU General Public License version 2 or later. Licensing varies by
8 | individual file. Check each file for specifics.
9 |
10 | Copies of the licenses are available in:
11 |
12 | LICENSES/GPL-2.0-only.txt
13 | LICENSES/GPL-2.0-or-later.txt
14 |
15 | Unless expressly stated otherwise, all code submitted to the project is
16 | licensed under GPL-2.0-only, and copyright is donated to the project.
17 |
--------------------------------------------------------------------------------
/LICENSES/GPL-2.0-only.txt:
--------------------------------------------------------------------------------
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 |
7 | Everyone is permitted to copy and distribute verbatim copies of this license
8 | document, but changing it is not allowed.
9 |
10 | Preamble
11 |
12 | The licenses for most software are designed to take away your freedom to share
13 | and change it. By contrast, the GNU General Public License is intended to
14 | guarantee your freedom to share and change free software--to make sure the
15 | software is free for all its users. This General Public License applies to
16 | most of the Free Software Foundation's software and to any other program whose
17 | authors commit to using it. (Some other Free Software Foundation software
18 | is covered by the GNU Lesser General Public License instead.) You can apply
19 | it to your programs, too.
20 |
21 | When we speak of free software, we are referring to freedom, not price. Our
22 | General Public Licenses are designed to make sure that you have the freedom
23 | to distribute copies of free software (and charge for this service if you
24 | wish), that you receive source code or can get it if you want it, that you
25 | can change the software or use pieces of it in new free programs; and that
26 | you know you can do these things.
27 |
28 | To protect your rights, we need to make restrictions that forbid anyone to
29 | deny you these rights or to ask you to surrender the rights. These restrictions
30 | translate to certain responsibilities for you if you distribute copies of
31 | the software, or if you modify it.
32 |
33 | For example, if you distribute copies of such a program, whether gratis or
34 | for a fee, you must give the recipients all the rights that you have. You
35 | must make sure that they, too, receive or can get the source code. And you
36 | must show them these terms so they know their rights.
37 |
38 | We protect your rights with two steps: (1) copyright the software, and (2)
39 | offer you this license which gives you legal permission to copy, distribute
40 | and/or modify the software.
41 |
42 | Also, for each author's protection and ours, we want to make certain that
43 | everyone understands that there is no warranty for this free software. If
44 | the software is modified by someone else and passed on, we want its recipients
45 | to know that what they have is not the original, so that any problems introduced
46 | by others will not reflect on the original authors' reputations.
47 |
48 | Finally, any free program is threatened constantly by software patents. We
49 | wish to avoid the danger that redistributors of a free program will individually
50 | obtain patent licenses, in effect making the program proprietary. To prevent
51 | this, we have made it clear that any patent must be licensed for everyone's
52 | free use or not licensed at all.
53 |
54 | The precise terms and conditions for copying, distribution and modification
55 | follow.
56 |
57 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
58 |
59 | 0. This License applies to any program or other work which contains a notice
60 | placed by the copyright holder saying it may be distributed under the terms
61 | of this General Public License. The "Program", below, refers to any such program
62 | or work, and a "work based on the Program" means either the Program or any
63 | derivative work under copyright law: that is to say, a work containing the
64 | Program or a portion of it, either verbatim or with modifications and/or translated
65 | into another language. (Hereinafter, translation is included without limitation
66 | in the term "modification".) Each licensee is addressed as "you".
67 |
68 | Activities other than copying, distribution and modification are not covered
69 | by this License; they are outside its scope. The act of running the Program
70 | is not restricted, and the output from the Program is covered only if its
71 | contents constitute a work based on the Program (independent of having been
72 | made by running the Program). Whether that is true depends on what the Program
73 | does.
74 |
75 | 1. You may copy and distribute verbatim copies of the Program's source code
76 | as you receive it, in any medium, provided that you conspicuously and appropriately
77 | publish on each copy an appropriate copyright notice and disclaimer of warranty;
78 | keep intact all the notices that refer to this License and to the absence
79 | of any warranty; and give any other recipients of the Program a copy of this
80 | License along with the Program.
81 |
82 | You may charge a fee for the physical act of transferring a copy, and you
83 | may at your option offer warranty protection in exchange for a fee.
84 |
85 | 2. You may modify your copy or copies of the Program or any portion of it,
86 | thus forming a work based on the Program, and copy and distribute such modifications
87 | or work under the terms of Section 1 above, provided that you also meet all
88 | of these conditions:
89 |
90 | a) You must cause the modified files to carry prominent notices stating that
91 | you changed the files and the date of any change.
92 |
93 | b) You must cause any work that you distribute or publish, that in whole or
94 | in part contains or is derived from the Program or any part thereof, to be
95 | licensed as a whole at no charge to all third parties under the terms of this
96 | License.
97 |
98 | c) If the modified program normally reads commands interactively when run,
99 | you must cause it, when started running for such interactive use in the most
100 | ordinary way, to print or display an announcement including an appropriate
101 | copyright notice and a notice that there is no warranty (or else, saying that
102 | you provide a warranty) and that users may redistribute the program under
103 | these conditions, and telling the user how to view a copy of this License.
104 | (Exception: if the Program itself is interactive but does not normally print
105 | such an announcement, your work based on the Program is not required to print
106 | an announcement.)
107 |
108 | These requirements apply to the modified work as a whole. If identifiable
109 | sections of that work are not derived from the Program, and can be reasonably
110 | considered independent and separate works in themselves, then this License,
111 | and its terms, do not apply to those sections when you distribute them as
112 | separate works. But when you distribute the same sections as part of a whole
113 | which is a work based on the Program, the distribution of the whole must be
114 | on the terms of this License, whose permissions for other licensees extend
115 | to the entire whole, and thus to each and every part regardless of who wrote
116 | it.
117 |
118 | Thus, it is not the intent of this section to claim rights or contest your
119 | rights to work written entirely by you; rather, the intent is to exercise
120 | the right to control the distribution of derivative or collective works based
121 | on the Program.
122 |
123 | In addition, mere aggregation of another work not based on the Program with
124 | the Program (or with a work based on the Program) on a volume of a storage
125 | or distribution medium does not bring the other work under the scope of this
126 | License.
127 |
128 | 3. You may copy and distribute the Program (or a work based on it, under Section
129 | 2) in object code or executable form under the terms of Sections 1 and 2 above
130 | provided that you also do one of the following:
131 |
132 | a) Accompany it with the complete corresponding machine-readable source code,
133 | which must be distributed under the terms of Sections 1 and 2 above on a medium
134 | customarily used for software interchange; or,
135 |
136 | b) Accompany it with a written offer, valid for at least three years, to give
137 | any third party, for a charge no more than your cost of physically performing
138 | source distribution, a complete machine-readable copy of the corresponding
139 | source code, to be distributed under the terms of Sections 1 and 2 above on
140 | a medium customarily used for software interchange; or,
141 |
142 | c) Accompany it with the information you received as to the offer to distribute
143 | corresponding source code. (This alternative is allowed only for noncommercial
144 | distribution and only if you received the program in object code or executable
145 | form with such an offer, in accord with Subsection b above.)
146 |
147 | The source code for a work means the preferred form of the work for making
148 | modifications to it. For an executable work, complete source code means all
149 | the source code for all modules it contains, plus any associated interface
150 | definition files, plus the scripts used to control compilation and installation
151 | of the executable. However, as a special exception, the source code distributed
152 | need not include anything that is normally distributed (in either source or
153 | binary form) with the major components (compiler, kernel, and so on) of the
154 | operating system on which the executable runs, unless that component itself
155 | accompanies the executable.
156 |
157 | If distribution of executable or object code is made by offering access to
158 | copy from a designated place, then offering equivalent access to copy the
159 | source code from the same place counts as distribution of the source code,
160 | even though third parties are not compelled to copy the source along with
161 | the object code.
162 |
163 | 4. You may not copy, modify, sublicense, or distribute the Program except
164 | as expressly provided under this License. Any attempt otherwise to copy, modify,
165 | sublicense or distribute the Program is void, and will automatically terminate
166 | your rights under this License. However, parties who have received copies,
167 | or rights, from you under this License will not have their licenses terminated
168 | so long as such parties remain in full compliance.
169 |
170 | 5. You are not required to accept this License, since you have not signed
171 | it. However, nothing else grants you permission to modify or distribute the
172 | Program or its derivative works. These actions are prohibited by law if you
173 | do not accept this License. Therefore, by modifying or distributing the Program
174 | (or any work based on the Program), you indicate your acceptance of this License
175 | to do so, and all its terms and conditions for copying, distributing or modifying
176 | the Program or works based on it.
177 |
178 | 6. Each time you redistribute the Program (or any work based on the Program),
179 | the recipient automatically receives a license from the original licensor
180 | to copy, distribute or modify the Program subject to these terms and conditions.
181 | You may not impose any further restrictions on the recipients' exercise of
182 | the rights granted herein. You are not responsible for enforcing compliance
183 | by third parties to this License.
184 |
185 | 7. If, as a consequence of a court judgment or allegation of patent infringement
186 | or for any other reason (not limited to patent issues), conditions are imposed
187 | on you (whether by court order, agreement or otherwise) that contradict the
188 | conditions of this License, they do not excuse you from the conditions of
189 | this License. If you cannot distribute so as to satisfy simultaneously your
190 | obligations under this License and any other pertinent obligations, then as
191 | a consequence you may not distribute the Program at all. For example, if a
192 | patent license would not permit royalty-free redistribution of the Program
193 | by all those who receive copies directly or indirectly through you, then the
194 | only way you could satisfy both it and this License would be to refrain entirely
195 | from distribution of the Program.
196 |
197 | If any portion of this section is held invalid or unenforceable under any
198 | particular circumstance, the balance of the section is intended to apply and
199 | the section as a whole is intended to apply in other circumstances.
200 |
201 | It is not the purpose of this section to induce you to infringe any patents
202 | or other property right claims or to contest validity of any such claims;
203 | this section has the sole purpose of protecting the integrity of the free
204 | software distribution system, which is implemented by public license practices.
205 | Many people have made generous contributions to the wide range of software
206 | distributed through that system in reliance on consistent application of that
207 | system; it is up to the author/donor to decide if he or she is willing to
208 | distribute software through any other system and a licensee cannot impose
209 | that choice.
210 |
211 | This section is intended to make thoroughly clear what is believed to be a
212 | consequence of the rest of this License.
213 |
214 | 8. If the distribution and/or use of the Program is restricted in certain
215 | countries either by patents or by copyrighted interfaces, the original copyright
216 | holder who places the Program under this License may add an explicit geographical
217 | distribution limitation excluding those countries, so that distribution is
218 | permitted only in or among countries not thus excluded. In such case, this
219 | License incorporates the limitation as if written in the body of this License.
220 |
221 | 9. The Free Software Foundation may publish revised and/or new versions of
222 | the General Public License from time to time. Such new versions will be similar
223 | in spirit to the present version, but may differ in detail to address new
224 | problems or concerns.
225 |
226 | Each version is given a distinguishing version number. If the Program specifies
227 | a version number of this License which applies to it and "any later version",
228 | you have the option of following the terms and conditions either of that version
229 | or of any later version published by the Free Software Foundation. If the
230 | Program does not specify a version number of this License, you may choose
231 | any version ever published by the Free Software Foundation.
232 |
233 | 10. If you wish to incorporate parts of the Program into other free programs
234 | whose distribution conditions are different, write to the author to ask for
235 | permission. For software which is copyrighted by the Free Software Foundation,
236 | write to the Free Software Foundation; we sometimes make exceptions for this.
237 | Our decision will be guided by the two goals of preserving the free status
238 | of all derivatives of our free software and of promoting the sharing and reuse
239 | of software generally.
240 |
241 | NO WARRANTY
242 |
243 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR
244 | THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE
245 | STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM
246 | "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
247 | BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
248 | FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE
249 | OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME
250 | THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
251 |
252 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
253 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE
254 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
255 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE
256 | OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA
257 | OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES
258 | OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH
259 | HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
260 |
261 | END OF TERMS AND CONDITIONS
262 |
263 | How to Apply These Terms to Your New Programs
264 |
265 | If you develop a new program, and you want it to be of the greatest possible
266 | use to the public, the best way to achieve this is to make it free software
267 | which everyone can redistribute and change under these terms.
268 |
269 | To do so, attach the following notices to the program. It is safest to attach
270 | them to the start of each source file to most effectively convey the exclusion
271 | of warranty; and each file should have at least the "copyright" line and a
272 | pointer to where the full notice is found.
273 |
274 | one line to give the program's name and an idea of what it does. Copyright
275 | (C) yyyy name of author
276 |
277 | This program is free software; you can redistribute it and/or modify it under
278 | the terms of the GNU General Public License as published by the Free Software
279 | Foundation; either version 2 of the License, or (at your option) any later
280 | version.
281 |
282 | This program is distributed in the hope that it will be useful, but WITHOUT
283 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
284 | FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
285 |
286 | You should have received a copy of the GNU General Public License along with
287 | this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
288 | Street, Fifth Floor, Boston, MA 02110-1301, USA. Also add information on how
289 | to contact you by electronic and paper mail.
290 |
291 | If the program is interactive, make it output a short notice like this when
292 | it starts in an interactive mode:
293 |
294 | Gnomovision version 69, Copyright (C) year name of author Gnomovision comes
295 | with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software,
296 | and you are welcome to redistribute it under certain conditions; type `show
297 | c' for details.
298 |
299 | The hypothetical commands `show w' and `show c' should show the appropriate
300 | parts of the General Public License. Of course, the commands you use may be
301 | called something other than `show w' and `show c'; they could even be mouse-clicks
302 | or menu items--whatever suits your program.
303 |
304 | You should also get your employer (if you work as a programmer) or your school,
305 | if any, to sign a "copyright disclaimer" for the program, if necessary. Here
306 | is a sample; alter the names:
307 |
308 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision'
309 | (which makes passes at compilers) written by James Hacker.
310 |
311 | signature of Ty Coon, 1 April 1989 Ty Coon, President of Vice
312 |
--------------------------------------------------------------------------------
/LICENSES/GPL-2.0-or-later.txt:
--------------------------------------------------------------------------------
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 |
7 | Everyone is permitted to copy and distribute verbatim copies of this license
8 | document, but changing it is not allowed.
9 |
10 | Preamble
11 |
12 | The licenses for most software are designed to take away your freedom to share
13 | and change it. By contrast, the GNU General Public License is intended to
14 | guarantee your freedom to share and change free software--to make sure the
15 | software is free for all its users. This General Public License applies to
16 | most of the Free Software Foundation's software and to any other program whose
17 | authors commit to using it. (Some other Free Software Foundation software
18 | is covered by the GNU Lesser General Public License instead.) You can apply
19 | it to your programs, too.
20 |
21 | When we speak of free software, we are referring to freedom, not price. Our
22 | General Public Licenses are designed to make sure that you have the freedom
23 | to distribute copies of free software (and charge for this service if you
24 | wish), that you receive source code or can get it if you want it, that you
25 | can change the software or use pieces of it in new free programs; and that
26 | you know you can do these things.
27 |
28 | To protect your rights, we need to make restrictions that forbid anyone to
29 | deny you these rights or to ask you to surrender the rights. These restrictions
30 | translate to certain responsibilities for you if you distribute copies of
31 | the software, or if you modify it.
32 |
33 | For example, if you distribute copies of such a program, whether gratis or
34 | for a fee, you must give the recipients all the rights that you have. You
35 | must make sure that they, too, receive or can get the source code. And you
36 | must show them these terms so they know their rights.
37 |
38 | We protect your rights with two steps: (1) copyright the software, and (2)
39 | offer you this license which gives you legal permission to copy, distribute
40 | and/or modify the software.
41 |
42 | Also, for each author's protection and ours, we want to make certain that
43 | everyone understands that there is no warranty for this free software. If
44 | the software is modified by someone else and passed on, we want its recipients
45 | to know that what they have is not the original, so that any problems introduced
46 | by others will not reflect on the original authors' reputations.
47 |
48 | Finally, any free program is threatened constantly by software patents. We
49 | wish to avoid the danger that redistributors of a free program will individually
50 | obtain patent licenses, in effect making the program proprietary. To prevent
51 | this, we have made it clear that any patent must be licensed for everyone's
52 | free use or not licensed at all.
53 |
54 | The precise terms and conditions for copying, distribution and modification
55 | follow.
56 |
57 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
58 |
59 | 0. This License applies to any program or other work which contains a notice
60 | placed by the copyright holder saying it may be distributed under the terms
61 | of this General Public License. The "Program", below, refers to any such program
62 | or work, and a "work based on the Program" means either the Program or any
63 | derivative work under copyright law: that is to say, a work containing the
64 | Program or a portion of it, either verbatim or with modifications and/or translated
65 | into another language. (Hereinafter, translation is included without limitation
66 | in the term "modification".) Each licensee is addressed as "you".
67 |
68 | Activities other than copying, distribution and modification are not covered
69 | by this License; they are outside its scope. The act of running the Program
70 | is not restricted, and the output from the Program is covered only if its
71 | contents constitute a work based on the Program (independent of having been
72 | made by running the Program). Whether that is true depends on what the Program
73 | does.
74 |
75 | 1. You may copy and distribute verbatim copies of the Program's source code
76 | as you receive it, in any medium, provided that you conspicuously and appropriately
77 | publish on each copy an appropriate copyright notice and disclaimer of warranty;
78 | keep intact all the notices that refer to this License and to the absence
79 | of any warranty; and give any other recipients of the Program a copy of this
80 | License along with the Program.
81 |
82 | You may charge a fee for the physical act of transferring a copy, and you
83 | may at your option offer warranty protection in exchange for a fee.
84 |
85 | 2. You may modify your copy or copies of the Program or any portion of it,
86 | thus forming a work based on the Program, and copy and distribute such modifications
87 | or work under the terms of Section 1 above, provided that you also meet all
88 | of these conditions:
89 |
90 | a) You must cause the modified files to carry prominent notices stating that
91 | you changed the files and the date of any change.
92 |
93 | b) You must cause any work that you distribute or publish, that in whole or
94 | in part contains or is derived from the Program or any part thereof, to be
95 | licensed as a whole at no charge to all third parties under the terms of this
96 | License.
97 |
98 | c) If the modified program normally reads commands interactively when run,
99 | you must cause it, when started running for such interactive use in the most
100 | ordinary way, to print or display an announcement including an appropriate
101 | copyright notice and a notice that there is no warranty (or else, saying that
102 | you provide a warranty) and that users may redistribute the program under
103 | these conditions, and telling the user how to view a copy of this License.
104 | (Exception: if the Program itself is interactive but does not normally print
105 | such an announcement, your work based on the Program is not required to print
106 | an announcement.)
107 |
108 | These requirements apply to the modified work as a whole. If identifiable
109 | sections of that work are not derived from the Program, and can be reasonably
110 | considered independent and separate works in themselves, then this License,
111 | and its terms, do not apply to those sections when you distribute them as
112 | separate works. But when you distribute the same sections as part of a whole
113 | which is a work based on the Program, the distribution of the whole must be
114 | on the terms of this License, whose permissions for other licensees extend
115 | to the entire whole, and thus to each and every part regardless of who wrote
116 | it.
117 |
118 | Thus, it is not the intent of this section to claim rights or contest your
119 | rights to work written entirely by you; rather, the intent is to exercise
120 | the right to control the distribution of derivative or collective works based
121 | on the Program.
122 |
123 | In addition, mere aggregation of another work not based on the Program with
124 | the Program (or with a work based on the Program) on a volume of a storage
125 | or distribution medium does not bring the other work under the scope of this
126 | License.
127 |
128 | 3. You may copy and distribute the Program (or a work based on it, under Section
129 | 2) in object code or executable form under the terms of Sections 1 and 2 above
130 | provided that you also do one of the following:
131 |
132 | a) Accompany it with the complete corresponding machine-readable source code,
133 | which must be distributed under the terms of Sections 1 and 2 above on a medium
134 | customarily used for software interchange; or,
135 |
136 | b) Accompany it with a written offer, valid for at least three years, to give
137 | any third party, for a charge no more than your cost of physically performing
138 | source distribution, a complete machine-readable copy of the corresponding
139 | source code, to be distributed under the terms of Sections 1 and 2 above on
140 | a medium customarily used for software interchange; or,
141 |
142 | c) Accompany it with the information you received as to the offer to distribute
143 | corresponding source code. (This alternative is allowed only for noncommercial
144 | distribution and only if you received the program in object code or executable
145 | form with such an offer, in accord with Subsection b above.)
146 |
147 | The source code for a work means the preferred form of the work for making
148 | modifications to it. For an executable work, complete source code means all
149 | the source code for all modules it contains, plus any associated interface
150 | definition files, plus the scripts used to control compilation and installation
151 | of the executable. However, as a special exception, the source code distributed
152 | need not include anything that is normally distributed (in either source or
153 | binary form) with the major components (compiler, kernel, and so on) of the
154 | operating system on which the executable runs, unless that component itself
155 | accompanies the executable.
156 |
157 | If distribution of executable or object code is made by offering access to
158 | copy from a designated place, then offering equivalent access to copy the
159 | source code from the same place counts as distribution of the source code,
160 | even though third parties are not compelled to copy the source along with
161 | the object code.
162 |
163 | 4. You may not copy, modify, sublicense, or distribute the Program except
164 | as expressly provided under this License. Any attempt otherwise to copy, modify,
165 | sublicense or distribute the Program is void, and will automatically terminate
166 | your rights under this License. However, parties who have received copies,
167 | or rights, from you under this License will not have their licenses terminated
168 | so long as such parties remain in full compliance.
169 |
170 | 5. You are not required to accept this License, since you have not signed
171 | it. However, nothing else grants you permission to modify or distribute the
172 | Program or its derivative works. These actions are prohibited by law if you
173 | do not accept this License. Therefore, by modifying or distributing the Program
174 | (or any work based on the Program), you indicate your acceptance of this License
175 | to do so, and all its terms and conditions for copying, distributing or modifying
176 | the Program or works based on it.
177 |
178 | 6. Each time you redistribute the Program (or any work based on the Program),
179 | the recipient automatically receives a license from the original licensor
180 | to copy, distribute or modify the Program subject to these terms and conditions.
181 | You may not impose any further restrictions on the recipients' exercise of
182 | the rights granted herein. You are not responsible for enforcing compliance
183 | by third parties to this License.
184 |
185 | 7. If, as a consequence of a court judgment or allegation of patent infringement
186 | or for any other reason (not limited to patent issues), conditions are imposed
187 | on you (whether by court order, agreement or otherwise) that contradict the
188 | conditions of this License, they do not excuse you from the conditions of
189 | this License. If you cannot distribute so as to satisfy simultaneously your
190 | obligations under this License and any other pertinent obligations, then as
191 | a consequence you may not distribute the Program at all. For example, if a
192 | patent license would not permit royalty-free redistribution of the Program
193 | by all those who receive copies directly or indirectly through you, then the
194 | only way you could satisfy both it and this License would be to refrain entirely
195 | from distribution of the Program.
196 |
197 | If any portion of this section is held invalid or unenforceable under any
198 | particular circumstance, the balance of the section is intended to apply and
199 | the section as a whole is intended to apply in other circumstances.
200 |
201 | It is not the purpose of this section to induce you to infringe any patents
202 | or other property right claims or to contest validity of any such claims;
203 | this section has the sole purpose of protecting the integrity of the free
204 | software distribution system, which is implemented by public license practices.
205 | Many people have made generous contributions to the wide range of software
206 | distributed through that system in reliance on consistent application of that
207 | system; it is up to the author/donor to decide if he or she is willing to
208 | distribute software through any other system and a licensee cannot impose
209 | that choice.
210 |
211 | This section is intended to make thoroughly clear what is believed to be a
212 | consequence of the rest of this License.
213 |
214 | 8. If the distribution and/or use of the Program is restricted in certain
215 | countries either by patents or by copyrighted interfaces, the original copyright
216 | holder who places the Program under this License may add an explicit geographical
217 | distribution limitation excluding those countries, so that distribution is
218 | permitted only in or among countries not thus excluded. In such case, this
219 | License incorporates the limitation as if written in the body of this License.
220 |
221 | 9. The Free Software Foundation may publish revised and/or new versions of
222 | the General Public License from time to time. Such new versions will be similar
223 | in spirit to the present version, but may differ in detail to address new
224 | problems or concerns.
225 |
226 | Each version is given a distinguishing version number. If the Program specifies
227 | a version number of this License which applies to it and "any later version",
228 | you have the option of following the terms and conditions either of that version
229 | or of any later version published by the Free Software Foundation. If the
230 | Program does not specify a version number of this License, you may choose
231 | any version ever published by the Free Software Foundation.
232 |
233 | 10. If you wish to incorporate parts of the Program into other free programs
234 | whose distribution conditions are different, write to the author to ask for
235 | permission. For software which is copyrighted by the Free Software Foundation,
236 | write to the Free Software Foundation; we sometimes make exceptions for this.
237 | Our decision will be guided by the two goals of preserving the free status
238 | of all derivatives of our free software and of promoting the sharing and reuse
239 | of software generally.
240 |
241 | NO WARRANTY
242 |
243 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR
244 | THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE
245 | STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM
246 | "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
247 | BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
248 | FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE
249 | OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME
250 | THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
251 |
252 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
253 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE
254 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
255 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE
256 | OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA
257 | OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES
258 | OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH
259 | HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
260 |
261 | END OF TERMS AND CONDITIONS
262 |
263 | How to Apply These Terms to Your New Programs
264 |
265 | If you develop a new program, and you want it to be of the greatest possible
266 | use to the public, the best way to achieve this is to make it free software
267 | which everyone can redistribute and change under these terms.
268 |
269 | To do so, attach the following notices to the program. It is safest to attach
270 | them to the start of each source file to most effectively convey the exclusion
271 | of warranty; and each file should have at least the "copyright" line and a
272 | pointer to where the full notice is found.
273 |
274 | one line to give the program's name and an idea of what it does. Copyright
275 | (C) yyyy name of author
276 |
277 | This program is free software; you can redistribute it and/or modify it under
278 | the terms of the GNU General Public License as published by the Free Software
279 | Foundation; either version 2 of the License, or (at your option) any later
280 | version.
281 |
282 | This program is distributed in the hope that it will be useful, but WITHOUT
283 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
284 | FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
285 |
286 | You should have received a copy of the GNU General Public License along with
287 | this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
288 | Street, Fifth Floor, Boston, MA 02110-1301, USA. Also add information on how
289 | to contact you by electronic and paper mail.
290 |
291 | If the program is interactive, make it output a short notice like this when
292 | it starts in an interactive mode:
293 |
294 | Gnomovision version 69, Copyright (C) year name of author Gnomovision comes
295 | with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software,
296 | and you are welcome to redistribute it under certain conditions; type `show
297 | c' for details.
298 |
299 | The hypothetical commands `show w' and `show c' should show the appropriate
300 | parts of the General Public License. Of course, the commands you use may be
301 | called something other than `show w' and `show c'; they could even be mouse-clicks
302 | or menu items--whatever suits your program.
303 |
304 | You should also get your employer (if you work as a programmer) or your school,
305 | if any, to sign a "copyright disclaimer" for the program, if necessary. Here
306 | is a sample; alter the names:
307 |
308 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision'
309 | (which makes passes at compilers) written by James Hacker.
310 |
311 | signature of Ty Coon, 1 April 1989 Ty Coon, President of Vice
312 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: GPL-2.0-or-later
2 | # Copyright (C) 2009-2013 Stephan Raue (stephan@openelec.tv)
3 | # Copyright (C) 2013 Lutz Fiebach (lufie@openelec.tv)
4 | # Copyright (C) 2020-present Team LibreELEC (https://libreelec.tv)
5 |
6 | ADDON_NAME := service.libreelec.settings
7 | ADDON_VERSION := 0.0.0
8 | DISTRONAME := LibreELEC
9 | ROOT_PASSWORD := libreelec
10 |
11 | SHELL := /bin/bash
12 | BUILDDIR := build
13 | DATADIR := /usr/share/kodi
14 | ADDONDIR := $(DATADIR)/addons
15 |
16 | ################################################################################
17 |
18 | all: $(BUILDDIR)/$(ADDON_NAME)
19 |
20 | addon: $(BUILDDIR)/$(ADDON_NAME)-$(ADDON_VERSION).zip
21 |
22 | install: $(BUILDDIR)/$(ADDON_NAME)
23 | mkdir -p $(DESTDIR)$(ADDONDIR)
24 | cp -R $(BUILDDIR)/$(ADDON_NAME) $(DESTDIR)$(ADDONDIR)
25 |
26 | clean:
27 | rm -rf $(BUILDDIR)
28 |
29 | uninstall:
30 | rm -rf $(DESTDIR)$(ADDONDIR)/$(ADDON_NAME)
31 |
32 | $(BUILDDIR)/$(ADDON_NAME):
33 | mkdir -p $(BUILDDIR)/$(ADDON_NAME)
34 | cp -R resources $(BUILDDIR)/$(ADDON_NAME)
35 | cp COPYING $(BUILDDIR)/$(ADDON_NAME)
36 | cp addon.xml $(BUILDDIR)/$(ADDON_NAME)
37 | cp *.py $(BUILDDIR)/$(ADDON_NAME)
38 | sed -e "s,@ADDONNAME@,$(ADDON_NAME),g" \
39 | -e "s,@ADDONVERSION@,$(ADDON_VERSION),g" \
40 | -e "s,@DISTRONAME@,$(DISTRONAME),g" \
41 | -i $(BUILDDIR)/$(ADDON_NAME)/addon.xml
42 | sed -e "s,@DISTRONAME@,$(DISTRONAME),g" \
43 | -e "s,@ROOT_PASSWORD@,$(ROOT_PASSWORD),g" \
44 | -i $(BUILDDIR)/$(ADDON_NAME)/resources/language/*/*.po
45 |
46 | $(BUILDDIR)/$(ADDON_NAME)-$(ADDON_VERSION).zip: $(BUILDDIR)/$(ADDON_NAME)
47 | cd $(BUILDDIR); zip -r $(ADDON_NAME)-$(ADDON_VERSION).zip $(ADDON_NAME)
48 |
--------------------------------------------------------------------------------
/addon.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | all
13 |
14 | resources/skins/Default/media/icon.png
15 | resources/skins/Default/media/fanart.png
16 |
17 |
18 | https://github.com/LibreELEC/service.libreelec.settings/commits
19 |
20 | @DISTRONAME@ Konfigurasie
21 | Настройки на @DISTRONAME@
22 | Configuració de @DISTRONAME@
23 | @DISTRONAME@ Nastavení
24 | @DISTRONAME@ konfiguration
25 | @DISTRONAME@-Konfiguration
26 | Διαμόρφωση του @DISTRONAME@
27 | @DISTRONAME@ Configuration
28 | @DISTRONAME@ Configuration
29 | @DISTRONAME@ Configuration
30 | @DISTRONAME@ Configuration
31 | Configuración de @DISTRONAME@
32 | Configuración de @DISTRONAME@
33 | @DISTRONAME@ Seadistus
34 | @DISTRONAME@-asetukset
35 | Configuration @DISTRONAME@
36 | Configuration d'@DISTRONAME@
37 | Configuración do @DISTRONAME@
38 | הגדרות @DISTRONAME@
39 | @DISTRONAME@ podešavanje
40 | @DISTRONAME@ konfiguráció
41 | Impostazioni @DISTRONAME@
42 | @DISTRONAME@設定
43 | @DISTRONAME@ 설정
44 | @DISTRONAME@ konfigūravimas
45 | @DISTRONAME@ Configuratie
46 | @DISTRONAME@-konfigurasjon
47 | Konfiguracja @DISTRONAME@
48 | Configuração @DISTRONAME@
49 | Configuração do @DISTRONAME@
50 | Configurare @DISTRONAME@
51 | Конфигурация @DISTRONAME@
52 | Konfigurácia @DISTRONAME@
53 | Prilagoditev @DISTRONAME@
54 | @DISTRONAME@-konfiguration
55 | @DISTRONAME@ Yapılandırması
56 | @DISTRONAME@ Cấu hình
57 | @DISTRONAME@ 设置
58 | Ползвайте добавката за да управлявате операционната система, в основата на @DISTRONAME@. Чрез добавката можете да настроите всичко и така не се налага да се притеснявате какво работи под Kodi.[CR][CR]От добавката можете да променяте настройките на мрежовите връзки, клавиатурната подредба и да включвате/изключвате отдалечения достъп посредством Samba или SSH.
59 | Utilitza aquest complement per configurar el sistema operatiu subjacent del sistema @DISTRONAME@. Des d'aquí es pot gestionar tot el sistema, de manera que no s'ha de preocupar sobre el que s'executa sota el Kodi.[CR][CR]Des d'aquí es pot canviar la connectivitat de la xarxa, la distribució del teclat i idioma i activar / desactivar l'accés remot inclòs samba i SSH.
60 | Použijte toto rozšíření pro správu vašeho @DISTRONAME@ systému. Odtud můžete spravovat celý systém, takže nemusíte mít strach o to, co běží pod kapotou. [CR] [CR] Odtud můžete změnit připojení k síti, rozložení klávesnice, jazyk a povolit nebo zakázat vzdálený přístup, včetně Samby a SSH.
61 | Brug denne addon til at styre dit @DISTRONAME@ systems underliggende operativsystem. Herfra kan du styre hele systemet, så du ikke behøver at bekymre dig om, hvad der kører under motorhjelmen. [CR] [CR] Herfra kan du ændre din netværksforbindelse, dit tastaturlayout og sprog og aktivere/deaktivere fjernadgang, herunder Samba og SSH.
62 | Verwenden Sie dieses Addon, um das Betriebssystem, auf dem @DISTRONAME@ läuft, zu administrieren. Von hier aus können Sie das gesamte System verwalten ohne sich Gedanken machen zu müssen, was genau im System abläuft.[CR][CR]Hier haben Sie die Möglichkeit Netzwerkeinstellungen, Tastaturlayouts oder Systemdienste, wie SSH oder Samba, zu konfigurieren.
63 | Χρησιμοποιήστε αυτό το πρόσθετο για να διαχειριστείτε το λειτουργικό σύστημα @DISTRONAME@. Από εδώ μπορείτε να διαχειριστείτε ολόκληρο το σύστημα ούτως ώστε να μη χρειάζεται να ανησυχείτε σχετικά με το τι τρέχει στο υπόβαθρο.[CR][CR]Μπορείτε, επίσης, να αλλάξετε τη συνδεσιμότητα του δικτύου σας, τη διάταξη του πληκτρολογίου σας και τη γλώσσα, καθώς και να ενεργοποιήσετε/απενεργοποιήσετε την απομακρυσμένη πρόσβαση μέσω Samba και SSH.
64 | Use this addon to manage your @DISTRONAME@ system's underlying operating system. From here you can manage the entire system so you don't have to worry about what runs under the hood.[CR][CR]From here you can change your network connectivity, your keyboard layout and language and enable/disable remote access including Samba and SSH.
65 | Use this addon to manage your @DISTRONAME@ system's underlying operating system. From here you can manage the entire system so you don't have to worry about what runs under the hood.[CR][CR]From here you can change your network connectivity, your keyboard layout and language and enable/disable remote access including Samba and SSH.
66 | Use this addon to manage your @DISTRONAME@ system's underlying operating system. From here you can manage the entire system so you don't have to worry about what runs under the hood.[CR][CR]From here you can change your network connectivity, your keyboard layout and language and enable/disable remote access including Samba and SSH.
67 | Use this addon to manage your @DISTRONAME@ system's underlying operating system. From here you can manage the entire system so you don't have to worry about what runs under the hood.[CR][CR]From here you can change your network connectivity, your keyboard layout and language and enable/disable remote access including Samba and SSH.
68 | Usa este add-on para administrar el sistema @DISTRONAME@. Desde aquí podrás controlar el sistema al completo (Conexiones de red, teclado, acceso remoto, samba y SSH)
69 | Usá esta extensión para administrar el sistema operativo subyacente a tu sistema @DISTRONAME@. Desde acá podés administrar el sistema en su totalidad sin tener que preocuparte por lo que pasa debajo del capó.[CR][CR]Desde acá podés cambiar la conexión de red, la distribución del teclado y el lenguaje y habilitar/deshabilitar el acceso remoto, incluyendo Samba y SSH.
70 | Usa este complemento para configurar el sistema operativo de tu @DISTRONAME@. Desde aquí puedes administrar todo el sistema fácilmente.[CR][CR]Desde aquí puedes cambiar la configuración de red, distribución del teclado, lenguaje del sistema y configurar Samba y SSH para controlar el acceso remoto al sistema.
71 | See lisa on @DISTRONAME@ operatsioonisüsteemi häälestamiseks. Siit saad hallata kogu süsteemi, ilma et oleks vaja kaane alla piiluda.[CR][CR] Siit saab seada võrguühenduse parameetreid, klaviatuuripaigutust, keelt ning lubada/keelata kaugligipääsu, sealhulgas Samba ja SSH.
72 | Käytä tätä lisäosaa muokataksesi @DISTRONAME@in alla olevaa käyttöjärjestelmää. Täältä voit muokata koko järjestelmää välittämättä siitä, mitä konepellin alta löytyy.[CR][CR]Voit muokata verkkoasetuksia, näppäimistön tyyppiä, kieliasetuksia sekä yhteysasetuksia, mukaanlukien Samba ja SSH.
73 | Utiliser cette extension pour configurer le système d'exploitation @DISTRONAME@. Il est possible de gérer l'intégralité du système simplement sans se soucier des détails techniques.[CR][CR]Il est possible de modifier la connexion au réseau, la disposition du clavier ou la langue du système. Il est aussi possible d'activer les accès distants comme Samba ou SSH.
74 | Utilisez cet addiciel pour gérer le système d'exploitation sous-jacent de votre système @DISTRONAME@. D'ici vous pouvez gérer votre système au complet sans vous soucier de ce qui tourne sous la capot.[CR][CR]D'ici vous pouvez changer vos paramètres de connexion réseau, l'agencement et la langue de votre clavier et activer/désactiver l'accès distant incluant Samba et SSH.
75 | בעזרת הרחבה זו ניתן לנהל את מערכת ההפעלה של @DISTRONAME@. מכאן ניתן לנהל כל אחד ממאפייני המערכת כך שאין צורך לדאוג מה קורה מתחת לממשק המשתמש.[CR][CR]ניתן לשנות הגדרות רשת, מערך מקלדת ושפה וגם להפעיל/לנטרל שירותי גישה מרחוק כולל Samba ו-SSH.
76 | Koristite ovaj dodatak za upravljanje @DISTRONAME@ operativnim sustavom. Odavdje možete upravljati cijelim sustavom stoga se ne morate brinuti što je pokrenuto u pozadini.[CR][CR]Odavdje možete promijeniti mrežno povezivenje, vaš raspored tipkovnice i jezik, omogućiti/onemogućiti udaljeni pristup uključujući Sambu i SSH.
77 | Ez a kiegészítő vezérli az @DISTRONAME@ rendszer alatti operációs rendszer beállításait. Innen kezelheti a teljes rendszert, tehát nem szükséges aggódnia mi van a motorháztető alatt. [CR][CR] Innen állíthatóak be a hálózati kapcsolatok, billentyűzet kiosztás és nyelvezet valamint a távoli hozzáférések engedélyezése/letiltása beleértve a Samba-t és SSH-t is.
78 | Usa questo addon per gestire le impostazioni del sistema operativo di @DISTRONAME@. Da qui puoi gestire l'intero sistema senza necessità di una conoscenza avanzata del software sottostante.[CR][CR]Puoi modificare le connessioni di rete, il layout e la lingua della tastiera così come abilitare/disabilitare l'accesso remoto tramite Samba e SSH
79 | このアドオンで@DISTRONAME@システムのオペレーティング・システムを管理します。ここからシステム全体を管理できますので、バックグラウンドで何が動作しているかなどを気にしなくてかまいません。[CR][CR]ネットワーク接続、キーボードのレイアウトや言語、SambaとSSHを含むリモートアクセスの有効・無効などの設定を行います。
80 | Naudokite šį priedą operacines sistemos, kuris pagrįsta jūsų @DISTRONAME@ sistema, tvarkymui. Čia jūs galite valdyta visą sistemą, kad jums netektų rūpintis kas vyksta po gaubtu..[CR][CR]Čia galite pakeisti tinklo nustatymus, klaviatūros išdėstymą ir kalbą bei įjungti/išjungti nuotolinę prieigą, įskaitant Samba ir SSH.
81 | Gebruik deze addon om het onderliggende @DISTRONAME@ systeem in te stellen. Vanaf hier kunt u het gehele systeem aanpassen, zodat u zich geen zorgen hoeft te maken over wat er onderhuids gebeurt.[CR][CR]Vanaf hier kunt u de netwerkverbindingen aanpassen, uw toetsenbord indeling en -taal, alsook een externe verbinding inclusief Samba en SSH in- of uitschakelen.
82 | Bruk dette tillegget for å konfigurere @DISTRONAME@s underliggende operativsystem. Herfra kan du konfigurere hele systemet slik at du ikke trenger å bekymre deg om hva som skjer under panseret.[CR][CR]Du kan endre nettverksinnstillinger, tastatur, språk og aktivere eller deaktivere nettverkstilgang slik som Samba og SSH.
83 | Za pomocą tej wtyczki możesz zarządzać systemem @DISTRONAME@. Z tego miejsca masz kontrolę nad całym systemem.[CR][CR] Zarządzasz połączeniem sieciowym, układem klawiatury i językiem systemu oraz możesz włączyć lub wyłączyć dostęp zdalny, w tym Sambę i SSH.
84 | Utilize este addon para gerir o sistema operativo que está na base do @DISTRONAME@. Aqui pode gerir todo o sistema, para não ter de se preocupar com aquilo que se passa nos bastidores.[CR][CR] Daqui, pode alterar as suas ligações de rede, disposição do teclado e idiomas. Também pode activar/desactivar acesso remoto, incluindo Samba e SSH.
85 | Utilize este addon para gerenciar o sistema operacional do @DISTRONAME@. Aqui você pode gerenciar todo o sistema, para não ter de se preocupar com aquilo que se passa nos bastidores.[CR][CR] Daqui, você pode alterar as suas conexões de rede, configurações do teclado e idiomas. Também pode ativar/desativar acesso remoto, incluindo compartilhamento de rede do Windows e SSH.
86 | Данное дополнение предназначено для управления системными настройками @DISTRONAME@. С помощью удобного интерфейса Вы можете управлять настройками системы (включая низкоуровневые настройки ОС) через удобный интерфейс.[CR][CR]Здесь Вы также сможете изменить способ соединения с сетью, настроить раскладку клавиатуры, выбрать язык интерфейса, а также включить удаленный доступ по SSH и/или Samba.
87 | Tento doplnok slúži na správu operačného systému, na ktorom beží @DISTRONAME@. Odtiaľto je možné spravovať celý systém bez nutnosti znalostí o tom, čo beží pod kapotou.[CR][CR]Je tu možné meniť sieťové nastavenia, rozloženie a jazyk klávesnice alebo povoliť/zakázať vzdialený prístup prostredníctvom Samby a SSH.
88 | S tem dodatkom upravljate operacijski sistem, ki deluje pod pokrovom sistema @DISTRONAME@. Odtod lahko upravljate s celotnim sistemom, tako da je skrb o tem, kar teče pod pokrovom, odveč.[CR][CR]Odtod lahko spremenite svojo omrežno povezljivost, postavitev tipkovnice in jezik ter omogočite/onemogočite oddaljeni dostop, vključno s Sambo in SSH.
89 | Använd detta tillägg för att hantera ditt @DISTRONAME@-systems underliggande operativ. Härifrån kan du hantera hela systemet så du inte behöver oroa dig för vad som körs under skalet.[CR][CR]Härifrån kan du ändra din nätverksanslutning, tangentbordslayout och språk, samt aktivera/inaktivera fjärråtkomst inklusive Samba och SSH.
90 | Bu eklentiyi kullanarak @DISTRONAME@ sisteminizin temelindeki işletim sistemini yönetin. Buradan tüm sistemi yönetebilirsiniz ve bu yüzden sistemin altında neler olduğu hakkında endişelenmenize gerek yok.[CR][CR]Buradan ağ bağlantısı, klavye düzeni ve dilini değiştirip, Samba ve SSH gibi uzaktan erişimi etkinleştirip/devre dışı bırakabilirsiniz.
91 | Sử dụng addon này để quản lý hệ thống điều hành @DISTRONAME@ cơ bản của bạn.
Từ đây bạn có thể quản lý toàn bộ hệ thống, do đó bạn không cần phải lo lắng về những gì đang chạy . [CR][CR] Từ đây bạn có thể thay đổi kết nối mạng của bạn, bố trí bàn phím của bạn và ngôn ngữ và cho phép / vô hiệu hóa truy cập từ xa bao gồm Samba và SSH.
92 | 使用此插件管理你的 @DISTRONAME@ 系统的底层操作系统。它使你可以在无需深入了解的情况下管理整个系统。[CR][CR]在这里,你可以修改网络设置、键盘布局、语言以及启用/禁用 Samba 和 SSH 等远程访问功能。
93 |
94 |
95 |
--------------------------------------------------------------------------------
/default.py:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: GPL-2.0-or-later
2 | # Copyright (C) 2009-2013 Stephan Raue (stephan@openelec.tv)
3 | # Copyright (C) 2013 Lutz Fiebach (lufie@openelec.tv)
4 | # Copyright (C) 2019-present Team LibreELEC (https://libreelec.tv)
5 |
6 | import socket
7 |
8 | import xbmc
9 | import xbmcaddon
10 |
11 |
12 | __scriptid__ = 'service.libreelec.settings'
13 | __addon__ = xbmcaddon.Addon(id=__scriptid__)
14 | __cwd__ = __addon__.getAddonInfo('path')
15 | __media__ = f'{__cwd__}/resources/skins/Default/media'
16 | _ = __addon__.getLocalizedString
17 |
18 | try:
19 | sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
20 | sock.connect('/var/run/service.libreelec.settings.sock')
21 | sock.send(bytes('openConfigurationWindow', 'utf-8'))
22 | sock.close()
23 | except Exception as e:
24 | xbmc.executebuiltin(f'Notification("LibreELEC", "{_(32390)}", 5000, "{__media__}/icon.png"')
25 |
--------------------------------------------------------------------------------
/requirements-dev.txt:
--------------------------------------------------------------------------------
1 | Kodistubs
2 | DBussy
3 |
--------------------------------------------------------------------------------
/resources/__init__.py:
--------------------------------------------------------------------------------
1 | # Dummy file to make this directory a package.
2 |
--------------------------------------------------------------------------------
/resources/language/resource.language.en_gb/strings.po:
--------------------------------------------------------------------------------
1 | # Kodi Media Center language file
2 | # Addon Name: @DISTRONAME@ Configuration
3 | # Addon id: service.libreelec.settings
4 | # Addon Provider: LibreELEC
5 | msgid ""
6 | msgstr ""
7 | "MIME-Version: 1.0\n"
8 | "Content-Type: text/plain; charset=UTF-8\n"
9 | "Content-Transfer-Encoding: 8bit\n"
10 |
11 | msgctxt "#600"
12 | msgid "@DISTRONAME@ Settings"
13 | msgstr ""
14 |
15 | msgctxt "#601"
16 | msgid "Interface"
17 | msgstr ""
18 |
19 | msgctxt "#602"
20 | msgid "Address"
21 | msgstr ""
22 |
23 | msgctxt "#603"
24 | msgid "Type"
25 | msgstr ""
26 |
27 | msgctxt "#604"
28 | msgid "State"
29 | msgstr ""
30 |
31 | msgctxt "#605"
32 | msgid "Address"
33 | msgstr ""
34 |
35 | msgctxt "#606"
36 | msgid "Distribution: "
37 | msgstr ""
38 |
39 | msgctxt "#607"
40 | msgid "Version: "
41 | msgstr ""
42 |
43 | msgctxt "#608"
44 | msgid "Architecture: "
45 | msgstr ""
46 |
47 | msgctxt "#609"
48 | msgid "LibreELEC is created by a global team of Linux and Kodi enthusiasts who contribute time and effort to manage the project, write code, and provide support. We have fun making it. We hope you have fun using it!"
49 | msgstr ""
50 |
51 | msgctxt "#610"
52 | msgid "[B]Support[/B] is provided via our forum:[CR]https://forum.libreelec.tv[CR][CR][B]Documentation[/B] can be read in our wiki:[CR]https://libreelec.wiki[CR][CR][B]Code[/B] can be found on GitHub:[CR]https://github.com/LibreELEC[CR][CR][B]Donations[/B] towards project expenses are accepted via OpenCollective:[CR]https://opencollective.com/libreelec/donate"
53 | msgstr ""
54 |
55 | msgctxt "#700"
56 | msgid "Configure a hostname, keyboard type, perform a reset, update, or backups and restores"
57 | msgstr ""
58 |
59 | msgctxt "#701"
60 | msgid "Configure network startup options, NTP and VPNs"
61 | msgstr ""
62 |
63 | msgctxt "#702"
64 | msgid "Manage the Ethernet, Wireless and VPN connections available to the system"
65 | msgstr ""
66 |
67 | msgctxt "#703"
68 | msgid "Configure system services like Samba, SSH, Cron, Avahi and Syslog"
69 | msgstr ""
70 |
71 | msgctxt "#704"
72 | msgid "Configure and pair Bluetooth devices"
73 | msgstr ""
74 |
75 | msgctxt "#705"
76 | msgid "Useful information like version and architecture details, support and documentation links, and how to donate and support the project."
77 | msgstr ""
78 |
79 | msgctxt "#707"
80 | msgid "Configure updates"
81 | msgstr ""
82 |
83 | msgctxt "#709"
84 | msgid "Select the timezone for this device."
85 | msgstr ""
86 |
87 | msgctxt "#710"
88 | msgid "Configure the Hostname of your @DISTRONAME@ system. This will be used for the HTPC \\\\hostname in Windows and SMB server name in the Mac OS Finder"
89 | msgstr ""
90 |
91 | msgctxt "#711"
92 | msgid "Configure the 1st keyboard software layout"
93 | msgstr ""
94 |
95 | msgctxt "#712"
96 | msgid "Configure the 2nd keyboard software layout"
97 | msgstr ""
98 |
99 | msgctxt "#713"
100 | msgid "Configure the physical keyboard type"
101 | msgstr ""
102 |
103 | msgctxt "#714"
104 | msgid "@DISTRONAME@ can be configured for automatic or manual updates. Automatic updates are available on stable releases and stable release candidates. Automatic update self-disables on beta and development builds"
105 | msgstr ""
106 |
107 | msgctxt "#715"
108 | msgid "Set to ON and an on-screen notification will be displayed when a new update is available"
109 | msgstr ""
110 |
111 | msgctxt "#718"
112 | msgid "Send boot config files from /flash, kodi.log, kernel log and Samba configs to http://ix.io, and display the short URL"
113 | msgstr ""
114 |
115 | msgctxt "#719"
116 | msgid "Send boot config files from /flash, kodi_crash.log, kernel log and Samba configs to http://ix.io, and display the short URL"
117 | msgstr ""
118 |
119 | msgctxt "#720"
120 | msgid "Set to ON to enable the Bluetooth service"
121 | msgstr ""
122 |
123 | msgctxt "#722"
124 | msgid "Create a tar archive containing all @DISTRONAME@ and Kodi configuration settings, databases and thumbnail content. Backup files will be stored in /storage/backup/"
125 | msgstr ""
126 |
127 | msgctxt "#723"
128 | msgid "Restore a tar archive backup previously created using the backup option above"
129 | msgstr ""
130 |
131 | msgctxt "#724"
132 | msgid "[COLOR FF00FF00]SOFT RESET[/COLOR]\nPermanently reset @DISTRONAME@ configuration to defaults (resets also Kodi to default including your library. your media - music/videos/etc are not touched)"
133 | msgstr ""
134 |
135 | msgctxt "#725"
136 | msgid "[COLOR FFFF0000]HARD RESET[/COLOR]\nPermanently reset @DISTRONAME@ and Kodi configuration to defaults (everything in your storage partition will be deleted)"
137 | msgstr ""
138 |
139 | msgctxt "#726"
140 | msgid "Enable or disable support for Wireless (WLAN) networks"
141 | msgstr ""
142 |
143 | msgctxt "#727"
144 | msgid "Enable a 'tethered' Wireless Access Point. This requires your wireless card (and driver) to support bridging and access point mode. Not all cards are capable."
145 | msgstr ""
146 |
147 | msgctxt "#728"
148 | msgid "Configure the Access Point SSID"
149 | msgstr ""
150 |
151 | msgctxt "#729"
152 | msgid "Configure the Access Point Passphrase"
153 | msgstr ""
154 |
155 | msgctxt "#730"
156 | msgid "Enable or disable support for Wired (Ethernet) networks"
157 | msgstr ""
158 |
159 | msgctxt "#732"
160 | msgid "Configure the 1st time (NTP) server"
161 | msgstr ""
162 |
163 | msgctxt "#733"
164 | msgid "Configure the 2nd time (NTP) server"
165 | msgstr ""
166 |
167 | msgctxt "#734"
168 | msgid "Configure the 3rd time (NTP) server"
169 | msgstr ""
170 |
171 | msgctxt "#736"
172 | msgid "Set to ON to delay Kodi startup until the network is available. Use this if the OS is booting into Kodi before the network is up and central MySQL databases are accessible."
173 | msgstr ""
174 |
175 | msgctxt "#737"
176 | msgid "Time in seconds to wait for an established network connection."
177 | msgstr ""
178 |
179 | msgctxt "#738"
180 | msgid "Set to ON to enable the embedded Samba (SMB) filesharing service"
181 | msgstr ""
182 |
183 | msgctxt "#739"
184 | msgid "Set to ON to require username/password access to local Samba fileshares"
185 | msgstr ""
186 |
187 | msgctxt "#740"
188 | msgid "Set the username for Samba sharing"
189 | msgstr ""
190 |
191 | msgctxt "#741"
192 | msgid "Set the password for Samba sharing"
193 | msgstr ""
194 |
195 | msgctxt "#742"
196 | msgid "Set to ON to enable the embedded SSH server. The SSH console can be accessed with username 'root' and password '@ROOT_PASSWORD@'."
197 | msgstr ""
198 |
199 | msgctxt "#743"
200 | msgid "Set to ON if you have copied private SSH keys to your HTPC and would like to improve security by disabling SSH username and password authentication."
201 | msgstr ""
202 |
203 | msgctxt "#744"
204 | msgid "Set to ON to enable the Avahi (Zeroconf/Bonjour) network discovery service"
205 | msgstr ""
206 |
207 | msgctxt "#745"
208 | msgid "Set to ON to enable the cron daemon"
209 | msgstr ""
210 |
211 | msgctxt "#746"
212 | msgid "Set the password for SSH"
213 | msgstr ""
214 |
215 | msgctxt "#747"
216 | msgid "Enable a PIN for @DISTRONAME@ Settings access"
217 | msgstr ""
218 |
219 | msgctxt "#748"
220 | msgid "Change the PIN Lock for @DISTRONAME@ Settings access"
221 | msgstr ""
222 |
223 | msgctxt "#749"
224 | msgid "Overrride the Wireless Regulatory Domain so radio properties (channels and transmit power) comply with local laws or match the country configuration of your router."
225 | msgstr ""
226 |
227 | msgctxt "#750"
228 | msgid "750"
229 | msgstr ""
230 |
231 | msgctxt "#751"
232 | msgid "With OBEX filetransfer you can send files, for example movies or pictures over bluetooth to @DISTRONAME@."
233 | msgstr ""
234 |
235 | msgctxt "#752"
236 | msgid "Here you can set the folder location where OBEX file transfer should store incoming files"
237 | msgstr ""
238 |
239 | msgctxt "#753"
240 | msgid "Configure the 1st keyboard software Variant"
241 | msgstr ""
242 |
243 | msgctxt "#754"
244 | msgid "Configure the 2nd keyboard software Variant"
245 | msgstr ""
246 |
247 | msgctxt "#755"
248 | msgid "Auto share external drives / partitions"
249 | msgstr ""
250 |
251 | msgctxt "#756"
252 | msgid "Disable older SMB protocols by specifying the minimum supported protocol."
253 | msgstr ""
254 |
255 | msgctxt "#757"
256 | msgid "Disable more recent SMB protocols for backward compatability with legacy clients."
257 | msgstr ""
258 |
259 | msgctxt "#758"
260 | msgid "NetBIOS group to which the server belongs. Default is WORKGROUP."
261 | msgstr ""
262 |
263 | msgctxt "#760"
264 | msgid "Select an update channel"
265 | msgstr ""
266 |
267 | msgctxt "#761"
268 | msgid "Enable to allow entering a custom update url"
269 | msgstr ""
270 |
271 | msgctxt "#762"
272 | msgid "Enter a custom update url (url should be the root of the update files)"
273 | msgstr ""
274 |
275 | msgctxt "#770"
276 | msgid "Select an available version"
277 | msgstr ""
278 |
279 | msgctxt "#771"
280 | msgid "The firewall blocks unwanted network traffic. Home (default) allows traffic from private network ranges (192.168.x.x, 172.16.x.x and 10.x.x.x) only. Public blocks all traffic from all networks. Custom uses rules in /storage/.config/iptables. Off disables the firewall."
281 | msgstr ""
282 |
283 | msgctxt "#772"
284 | msgid "Checking for a new version will submit the installed Distribution, Project, CPU Arch and Version to the update server. This data is also used to report basic statistics for the project. To continue checking for updates while opting-out of stats reporting, disable this option."
285 | msgstr ""
286 |
287 | msgctxt "#773"
288 | msgid "Set the idle timeout (in minutes) before devices will be disconnected (defaults to 0 for no timeout). Applies to devices where \"Enable Standby\" has been activated in the LibreELEC device connection context menu."
289 | msgstr ""
290 |
291 | msgctxt "#32001"
292 | msgid "Services"
293 | msgstr ""
294 |
295 | msgctxt "#32002"
296 | msgid "System"
297 | msgstr ""
298 |
299 | msgctxt "#32003"
300 | msgid "Interface"
301 | msgstr ""
302 |
303 | msgctxt "#32005"
304 | msgid "Updates"
305 | msgstr ""
306 |
307 | msgctxt "#32009"
308 | msgid "Keyboard"
309 | msgstr ""
310 |
311 | msgctxt "#32010"
312 | msgid "Keyboard Layout"
313 | msgstr ""
314 |
315 | msgctxt "#32012"
316 | msgid "Select Action"
317 | msgstr ""
318 |
319 | msgctxt "#32013"
320 | msgid "OS Updates"
321 | msgstr ""
322 |
323 | msgctxt "#32014"
324 | msgid "Automatic Updates"
325 | msgstr ""
326 |
327 | msgctxt "#32015"
328 | msgid "Update Channel"
329 | msgstr ""
330 |
331 | msgctxt "#32016"
332 | msgid "Show Custom Channels"
333 | msgstr ""
334 |
335 | msgctxt "#32017"
336 | msgid " - Custom Channel 1"
337 | msgstr ""
338 |
339 | msgctxt "#32018"
340 | msgid " - Custom Channel 2"
341 | msgstr ""
342 |
343 | msgctxt "#32019"
344 | msgid " - Custom Channel 3"
345 | msgstr ""
346 |
347 | msgctxt "#32020"
348 | msgid "Available Versions"
349 | msgstr ""
350 |
351 | msgctxt "#32021"
352 | msgid "Submit Statistics"
353 | msgstr ""
354 |
355 | msgctxt "#32022"
356 | msgid "Firmware Updates"
357 | msgstr ""
358 |
359 | msgctxt "#32023"
360 | msgid "Updating will occur once the system is rebooted."
361 | msgstr ""
362 |
363 | msgctxt "#32024"
364 | msgid "Bootloader EEPROM"
365 | msgstr ""
366 |
367 | msgctxt "#32025"
368 | msgid "Update the Raspberry Pi Bootloader EEPROM to the latest version. This option is automatically disabled after rebooting. Reboot the system to apply the update."
369 | msgstr ""
370 |
371 | msgctxt "#32026"
372 | msgid "VIA USB3 Firmware"
373 | msgstr ""
374 |
375 | msgctxt "#32027"
376 | msgid "Update the Raspberry Pi VIA USB3 firmware to the latest version. This option is automatically disabled after rebooting. Reboot the system to apply the update."
377 | msgstr ""
378 |
379 | msgctxt "#32028"
380 | msgid "update from %s to %s"
381 | msgstr ""
382 |
383 | msgctxt "#32029"
384 | msgid "up to date: %s"
385 | msgstr ""
386 |
387 | msgctxt "#32100"
388 | msgid "Connections"
389 | msgstr ""
390 |
391 | msgctxt "#32101"
392 | msgid "Network"
393 | msgstr ""
394 |
395 | msgctxt "#32102"
396 | msgid "Wireless Networks"
397 | msgstr ""
398 |
399 | msgctxt "#32103"
400 | msgid "Wired Networks"
401 | msgstr ""
402 |
403 | msgctxt "#32105"
404 | msgid "Active"
405 | msgstr ""
406 |
407 | msgctxt "#32106"
408 | msgid "Username"
409 | msgstr ""
410 |
411 | msgctxt "#32107"
412 | msgid "Passphrase"
413 | msgstr ""
414 |
415 | msgctxt "#32108"
416 | msgid "Enable 'tethered' Wireless Access Point"
417 | msgstr ""
418 |
419 | msgctxt "#32109"
420 | msgid "Connect Automatically"
421 | msgstr ""
422 |
423 | msgctxt "#32110"
424 | msgid "Connection"
425 | msgstr ""
426 |
427 | msgctxt "#32111"
428 | msgid "IPv4"
429 | msgstr ""
430 |
431 | msgctxt "#32112"
432 | msgid "IPv6"
433 | msgstr ""
434 |
435 | msgctxt "#32113"
436 | msgid "IP Address Method"
437 | msgstr ""
438 |
439 | msgctxt "#32114"
440 | msgid "IP Address"
441 | msgstr ""
442 |
443 | msgctxt "#32115"
444 | msgid "Subnet Mask"
445 | msgstr ""
446 |
447 | msgctxt "#32116"
448 | msgid "Default Gateway"
449 | msgstr ""
450 |
451 | msgctxt "#32117"
452 | msgid "Prefix Length"
453 | msgstr ""
454 |
455 | msgctxt "#32118"
456 | msgid "Privacy"
457 | msgstr ""
458 |
459 | msgctxt "#32119"
460 | msgid "DNS Servers"
461 | msgstr ""
462 |
463 | msgctxt "#32120"
464 | msgid "Nameserver #1"
465 | msgstr ""
466 |
467 | msgctxt "#32121"
468 | msgid "Nameserver #2"
469 | msgstr ""
470 |
471 | msgctxt "#32122"
472 | msgid "Nameserver #3"
473 | msgstr ""
474 |
475 | msgctxt "#32123"
476 | msgid "NTP Servers"
477 | msgstr ""
478 |
479 | msgctxt "#32124"
480 | msgid "Timeserver #1"
481 | msgstr ""
482 |
483 | msgctxt "#32125"
484 | msgid "Timeserver #2"
485 | msgstr ""
486 |
487 | msgctxt "#32126"
488 | msgid "Timeserver #3"
489 | msgstr ""
490 |
491 | msgctxt "#32127"
492 | msgid "DNS Domains"
493 | msgstr ""
494 |
495 | msgctxt "#32128"
496 | msgid "Domain #1"
497 | msgstr ""
498 |
499 | msgctxt "#32129"
500 | msgid "Domain #2"
501 | msgstr ""
502 |
503 | msgctxt "#32130"
504 | msgid "Domain #3"
505 | msgstr ""
506 |
507 | msgctxt "#32140"
508 | msgid "Save"
509 | msgstr ""
510 |
511 | msgctxt "#32141"
512 | msgid "Delete"
513 | msgstr ""
514 |
515 | msgctxt "#32142"
516 | msgid "Refresh"
517 | msgstr ""
518 |
519 | msgctxt "#32143"
520 | msgid "Disconnect"
521 | msgstr ""
522 |
523 | msgctxt "#32144"
524 | msgid "Connect"
525 | msgstr ""
526 |
527 | msgctxt "#32145"
528 | msgid "Pair"
529 | msgstr ""
530 |
531 | msgctxt "#32146"
532 | msgid "Hidden Network Name"
533 | msgstr ""
534 |
535 | msgctxt "#32147"
536 | msgid "Wireless Network Passphrase"
537 | msgstr ""
538 |
539 | msgctxt "#32148"
540 | msgid "Wireless Network Username"
541 | msgstr ""
542 |
543 | msgctxt "#32150"
544 | msgid "Edit"
545 | msgstr ""
546 |
547 | msgctxt "#32180"
548 | msgid "Would you like to update @DISTRONAME@ now?"
549 | msgstr ""
550 |
551 | msgctxt "#32181"
552 | msgid "Filename"
553 | msgstr ""
554 |
555 | msgctxt "#32182"
556 | msgid "Download speed"
557 | msgstr ""
558 |
559 | msgctxt "#32183"
560 | msgid "Time remaining"
561 | msgstr ""
562 |
563 | msgctxt "#32184"
564 | msgid "Extract file"
565 | msgstr ""
566 |
567 | msgctxt "#32185"
568 | msgid "Extract speed"
569 | msgstr ""
570 |
571 | msgctxt "#32186"
572 | msgid "Initialize Archive File"
573 | msgstr ""
574 |
575 | msgctxt "#32187"
576 | msgid "New Version"
577 | msgstr ""
578 |
579 | msgctxt "#32188"
580 | msgid "Current Version"
581 | msgstr ""
582 |
583 | msgctxt "#32189"
584 | msgid "OS Configuration"
585 | msgstr ""
586 |
587 | msgctxt "#32190"
588 | msgid "System Name"
589 | msgstr ""
590 |
591 | msgctxt "#32191"
592 | msgid "Invalid URL"
593 | msgstr ""
594 |
595 | msgctxt "#32192"
596 | msgid "PIN lock"
597 | msgstr ""
598 |
599 | msgctxt "#32193"
600 | msgid "Enable @DISTRONAME@ Settings PIN Lock"
601 | msgstr ""
602 |
603 | msgctxt "#32194"
604 | msgid "Change @DISTRONAME@ Settings PIN Lock"
605 | msgstr ""
606 |
607 | msgctxt "#32196"
608 | msgid "About"
609 | msgstr ""
610 |
611 | msgctxt "#32198"
612 | msgid "SSID"
613 | msgstr ""
614 |
615 | msgctxt "#32200"
616 | msgid "Samba"
617 | msgstr ""
618 |
619 | msgctxt "#32201"
620 | msgid "SSH"
621 | msgstr ""
622 |
623 | msgctxt "#32202"
624 | msgid "Use Samba Password Authentication"
625 | msgstr ""
626 |
627 | msgctxt "#32203"
628 | msgid "Disable SSH Password"
629 | msgstr ""
630 |
631 | msgctxt "#32204"
632 | msgid "Enable Samba"
633 | msgstr ""
634 |
635 | msgctxt "#32205"
636 | msgid "Enable SSH"
637 | msgstr ""
638 |
639 | msgctxt "#32206"
640 | msgid "Enable Avahi (Zeroconf)"
641 | msgstr ""
642 |
643 | msgctxt "#32207"
644 | msgid "Avahi"
645 | msgstr ""
646 |
647 | msgctxt "#32208"
648 | msgid "Hidden Wlan"
649 | msgstr ""
650 |
651 | msgctxt "#32209"
652 | msgid "SSH Password"
653 | msgstr ""
654 |
655 | msgctxt "#32210"
656 | msgid "The default SSH password is widely known and considered insecure.[CR][CR]Setting a personal password is recommended."
657 | msgstr ""
658 |
659 | msgctxt "#32212"
660 | msgid "Cancel"
661 | msgstr ""
662 |
663 | msgctxt "#32213"
664 | msgid "Keep Existing"
665 | msgstr ""
666 |
667 | msgctxt "#32214"
668 | msgid "Set Password"
669 | msgstr ""
670 |
671 | msgctxt "#32215"
672 | msgid "Workgroup name"
673 | msgstr ""
674 |
675 | msgctxt "#32216"
676 | msgid "Auto-Share External Drives"
677 | msgstr ""
678 |
679 | msgctxt "#32217"
680 | msgid "Minimum supported protocol"
681 | msgstr ""
682 |
683 | msgctxt "#32218"
684 | msgid "Maximum supported protocol"
685 | msgstr ""
686 |
687 | msgctxt "#32220"
688 | msgid "Bad password!"
689 | msgstr ""
690 |
691 | msgctxt "#32221"
692 | msgid "The entered password is too weak.[CR]SSH password is unchanged."
693 | msgstr ""
694 |
695 | msgctxt "#32222"
696 | msgid "Password changed!"
697 | msgstr ""
698 |
699 | msgctxt "#32223"
700 | msgid "The SSH password has been successfully changed."
701 | msgstr ""
702 |
703 | msgctxt "#32224"
704 | msgid "Unknown error!"
705 | msgstr ""
706 |
707 | msgctxt "#32225"
708 | msgid "There was an error during the process.[CR]SSH password is unchanged."
709 | msgstr ""
710 |
711 | msgctxt "#32226"
712 | msgid "Enter new 4 digit PIN"
713 | msgstr ""
714 |
715 | msgctxt "#32227"
716 | msgid "Re-enter PIN"
717 | msgstr ""
718 |
719 | msgctxt "#32228"
720 | msgid "Error - PIN codes did not match!"
721 | msgstr ""
722 |
723 | msgctxt "#32229"
724 | msgid "@DISTRONAME@ Settings PIN lock not set.[CR][CR]Please try again."
725 | msgstr ""
726 |
727 | msgctxt "#32230"
728 | msgid "@DISTRONAME@ Settings PIN lock set."
729 | msgstr ""
730 |
731 | msgctxt "#32231"
732 | msgid "Your @DISTRONAME@ Settings PIN lock has been set to:"
733 | msgstr ""
734 |
735 | msgctxt "#32232"
736 | msgid "Error - PIN code not 4 digits!"
737 | msgstr ""
738 |
739 | msgctxt "#32233"
740 | msgid "@DISTRONAME@ Settings Locked[CR]Enter 4 digit PIN"
741 | msgstr ""
742 |
743 | msgctxt "#32234"
744 | msgid "Incorrect PIN!"
745 | msgstr ""
746 |
747 | msgctxt "#32235"
748 | msgid " attempts remaining."
749 | msgstr ""
750 |
751 | msgctxt "#32236"
752 | msgid "You have entered an incorrect PIN too many times.[CR][CR]You will need to wait 5 minutes before trying again."
753 | msgstr ""
754 |
755 | msgctxt "#32237"
756 | msgid "@DISTRONAME@ Settings Locked!"
757 | msgstr ""
758 |
759 | msgctxt "#32238"
760 | msgid "Time remaining before PIN can be entered: %02d:%02d[CR][CR]Too many previous failed attempts."
761 | msgstr ""
762 |
763 | msgctxt "#32240"
764 | msgid "Wireless Regulatory Domain"
765 | msgstr ""
766 |
767 | msgctxt "#32300"
768 | msgid "Welcome to @DISTRONAME@"
769 | msgstr ""
770 |
771 | msgctxt "#32301"
772 | msgid "Welcome"
773 | msgstr ""
774 |
775 | msgctxt "#32302"
776 | msgid "This wizard will guide you through the process of setting up your new @DISTRONAME@ installation - setting your location, timezone and connecting you to the internet.[CR][CR]These settings can be changed later by navigating to Programs > @DISTRONAME@ Settings."
777 | msgstr ""
778 |
779 | msgctxt "#32303"
780 | msgid "Next"
781 | msgstr ""
782 |
783 | msgctxt "#32304"
784 | msgid "To be identified easily on the network, your new @DISTRONAME@ machine needs a name.[CR][CR]Try to choose something meaningful - like the room it's in - so you'll know what it is when you see it on the network.[CR][CR]This name is used when configuring network services, like file sharing using samba."
785 | msgstr ""
786 |
787 | msgctxt "#32305"
788 | msgid "Networking"
789 | msgstr ""
790 |
791 | msgctxt "#32306"
792 | msgid "In order to download backdrops, banners and thumbnails for your movies and TV shows and to stream online content from sites like YouTube, @DISTRONAME@ needs to be connected the Internet.[CR][CR]An Internet connection is also required for @DISTRONAME@ to automatically update itself."
793 | msgstr ""
794 |
795 | msgctxt "#32307"
796 | msgid "Previous"
797 | msgstr ""
798 |
799 | msgctxt "#32308"
800 | msgid "Hostname:"
801 | msgstr ""
802 |
803 | msgctxt "#32309"
804 | msgid "The following Networks are currently available:"
805 | msgstr ""
806 |
807 | msgctxt "#32310"
808 | msgid "Language:"
809 | msgstr ""
810 |
811 | msgctxt "#32311"
812 | msgid "Sharing and Remote Access"
813 | msgstr ""
814 |
815 | msgctxt "#32312"
816 | msgid "@DISTRONAME@ also supports SSH for remote access. This is for advanced users who wish to interact with @DISTRONAME@'s underlying operating system. The default user is [COLOR blue]root[/COLOR] and the default password is [COLOR blue]@ROOT_PASSWORD@[/COLOR]."
817 | msgstr ""
818 |
819 | msgctxt "#32313"
820 | msgid "In order to share your files between your computers @DISTRONAME@ has incorporated a samba server. This samba server can be integrated into your local network by accessing it in a familiar way with Finder or Windows Explorer."
821 | msgstr ""
822 |
823 | msgctxt "#32316"
824 | msgid "Configure Services:"
825 | msgstr ""
826 |
827 | msgctxt "#32317"
828 | msgid "Thank you"
829 | msgstr ""
830 |
831 | msgctxt "#32318"
832 | msgid "Your @DISTRONAME@ installation is now complete and you are about to enter Kodi where you can set up your media libraries. For help with this, there is a guide available at wiki.kodi.tv[CR][CR]@DISTRONAME@ is developed by a dedicated team of developers who work purely in their spare time. Even as a volunteer project, we still have to pay for our internet bandwidth and development resources so if you find @DISTRONAME@ useful we will always appreciate a donation of any amount.[CR][CR]Finally, we hope you enjoy using @DISTRONAME@ as much as we've enjoyed building it. If you need any more help, you can find links to our support forum along with latest news at our website."
833 | msgstr ""
834 |
835 | msgctxt "#32319"
836 | msgid "Cron"
837 | msgstr ""
838 |
839 | msgctxt "#32320"
840 | msgid "Enable Cron"
841 | msgstr ""
842 |
843 | msgctxt "#32323"
844 | msgid "Reset to Defaults"
845 | msgstr ""
846 |
847 | msgctxt "#32324"
848 | msgid "Reset System Settings to defaults"
849 | msgstr ""
850 |
851 | msgctxt "#32325"
852 | msgid "Reset @DISTRONAME@ to defaults"
853 | msgstr ""
854 |
855 | msgctxt "#32326"
856 | msgid "Are you sure?"
857 | msgstr ""
858 |
859 | msgctxt "#32328"
860 | msgid "The system must reboot."
861 | msgstr ""
862 |
863 | msgctxt "#32329"
864 | msgid "Rebooting in %d seconds"
865 | msgstr ""
866 |
867 | msgctxt "#32330"
868 | msgid "Keyboard Type"
869 | msgstr ""
870 |
871 | msgctxt "#32331"
872 | msgid "Bluetooth"
873 | msgstr ""
874 |
875 | msgctxt "#32333"
876 | msgid "Connected: "
877 | msgstr ""
878 |
879 | msgctxt "#32334"
880 | msgid "Yes"
881 | msgstr ""
882 |
883 | msgctxt "#32335"
884 | msgid "No"
885 | msgstr ""
886 |
887 | msgctxt "#32338"
888 | msgid "No Bluetooth adapter found."
889 | msgstr ""
890 |
891 | msgctxt "#32339"
892 | msgid "No Bluetooth device found. Please put your Bluetooth device into discovery mode[CR]and start the scan"
893 | msgstr ""
894 |
895 | msgctxt "#32343"
896 | msgid "Enter the following Key on your Device."
897 | msgstr ""
898 |
899 | msgctxt "#32344"
900 | msgid "Enable Bluetooth"
901 | msgstr ""
902 |
903 | msgctxt "#32346"
904 | msgid "Bluetooth is disabled"
905 | msgstr ""
906 |
907 | msgctxt "#32358"
908 | msgid "Trust and Connect"
909 | msgstr ""
910 |
911 | msgctxt "#32362"
912 | msgid "Check for updates now:"
913 | msgstr ""
914 |
915 | msgctxt "#32363"
916 | msgid "@DISTRONAME@"
917 | msgstr ""
918 |
919 | msgctxt "#32364"
920 | msgid "Update available"
921 | msgstr ""
922 |
923 | msgctxt "#32365"
924 | msgid "Show Update Notifications"
925 | msgstr ""
926 |
927 | msgctxt "#32366"
928 | msgid "Update Download Completed"
929 | msgstr ""
930 |
931 | msgctxt "#32367"
932 | msgid "Update Extract Complete"
933 | msgstr ""
934 |
935 | msgctxt "#32368"
936 | msgid "Advanced Network Settings"
937 | msgstr ""
938 |
939 | msgctxt "#32369"
940 | msgid "Wait for network before starting Kodi"
941 | msgstr ""
942 |
943 | msgctxt "#32370"
944 | msgid "Maximum Wait Time (Sec.)"
945 | msgstr ""
946 |
947 | msgctxt "#32371"
948 | msgid "Backup"
949 | msgstr ""
950 |
951 | msgctxt "#32372"
952 | msgid "Create System and Kodi Backup"
953 | msgstr ""
954 |
955 | msgctxt "#32373"
956 | msgid "Restore Backup"
957 | msgstr ""
958 |
959 | msgctxt "#32374"
960 | msgid "Error: Invalid backup file. Filename must end in: .tar, .tar.gz, .tar.bz2, or .tar.xz"
961 | msgstr ""
962 |
963 | msgctxt "#32375"
964 | msgid "Backup Progress"
965 | msgstr ""
966 |
967 | msgctxt "#32376"
968 | msgid "Submit Log"
969 | msgstr ""
970 |
971 | msgctxt "#32377"
972 | msgid "Upload latest Kodi log and configs, and view the short URL"
973 | msgstr ""
974 |
975 | msgctxt "#32378"
976 | msgid "Upload latest Kodi crash log and configs, and view the short URL"
977 | msgstr ""
978 |
979 | msgctxt "#32379"
980 | msgid "There is not enough free storage space to continue!"
981 | msgstr ""
982 |
983 | msgctxt "#32380"
984 | msgid "Restoring system settings requires a reboot. Are you sure you want to restore?"
985 | msgstr ""
986 |
987 | msgctxt "#32381"
988 | msgid "Accept incoming Bluetooth Filetransfer ?"
989 | msgstr ""
990 |
991 | msgctxt "#32382"
992 | msgid "Speed"
993 | msgstr ""
994 |
995 | msgctxt "#32383"
996 | msgid "Play Files ?"
997 | msgstr ""
998 |
999 | msgctxt "#32384"
1000 | msgid "OBEX Enabled"
1001 | msgstr ""
1002 |
1003 | msgctxt "#32385"
1004 | msgid "OBEX Upload Folder"
1005 | msgstr ""
1006 |
1007 | msgctxt "#32386"
1008 | msgid "Keyboard Layout Variant #1"
1009 | msgstr ""
1010 |
1011 | msgctxt "#32387"
1012 | msgid "Keyboard Layout Variant #2"
1013 | msgstr ""
1014 |
1015 | msgctxt "#32388"
1016 | msgid "Enable Standby"
1017 | msgstr ""
1018 |
1019 | msgctxt "#32389"
1020 | msgid "Disable Standby"
1021 | msgstr ""
1022 |
1023 | msgctxt "#32390"
1024 | msgid "Settings addon is not yet ready, please try again later."
1025 | msgstr ""
1026 |
1027 | msgctxt "#32393"
1028 | msgid "** SAFE MODE! ** SAFE MODE! ** SAFE MODE! **"
1029 | msgstr ""
1030 |
1031 | msgctxt "#32394"
1032 | msgid "@DISTRONAME@ has temporarily started in safe mode due to repeated Kodi crashes.[CR][CR]You may now investigate the cause of the crashes by enabling ssh or Samba.[CR][CR]Your original Kodi installation can be accessed via \"/storage/.kodi.FAILED\" and the Samba \"Kodi-Failed\" share.[CR][CR]Rebooting will return to your original Kodi installation.[CR][CR]Go to https://forum.libreelec.tv if you require further assistance. When posting to the forum include the link to your crash log which can be viewed by clicking the crash log option in Settings > LibreELEC > System > Submit Log."
1033 | msgstr ""
1034 |
1035 | msgctxt "#32395"
1036 | msgid "Firewall"
1037 | msgstr ""
1038 |
1039 | msgctxt "#32396"
1040 | msgid "Custom"
1041 | msgstr ""
1042 |
1043 | msgctxt "#32397"
1044 | msgid "Off"
1045 | msgstr ""
1046 |
1047 | msgctxt "#32398"
1048 | msgid "Home"
1049 | msgstr ""
1050 |
1051 | msgctxt "#32399"
1052 | msgid "Public"
1053 | msgstr ""
1054 |
1055 | msgctxt "#32400"
1056 | msgid "Idle Timeout"
1057 | msgstr ""
1058 |
1059 | msgctxt "#32401"
1060 | msgid "Syncing Disks..."
1061 | msgstr ""
1062 |
1063 | msgctxt "#32402"
1064 | msgid "Backup is incomplete. An error occurred. See Kodi log for details."
1065 | msgstr ""
1066 |
1067 | msgctxt "#32410"
1068 | msgid "Logging"
1069 | msgstr ""
1070 |
1071 | msgctxt "#32411"
1072 | msgid "Use Persistent Logs"
1073 | msgstr ""
1074 |
1075 | msgctxt "#32412"
1076 | msgid "Use Persistent Journal and Log files instead of default volatile ones. Reboot to apply changes."
1077 | msgstr ""
1078 |
1079 | msgctxt "#32413"
1080 | msgid "Journal Size"
1081 | msgstr ""
1082 |
1083 | msgctxt "#32414"
1084 | msgid "Set max. size of persistent journal. Reboot to apply changes."
1085 | msgstr ""
1086 |
1087 | msgctxt "#32415"
1088 | msgid "Disable journald Rate Limit"
1089 | msgstr ""
1090 |
1091 | msgctxt "#32416"
1092 | msgid "Reboot to apply changes."
1093 | msgstr ""
1094 |
1095 | msgctxt "#32417"
1096 | msgid "Sending..."
1097 | msgstr ""
1098 |
1099 | msgctxt "#32418"
1100 | msgid "Log files sent to:"
1101 | msgstr ""
1102 |
1103 | msgctxt "#32419"
1104 | msgid "Error sending log files. Please try again."
1105 | msgstr ""
1106 |
1107 | msgctxt "#32420"
1108 | msgid "Timezone"
1109 | msgstr ""
1110 |
--------------------------------------------------------------------------------
/resources/lib/config.py:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: GPL-2.0
2 | # Copyright (C) 2020-present Team LibreELEC (https://libreelec.tv)
3 |
4 | import os
5 |
6 | import os_tools
7 |
8 |
9 | OS_RELEASE = os_tools.read_shell_settings('/etc/os-release')
10 |
11 | CONFIG_CACHE = os.environ.get('CONFIG_CACHE', '/storage/.cache')
12 | USER_CONFIG = os.environ.get('USER_CONFIG', '/storage/.config')
13 |
14 | HOSTNAME = os.path.join(CONFIG_CACHE, 'hostname')
15 | HOSTS_CONF = os.path.join(USER_CONFIG, 'hosts.conf')
16 |
17 | REGDOMAIN_CONF = os.path.join(CONFIG_CACHE, 'regdomain.conf')
18 | SETREGDOMAIN = '/usr/lib/iw/setregdomain'
19 |
20 | TIMEZONE = os.path.join(CONFIG_CACHE, 'timezone')
21 |
--------------------------------------------------------------------------------
/resources/lib/dbus_bluez.py:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: GPL-2.0
2 | # Copyright (C) 2020-present Team LibreELEC (https://libreelec.tv)
3 |
4 | import dbussy
5 | import ravel
6 |
7 | import dbus_utils
8 |
9 |
10 | BUS_NAME = 'org.bluez'
11 | ERROR_REJECTED = 'org.bluez.Error.Rejected'
12 | INTERFACE_ADAPTER = 'org.bluez.Adapter1'
13 | INTERFACE_AGENT = 'org.bluez.Agent1'
14 | INTERFACE_AGENT_MANAGER = 'org.bluez.AgentManager1'
15 | INTERFACE_DEVICE = 'org.bluez.Device1'
16 | PATH_BLUEZ = '/org/bluez'
17 | PATH_AGENT = '/kodi/agent/bluez'
18 |
19 |
20 | @ravel.interface(ravel.INTERFACE.SERVER, name=INTERFACE_AGENT)
21 | class Agent(dbus_utils.Agent):
22 |
23 | def __init__(self):
24 | super().__init__(BUS_NAME, PATH_AGENT)
25 |
26 | def manager_register_agent(self):
27 | dbus_utils.call_method(BUS_NAME, PATH_BLUEZ, INTERFACE_AGENT_MANAGER,
28 | 'RegisterAgent', PATH_AGENT, 'KeyboardDisplay')
29 |
30 | def manager_unregister_agent(self):
31 | dbus_utils.call_method(BUS_NAME, PATH_BLUEZ, INTERFACE_AGENT_MANAGER,
32 | 'UnregisterAgent', PATH_AGENT)
33 |
34 | @ravel.method(
35 | in_signature='os',
36 | out_signature='',
37 | arg_keys=['device', 'uuid']
38 | )
39 | def AuthorizeService(self, device, uuid):
40 | self.authorize_service(device, uuid)
41 |
42 | @ravel.method(
43 | in_signature='',
44 | out_signature=''
45 | )
46 | def Cancel(self):
47 | self.cancel()
48 |
49 | @ravel.method(
50 | in_signature='ouq',
51 | out_signature='',
52 | arg_keys=['device', 'passkey', 'entered']
53 | )
54 | def DisplayPasskey(self, device, passkey, entered):
55 | self.display_passkey(device, passkey, entered)
56 |
57 | @ravel.method(
58 | in_signature='os',
59 | out_signature='',
60 | arg_keys=['device', 'pincode']
61 | )
62 | def DisplayPinCode(self, device, pincode):
63 | self.display_pincode(device, pincode)
64 |
65 | @ravel.method(
66 | in_signature='',
67 | out_signature=''
68 | )
69 | def Release(self):
70 | raise NotImplementedError
71 |
72 | @ravel.method(
73 | in_signature='o',
74 | out_signature='',
75 | arg_keys=['device']
76 | )
77 | def RequestAuthorization(self, device):
78 | self.request_authorization(device)
79 |
80 | @ravel.method(
81 | in_signature='ou',
82 | out_signature='',
83 | arg_keys=['device', 'passkey']
84 | )
85 | def RequestConfirmation(self, device, passkey):
86 | self.request_confirmation(device, passkey)
87 |
88 | @ravel.method(
89 | in_signature='o',
90 | out_signature='u',
91 | arg_keys=['device'],
92 | result_keyword='reply'
93 | )
94 | def RequestPasskey(self, device):
95 | passkey = self.request_passkey(device)
96 | reply[0] = (dbussy.DBUS.Signature('u'), passkey)
97 |
98 | @ravel.method(
99 | in_signature='o',
100 | out_signature='s',
101 | arg_keys=['device'],
102 | result_keyword='reply'
103 | )
104 | def RequestPinCode(self, device, reply):
105 | pincode = self.request_pincode(device)
106 | reply[0] = (dbussy.DBUS.Signature('s'), pincode)
107 |
108 | def reject(self, message):
109 | raise dbussy.DBusError(ERROR_REJECTED, message)
110 |
111 | class Listener(object):
112 |
113 | def __init__(self):
114 | dbus_utils.BUS.listen_objects_added(func=self._on_interfaces_added)
115 | dbus_utils.BUS.listen_objects_removed(func=self._on_interfaces_removed)
116 | dbus_utils.BUS.listen_propchanged(
117 | interface=dbussy.DBUS.INTERFACE_PROPERTIES,
118 | fallback=True,
119 | func=self._on_properties_changed,
120 | path='/')
121 |
122 | @ravel.signal(name='InterfacesAdded', in_signature='oa{sa{sv}}', arg_keys=('path', 'interfaces'))
123 | def _on_interfaces_added(self, path, interfaces):
124 | interfaces = dbus_utils.convert_from_dbussy(interfaces)
125 | self.on_interfaces_added(path, interfaces)
126 |
127 | @ravel.signal(name='InterfacesRemoved', in_signature='oas', arg_keys=('path', 'interfaces'))
128 | def _on_interfaces_removed(self, path, interfaces):
129 | interfaces = dbus_utils.convert_from_dbussy(interfaces)
130 | self.on_interfaces_removed(path, interfaces)
131 |
132 | @ravel.signal(name='PropertiesChanged', in_signature='sa{sv}as', arg_keys=('interface', 'changed', 'invalidated'), path_keyword='path')
133 | def _on_properties_changed(self, interface, changed, invalidated, path):
134 | interface = dbus_utils.convert_from_dbussy(interface)
135 | changed = dbus_utils.convert_from_dbussy(changed)
136 | invalidated = dbus_utils.convert_from_dbussy(invalidated)
137 | self.on_properties_changed(interface, changed, invalidated, path)
138 |
139 | def get_managed_objects():
140 | return dbus_utils.call_method(BUS_NAME, '/', dbussy.DBUSX.INTERFACE_OBJECT_MANAGER, 'GetManagedObjects')
141 |
142 |
143 | def adapter_get_property(path, name):
144 | return dbus_utils.call_method(BUS_NAME, path, dbussy.DBUS.INTERFACE_PROPERTIES, 'Get', INTERFACE_ADAPTER, name)
145 |
146 |
147 | def adapter_get_powered(path):
148 | return adapter_get_property(path, 'Powered')
149 |
150 |
151 | def adapter_remove_device(path, device):
152 | return dbus_utils.call_method(BUS_NAME, path, INTERFACE_ADAPTER, 'RemoveDevice', device)
153 |
154 |
155 | def adapter_set_property(path, name, value):
156 | return dbus_utils.call_method(BUS_NAME, path, dbussy.DBUS.INTERFACE_PROPERTIES, 'Set', INTERFACE_ADAPTER, name, value)
157 |
158 |
159 | def adapter_set_alias(path, alias):
160 | return adapter_set_property(path, 'Alias', (dbussy.DBUS.Signature('s'), alias))
161 |
162 |
163 | def adapter_set_powered(path, powered):
164 | return adapter_set_property(path, 'Powered', (dbussy.DBUS.Signature('b'), powered))
165 |
166 |
167 | def adapter_start_discovery(path):
168 | return dbus_utils.call_method(BUS_NAME, path, INTERFACE_ADAPTER, 'StartDiscovery')
169 |
170 |
171 | def adapter_stop_discovery(path):
172 | return dbus_utils.call_method(BUS_NAME, path, INTERFACE_ADAPTER, 'StopDiscovery')
173 |
174 |
175 | def device_get_property(path, name):
176 | return dbus_utils.call_method(BUS_NAME, path, dbussy.DBUS.INTERFACE_PROPERTIES, 'Get', INTERFACE_DEVICE, name)
177 |
178 |
179 | def device_get_connected(path):
180 | return device_get_property(path, 'Connected')
181 |
182 |
183 | def device_connect(path):
184 | return dbus_utils.run_method(BUS_NAME, path, INTERFACE_DEVICE, 'Connect')
185 |
186 |
187 | def device_disconnect(path):
188 | return dbus_utils.call_method(BUS_NAME, path, INTERFACE_DEVICE, 'Disconnect')
189 |
190 |
191 | def device_pair(path):
192 | return dbus_utils.run_method(BUS_NAME, path, INTERFACE_DEVICE, 'Pair')
193 |
194 |
195 | def device_set_property(path, name, value):
196 | return dbus_utils.call_method(BUS_NAME, path, dbussy.DBUS.INTERFACE_PROPERTIES, 'Set', INTERFACE_DEVICE, name, value)
197 |
198 |
199 | def device_set_trusted(path, trusted):
200 | return device_set_property(path, 'Trusted', (dbussy.DBUS.Signature('b'), trusted))
201 |
202 |
203 | def find_adapter():
204 | if system_has_bluez():
205 | objects = get_managed_objects()
206 | for path, interfaces in objects.items():
207 | if interfaces.get(INTERFACE_ADAPTER):
208 | return path
209 |
210 |
211 | def find_devices():
212 | devices = {}
213 | objects = get_managed_objects()
214 | for path, interfaces in objects.items():
215 | if interfaces.get(INTERFACE_DEVICE):
216 | devices[path] = interfaces[INTERFACE_DEVICE]
217 | return devices
218 |
219 |
220 | def system_has_bluez():
221 | return BUS_NAME in dbus_utils.list_names()
222 |
--------------------------------------------------------------------------------
/resources/lib/dbus_connman.py:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: GPL-2.0
2 | # Copyright (C) 2020-present Team LibreELEC (https://libreelec.tv)
3 |
4 | import dbussy
5 | import ravel
6 |
7 | import dbus_utils
8 | import log
9 |
10 |
11 | BUS_NAME = 'net.connman'
12 | ERROR_AGENT_CANCELLED = 'net.connman.Agent.Error.Canceled'
13 | INTERFACE_AGENT = 'net.connman.Agent'
14 | INTERFACE_CLOCK = 'net.connman.Clock'
15 | INTERFACE_MANAGER = 'net.connman.Manager'
16 | INTERFACE_SERVICE = 'net.connman.Service'
17 | INTERFACE_TECHNOLOGY = 'net.connman.Technology'
18 | PATH_TECH_ETHERNET = '/net/connman/technology/ethernet'
19 | PATH_TECH_WIFI = '/net/connman/technology/wifi'
20 | PATH_AGENT = '/kodi/agent/connman'
21 |
22 |
23 | @ravel.interface(ravel.INTERFACE.SERVER, name=INTERFACE_AGENT)
24 | class Agent(dbus_utils.Agent):
25 |
26 | @log.log_function()
27 | def __init__(self):
28 | super().__init__(BUS_NAME, PATH_AGENT)
29 |
30 | def manager_register_agent(self):
31 | dbus_utils.call_method(
32 | BUS_NAME, '/', INTERFACE_MANAGER, 'RegisterAgent', PATH_AGENT)
33 |
34 | def manager_unregister_agent(self):
35 | dbus_utils.call_method(
36 | BUS_NAME, '/', INTERFACE_MANAGER, 'UnregisterAgent', PATH_AGENT
37 | )
38 |
39 | @ravel.method(
40 | in_signature='',
41 | out_signature=''
42 | )
43 | def Cancel(self):
44 | self.cancel()
45 |
46 | def cancel(self):
47 | pass
48 |
49 | @ravel.method(
50 | in_signature='',
51 | out_signature=''
52 | )
53 | def Release(self):
54 | pass
55 |
56 | @ravel.method(
57 | in_signature='os',
58 | out_signature='',
59 | arg_keys=['path', 'error']
60 | )
61 | async def ReportError(self, path, error):
62 | self.report_error(path, error)
63 |
64 | @ravel.method(
65 | in_signature='os',
66 | out_signature='',
67 | arg_keys=['service', 'url']
68 | )
69 | def RequestBrowser(self, path, url):
70 | raise NotImplementedError
71 |
72 | @ravel.method(
73 | in_signature='oa{sv}',
74 | out_signature='a{sv}',
75 | args_keyword='request',
76 | result_keyword='reply'
77 | )
78 | async def RequestInput(self, request, reply):
79 | request = dbus_utils.convert_from_dbussy(request)
80 | input = self.request_input(*request)
81 | input = {k: (dbussy.DBUS.Signature('s'), v)
82 | for (k, v) in input.items()}
83 | reply[0] = input
84 |
85 | def agent_abort(self):
86 | raise ravel.ErrorReturn(ERROR_AGENT_CANCELLED, 'Input cancelled')
87 |
88 |
89 | class Listener(object):
90 |
91 | def __init__(self):
92 | dbus_utils.BUS.listen_signal(
93 | interface=INTERFACE_MANAGER,
94 | fallback=True,
95 | func=self._on_property_changed,
96 | path='/',
97 | name='PropertyChanged')
98 | dbus_utils.BUS.listen_signal(
99 | interface=INTERFACE_MANAGER,
100 | fallback=True,
101 | func=self._on_services_changed,
102 | path='/',
103 | name='ServicesChanged')
104 | dbus_utils.BUS.listen_signal(
105 | interface=INTERFACE_SERVICE,
106 | fallback=True,
107 | func=self._on_property_changed,
108 | path='/',
109 | name='PropertyChanged')
110 | dbus_utils.BUS.listen_signal(
111 | interface=INTERFACE_TECHNOLOGY,
112 | fallback=True,
113 | func=self._on_technology_changed,
114 | path='/',
115 | name='PropertyChanged')
116 |
117 | @ravel.signal(name='PropertyChanged', in_signature='sv', arg_keys=('name', 'value'), path_keyword='path')
118 | async def _on_property_changed(self, name, value, path):
119 | value = dbus_utils.convert_from_dbussy(value)
120 | await self.on_property_changed(name, value, path)
121 |
122 | @ravel.signal(name='ServicesChanged', in_signature='a(oa{sv})ao', arg_keys=('services', 'removed'))
123 | async def _on_services_changed(self, services, removed):
124 | services = dbus_utils.convert_from_dbussy(services)
125 | removed = dbus_utils.convert_from_dbussy(removed)
126 | await self.on_services_changed(services, removed)
127 |
128 | @ravel.signal(name='PropertyChanged', in_signature='sv', arg_keys=('name', 'value'), path_keyword='path')
129 | async def _on_technology_changed(self, name, value, path):
130 | value = dbus_utils.convert_from_dbussy(value)
131 | await self.on_technology_changed(name, value, path)
132 |
133 |
134 | def clock_get_properties():
135 | return dbus_utils.call_method(BUS_NAME, '/', INTERFACE_CLOCK, 'GetProperties')
136 |
137 |
138 | def clock_set_timeservers(timeservers):
139 | return dbus_utils.call_method(BUS_NAME, '/', INTERFACE_CLOCK, 'SetProperty', 'Timeservers', (dbussy.DBUS.Signature('as'), timeservers))
140 |
141 |
142 | def manager_get_properties():
143 | return dbus_utils.call_method(BUS_NAME, '/', INTERFACE_MANAGER, 'GetProperties')
144 |
145 |
146 | def manager_get_services():
147 | return dbus_utils.call_method(BUS_NAME, '/', INTERFACE_MANAGER, 'GetServices')
148 |
149 |
150 | def manager_get_technologies():
151 | return dbus_utils.call_method(BUS_NAME, '/', INTERFACE_MANAGER, 'GetTechnologies')
152 |
153 |
154 | def service_connect(path):
155 | return dbus_utils.run_method(BUS_NAME, path, INTERFACE_SERVICE, 'Connect')
156 |
157 |
158 | def service_disconnect(path):
159 | return dbus_utils.call_method(BUS_NAME, path, INTERFACE_SERVICE, 'Disconnect')
160 |
161 |
162 | def service_get_properties(path):
163 | return dbus_utils.call_method(BUS_NAME, path, INTERFACE_SERVICE, 'GetProperties')
164 |
165 |
166 | def service_remove(path):
167 | return dbus_utils.call_method(BUS_NAME, path, INTERFACE_SERVICE, 'Remove')
168 |
169 |
170 | def service_set_autoconnect(path, autoconnect):
171 | autoconnect = True if autoconnect == '1' else False
172 | return service_set_property(path, 'AutoConnect', (dbussy.DBUS.Signature('b'), autoconnect))
173 |
174 |
175 | def service_set_domains_configuration(path, domains):
176 | return service_set_property(path, 'Domains.Configuration', (dbussy.DBUS.Signature('as'), domains))
177 |
178 |
179 | def service_set_ipv4_configuration(path, ipv4):
180 | return service_set_property(path, 'IPv4.Configuration', (dbussy.DBUS.Signature('a{sv}'), {key: (dbussy.DBUS.Signature('s'), value) for key, value in ipv4.items()}))
181 |
182 |
183 | def service_set_ipv6_configuration(path, ipv6):
184 | return service_set_property(path, 'IPv6.Configuration', (dbussy.DBUS.Signature('a{sv}'), {key: (dbussy.DBUS.Signature('y'), int(value)) if key == 'PrefixLength' else (dbussy.DBUS.Signature('s'), value) for key, value in ipv6.items()}))
185 |
186 |
187 | def service_set_nameservers_configuration(path, nameservers):
188 | return service_set_property(path, 'Nameservers.Configuration', (dbussy.DBUS.Signature('as'), nameservers))
189 |
190 |
191 | def service_set_property(path, name, value):
192 | return dbus_utils.call_method(BUS_NAME, path, INTERFACE_SERVICE, 'SetProperty', name, value)
193 |
194 |
195 | def service_set_timeservers_configuration(path, timeservers):
196 | return service_set_property(path, 'Timeservers.Configuration', (dbussy.DBUS.Signature('as'), timeservers))
197 |
198 |
199 | def technology_set_powered(path, state):
200 | return technology_set_property(path, 'Powered', (dbussy.DBUS.Signature('b'), state))
201 |
202 |
203 | def technology_set_property(path, name, value):
204 | return dbus_utils.call_method(BUS_NAME, path, INTERFACE_TECHNOLOGY, 'SetProperty', name, value)
205 |
206 |
207 | def technology_wifi_scan():
208 | return dbus_utils.call_method(BUS_NAME, PATH_TECH_WIFI, INTERFACE_TECHNOLOGY, 'Scan')
209 |
210 |
211 | def technology_wifi_set_tethering(state):
212 | return technology_set_property(PATH_TECH_WIFI, 'Tethering', (dbussy.DBUS.Signature('b'), state))
213 |
214 |
215 | def technology_wifi_set_tethering_identifier(identifier):
216 | return technology_set_property(PATH_TECH_WIFI, 'TetheringIdentifier', (dbussy.DBUS.Signature('s'), identifier))
217 |
218 |
219 | def technology_wifi_set_tethering_passphrase(passphrase):
220 | return technology_set_property(PATH_TECH_WIFI, 'TetheringPassphrase', (dbussy.DBUS.Signature('s'), passphrase))
221 |
--------------------------------------------------------------------------------
/resources/lib/dbus_obex.py:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: GPL-2.0
2 | # Copyright (C) 2020-present Team LibreELEC (https://libreelec.tv)
3 |
4 | import dbussy
5 | import ravel
6 |
7 | import dbus_utils
8 |
9 |
10 | BUS_NAME = 'org.bluez.obex'
11 | ERROR_REJECTED = 'org.bluez.Error.Rejected'
12 | INTERFACE_AGENT = 'org.bluez.obex.Agent1'
13 | INTERFACE_AGENT_MANAGER = 'org.bluez.obex.AgentManager1'
14 | INTERFACE_TRANSFER = 'org.bluez.obex.Transfer1'
15 | PATH_OBEX = '/org/bluez/obex'
16 | PATH_AGENT = '/kodi/agent/obex'
17 |
18 | @ravel.interface(ravel.INTERFACE.SERVER, name=INTERFACE_AGENT)
19 | class Agent(dbus_utils.Agent):
20 |
21 | def __init__(self):
22 | super().__init__(BUS_NAME, PATH_AGENT)
23 |
24 | def manager_register_agent(self):
25 | dbus_utils.call_method(
26 | BUS_NAME, PATH_OBEX, INTERFACE_AGENT_MANAGER, 'RegisterAgent', PATH_AGENT)
27 |
28 | @ravel.method(
29 | in_signature='',
30 | out_signature=''
31 | )
32 | def Release(self):
33 | pass
34 |
35 | @ravel.method(
36 | in_signature='o',
37 | out_signature='s',
38 | arg_keys=['path'],
39 | result_keyword='reply'
40 | )
41 | def AuthorizePush(self, transfer):
42 | name = self.authorize_push(transfer)
43 | reply[0] = (dbussy.DBUS.Signature('s'), name)
44 |
45 | @ravel.method(
46 | in_signature='',
47 | out_signature=''
48 | )
49 | def Cancel(self):
50 | pass
51 |
52 | def reject(self, message):
53 | raise dbussy.DBusError(ERROR_REJECTED, message)
54 |
55 | class Listener(object):
56 |
57 | def __init__(self):
58 | pass
59 | # dbussy doesn't currenltly support listening for non specific signals
60 | # dbus_utils.BUS.listen_signal(
61 | # interface=INTERFACE_TRANSFER,
62 | # fallback=True,
63 | # func=self._on_transfer_changed,
64 | # path='/')
65 |
66 | # @ravel.signal(name='PropertiesChanged', in_signature='sa{sv}as', arg_keys=('interface', 'changed', 'invalidated'), path_keyword='path', bus_keyword=BUS_NAME)
67 | # async def _on_transfer_changed(self, interface, changed, invalidated, path):
68 | # interface = dbus_utils.convert_from_dbussy(interface)
69 | # changed = dbus_utils.convert_from_dbussy(changed)
70 | # invalidated = dbus_utils.convert_from_dbussy(invalidated)
71 | # await self.on_transfer_changed(interface, changed, invalidated, path)
72 |
73 | def transfer_get_all_properties(path):
74 | return dbus_utils.call_method(BUS_NAME, path, dbussy.DBUS.INTERFACE_PROPERTIES, 'GetAll', INTERFACE_TRANSFER)
75 |
--------------------------------------------------------------------------------
/resources/lib/dbus_utils.py:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: GPL-2.0
2 | # Copyright (C) 2020-present Team LibreELEC (https://libreelec.tv)
3 |
4 | import asyncio
5 | import threading
6 |
7 | import dbussy
8 | import ravel
9 |
10 | import log
11 |
12 |
13 | BUS_NAME = ''
14 | INTERFACE_AGENT = ''
15 | PATH_AGENT = ''
16 |
17 |
18 | class Agent(object):
19 |
20 | def __init__(self, bus_name, path_agent):
21 | self.bus_name = bus_name
22 | self.path_agent = path_agent
23 | if self.bus_name in list_names():
24 | self.register_agent()
25 | self.watch_name()
26 |
27 | @log.log_function()
28 | def watch_name(self):
29 | BUS.listen_signal(
30 | interface=dbussy.DBUS.SERVICE_DBUS,
31 | fallback=True,
32 | func=self.on_name_owner_changed,
33 | path='/',
34 | name='NameOwnerChanged')
35 |
36 | @ravel.signal(name='NameOwnerChanged', in_signature='sss', arg_keys=('name', 'old_owner', 'new_owner'))
37 | async def on_name_owner_changed(self, name, old_owner, new_owner):
38 | if name == self.bus_name and new_owner != '':
39 | self.register_agent()
40 |
41 | @log.log_function()
42 | def register_agent(self):
43 | BUS.request_name(
44 | self.bus_name, flags=dbussy.DBUS.NAME_FLAG_DO_NOT_QUEUE)
45 | BUS.register(
46 | path=self.path_agent, interface=self, fallback=True)
47 | self.manager_register_agent()
48 |
49 | @log.log_function()
50 | def unregister_agent(self):
51 | self.manager_unregister_agent()
52 | BUS.unregister(path=self.path_agent)
53 |
54 | def manager_register_agent(self):
55 | pass
56 |
57 | def manager_unregister_agent(self):
58 | pass
59 |
60 |
61 | class Bool(int):
62 |
63 | def __new__(cls, value):
64 | return int.__new__(cls, bool(value))
65 |
66 | def __str__(self):
67 | return '1' if self == True else '0'
68 |
69 |
70 | class LoopThread(threading.Thread):
71 |
72 | def __init__(self, loop):
73 | super().__init__()
74 | self.loop = loop
75 | self.is_stopped = False
76 |
77 | @log.log_function()
78 | async def wait(self):
79 | while not self.is_stopped:
80 | await asyncio.sleep(1)
81 |
82 | @log.log_function()
83 | def run(self):
84 | self.loop.run_until_complete(self.wait())
85 | self.loop.close()
86 |
87 | @log.log_function()
88 | def stop(self):
89 | self.is_stopped = True
90 | self.join()
91 |
92 |
93 | def list_names():
94 | return BUS[dbussy.DBUS.SERVICE_DBUS]['/'].get_interface(dbussy.DBUS.INTERFACE_DBUS).ListNames()[0]
95 |
96 |
97 | def convert_from_dbussy(data):
98 | if isinstance(data, bool):
99 | return Bool(data)
100 | if isinstance(data, dict):
101 | return {key: convert_from_dbussy(data[key]) for key in data.keys()}
102 | if isinstance(data, list):
103 | return [convert_from_dbussy(item) for item in data]
104 | if isinstance(data, tuple) and isinstance(data[0], dbussy.DBUS.Signature):
105 | return convert_from_dbussy(data[1])
106 | return data
107 |
108 |
109 | def call_method(bus_name, path, interface, method_name, *args, **kwargs):
110 | interface = BUS[bus_name][path].get_interface(interface)
111 | method = getattr(interface, method_name)
112 | result = method(*args, **kwargs)
113 | first = next(iter(result or []), None)
114 | return convert_from_dbussy(first)
115 |
116 |
117 | async def call_async_method(bus_name, path, interface, method_name, *args, **kwargs):
118 | interface = await BUS[bus_name][path].get_async_interface(interface)
119 | method = getattr(interface, method_name)
120 | result = await method(*args, **kwargs)
121 | first = next(iter(result or []), None)
122 | return convert_from_dbussy(first)
123 |
124 |
125 | def run_method(bus_name, path, interface, method_name, *args, **kwargs):
126 | future = asyncio.run_coroutine_threadsafe(call_async_method(
127 | bus_name, path, interface, method_name, *args, **kwargs), LOOP)
128 | return future.result()
129 |
130 |
131 | try:
132 | LOOP = asyncio.get_running_loop()
133 | except RuntimeError:
134 | LOOP = asyncio.new_event_loop()
135 | asyncio.set_event_loop(LOOP)
136 |
137 | BUS = ravel.system_bus()
138 | BUS.attach_asyncio(LOOP)
139 | LOOP_THREAD = LoopThread(LOOP)
140 |
--------------------------------------------------------------------------------
/resources/lib/debug_utils.py:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: GPL-2.0
2 | # Copyright (C) 2020-present Team LibreELEC (https://libreelec.tv)
3 |
4 | import inspect
5 | import sys
6 | from contextlib import contextmanager
7 | from platform import uname
8 | from pprint import pformat
9 | from typing import List, Iterable, Tuple, Any, Optional
10 |
11 | import xbmc
12 |
13 |
14 | def _logger(message):
15 | xbmc.log(message, xbmc.LOGERROR)
16 |
17 |
18 | def format_vars(variables: List[Tuple[str, Any]]) -> str:
19 | """
20 | Format variables dictionary
21 |
22 | :param variables: variables list
23 | :return: formatted string with sorted ``var = val`` pairs
24 | """
25 | var_list = [(var, val) for var, val in variables
26 | if not (var.startswith('__') and var.endswith('__'))]
27 | var_list.sort(key=lambda i: i[0])
28 | lines = []
29 | for var, val in var_list:
30 | lines.append('{} = {}'.format(var, pformat(val, indent=4)))
31 | return '\n'.join(lines)
32 |
33 |
34 | def _format_code_context(code_context: List[str], lineno: int, index: int) -> str:
35 | context = ''
36 | if code_context is not None:
37 | for i, line in enumerate(code_context, lineno - index):
38 | if i == lineno:
39 | context += '{}:>{}'.format(str(i).rjust(5), line)
40 | else:
41 | context += '{}: {}'.format(str(i).rjust(5), line)
42 | return context
43 |
44 |
45 | FRAME_INFO_TEMPLATE = """File:
46 | {file_path}:{lineno}
47 | ----------------------------------------------------------------------------------------------------
48 | Code context:
49 | {code_context}
50 | ----------------------------------------------------------------------------------------------------
51 | Local variables:
52 | {local_vars}
53 | ====================================================================================================
54 | """
55 |
56 |
57 | def format_frame_info(frame_info: tuple) -> str:
58 | """Get extended information about an execution frame"""
59 | return FRAME_INFO_TEMPLATE.format(
60 | file_path=frame_info[1],
61 | lineno=frame_info[2],
62 | code_context=_format_code_context(frame_info[4], frame_info[2],
63 | frame_info[5]),
64 | local_vars=format_vars(frame_info[0].f_locals.items())
65 | )
66 |
67 |
68 | OBJECT_INFO_TEMPLATE = """
69 | ####################################################################################################
70 | Object info
71 | ----------------------------------------------------------------------------------------------------
72 | Object : {object}
73 | Object type : {object_type}
74 | Object attributes:
75 | {object_attributes}
76 | ************************************** End of object info ******************************************
77 | """
78 |
79 |
80 | def inspect_object(obj):
81 | """Get extended information about an object"""
82 | object_attributes = format_vars(inspect.getmembers(obj))
83 | object_info_string = OBJECT_INFO_TEMPLATE.format(
84 | object=obj,
85 | object_type=type(obj),
86 | object_attributes=object_attributes
87 | )
88 | return object_info_string
89 |
90 |
91 | STACK_TRACE_TEMPLATE = """
92 | ####################################################################################################
93 | Stack Trace
94 | ====================================================================================================
95 | {stack_trace}
96 | """
97 |
98 |
99 | def format_stack_trace(frame_stack: Iterable[tuple]) -> str:
100 | """Get extended information about a frame stack"""
101 | stack_trace = ''
102 | for frame_info in frame_stack:
103 | stack_trace += format_frame_info(frame_info)
104 | return STACK_TRACE_TEMPLATE.format(stack_trace=stack_trace)
105 |
106 |
107 | EXCEPTION_TEMPLATE = """
108 | *********************************** Unhandled exception detected ***********************************
109 | ####################################################################################################
110 | Diagnostic info
111 | ----------------------------------------------------------------------------------------------------
112 | Exception type : {exc_type}
113 | Exception value : {exc}
114 | System info : {system_info}
115 | Python version : {python_version}
116 | Kodi version : {kodi_version}
117 | sys.argv : {sys_argv}
118 | ----------------------------------------------------------------------------------------------------
119 | sys.path:
120 | {sys_path}
121 | {stack_trace}
122 | ************************************* End of diagnostic info ***************************************
123 | """
124 |
125 |
126 | def get_exception_message(exc: Exception,
127 | outer_stack_trace: Optional[List[inspect.FrameInfo]] = None) -> str:
128 | """Get extended information about the currently handled exception"""
129 | stack_trace = inspect.trace(5)
130 | if outer_stack_trace is not None:
131 | stack_trace = outer_stack_trace + stack_trace
132 | stack_trace_string = format_stack_trace(stack_trace)
133 | message = EXCEPTION_TEMPLATE.format(
134 | exc_type=exc.__class__.__name__,
135 | exc=exc,
136 | system_info=uname(),
137 | python_version=sys.version.replace('\n', ' '),
138 | kodi_version=xbmc.getInfoLabel('System.BuildVersion'),
139 | sys_argv=sys.argv,
140 | sys_path=pformat(sys.path),
141 | stack_trace=stack_trace_string
142 | )
143 | return message
144 |
145 |
146 | @contextmanager
147 | def log_exception(logger_func=_logger):
148 | """
149 | Diagnostic helper context manager
150 |
151 | It controls execution within its context and writes extended
152 | diagnostic info to the Kodi log if an unhandled exception
153 | happens within the context. The info includes the following items:
154 |
155 | - System info
156 | - Python version
157 | - Kodi version
158 | - Module path.
159 | - Stack trace including:
160 | * File path and line number where the exception happened
161 | * Code fragment where the exception has happened.
162 | * Local variables at the moment of the exception.
163 |
164 | After logging the diagnostic info the exception is re-raised.
165 |
166 | Example::
167 |
168 | with debug_exception():
169 | # Some risky code
170 | raise RuntimeError('Fatal error!')
171 |
172 | :param logger_func: logger function that accepts a single argument
173 | that is a log message.
174 | """
175 | try:
176 | yield
177 | except Exception as exc:
178 | message = get_exception_message(exc)
179 | logger_func(message)
180 | raise exc
181 |
--------------------------------------------------------------------------------
/resources/lib/defaults.py:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: GPL-2.0-or-later
2 | # Copyright (C) 2009-2013 Stephan Raue (stephan@openelec.tv)
3 | # Copyright (C) 2013 Lutz Fiebach (lufie@openelec.tv)
4 | # Copyright (C) 2020-present Team LibreELEC (https://libreelec.tv)
5 |
6 | import os
7 |
8 |
9 | ################################################################################
10 | # Base
11 | ################################################################################
12 |
13 | XBMC_USER_HOME = os.environ.get('XBMC_USER_HOME', '/storage/.kodi')
14 | CONFIG_CACHE = os.environ.get('CONFIG_CACHE', '/storage/.cache')
15 | USER_CONFIG = os.environ.get('USER_CONFIG', '/storage/.config')
16 |
17 | ################################################################################
18 | # Connamn Module
19 | ################################################################################
20 |
21 | connman = {
22 | 'CONNMAN_DAEMON': '/usr/sbin/connmand',
23 | 'WAIT_CONF_FILE': f'{CONFIG_CACHE}/libreelec/network_wait',
24 | 'ENABLED': lambda : (True if os.path.exists(connman['CONNMAN_DAEMON']) and not os.path.exists('/dev/.kernel_ipconfig') else False),
25 | }
26 | connman['ENABLED'] = connman['ENABLED']()
27 |
28 | ################################################################################
29 | # Bluez Module
30 | ################################################################################
31 |
32 | bluetooth = {
33 | 'BLUETOOTH_DAEMON': '/usr/lib/bluetooth/bluetoothd',
34 | 'OBEX_DAEMON': '/usr/lib/bluetooth/obexd',
35 | 'ENABLED': lambda : (True if os.path.exists(bluetooth['BLUETOOTH_DAEMON']) else False),
36 | 'D_OBEXD_ROOT': '/storage/downloads/',
37 | }
38 | bluetooth['ENABLED'] = bluetooth['ENABLED']()
39 |
40 | ################################################################################
41 | # Service Module
42 | ################################################################################
43 |
44 | services = {
45 | 'ENABLED': True,
46 | 'KERNEL_CMD': '/proc/cmdline',
47 | 'SAMBA_NMDB': '/usr/sbin/nmbd',
48 | 'SAMBA_SMDB': '/usr/sbin/smbd',
49 | 'D_SAMBA_WORKGROUP': 'WORKGROUP',
50 | 'D_SAMBA_SECURE': '0',
51 | 'D_SAMBA_USERNAME': 'libreelec',
52 | 'D_SAMBA_PASSWORD': 'libreelec',
53 | 'D_SAMBA_MINPROTOCOL': 'SMB2',
54 | 'D_SAMBA_MAXPROTOCOL': 'SMB3',
55 | 'D_SAMBA_AUTOSHARE': '1',
56 | 'SSH_DAEMON': '/usr/sbin/sshd',
57 | 'OPT_SSH_NOPASSWD': "-o 'PasswordAuthentication no'",
58 | 'D_SSH_DISABLE_PW_AUTH': '0',
59 | 'AVAHI_DAEMON': '/usr/sbin/avahi-daemon',
60 | 'CRON_DAEMON': '/sbin/crond',
61 | }
62 |
63 | system = {
64 | 'ENABLED': True,
65 | 'KERNEL_CMD': '/proc/cmdline',
66 | 'SET_CLOCK_CMD': '/sbin/hwclock --systohc --utc',
67 | 'XBMC_RESET_FILE': f'{CONFIG_CACHE}/reset_soft',
68 | 'LIBREELEC_RESET_FILE': f'{CONFIG_CACHE}/reset_hard',
69 | 'KEYBOARD_INFO': '/usr/share/X11/xkb/rules/base.xml',
70 | 'UDEV_KEYBOARD_INFO': f'{CONFIG_CACHE}/xkb/layout',
71 | 'NOX_KEYBOARD_INFO': '/usr/lib/keymaps',
72 | 'BACKUP_DIRS': [
73 | XBMC_USER_HOME,
74 | USER_CONFIG,
75 | CONFIG_CACHE,
76 | '/storage/.ssh',
77 | ],
78 | 'BACKUP_FILTER' : [
79 | f'{XBMC_USER_HOME}/addons/packages',
80 | f'{XBMC_USER_HOME}/addons/temp',
81 | f'{XBMC_USER_HOME}/temp'
82 | ],
83 | 'BACKUP_DESTINATION': '/storage/backup/',
84 | 'RESTORE_DIR': '/storage/.restore/',
85 | 'JOURNALD_CONFIG_FILE': '/storage/.cache/journald.conf.d/00_settings.conf'
86 | }
87 |
88 | updates = {
89 | 'ENABLED': not os.path.exists('/dev/.update_disabled'),
90 | 'UPDATE_REQUEST_URL': 'https://update.libreelec.tv/updates.php',
91 | 'UPDATE_DOWNLOAD_URL': 'http://%s.libreelec.tv/%s',
92 | 'LOCAL_UPDATE_DIR': '/storage/.update/',
93 | }
94 |
95 | about = {'ENABLED': True}
96 |
97 | _services = {
98 | 'sshd': ['sshd.service'],
99 | 'avahi': ['avahi-daemon.service'],
100 | 'samba': ['samba-config.service', 'nmbd.service', 'smbd.service'],
101 | 'bluez': ['bluetooth.service'],
102 | 'obexd': ['obex.service'],
103 | 'crond': ['cron.service'],
104 | 'iptables': ['iptables.service'],
105 | }
106 |
--------------------------------------------------------------------------------
/resources/lib/hostname.py:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: GPL-2.0
2 | # Copyright (C) 2020-present Team LibreELEC (https://libreelec.tv)
3 |
4 | import os
5 |
6 | import config
7 | import os_tools
8 |
9 |
10 | def get_hostname():
11 | return os_tools.read_shell_setting(config.HOSTNAME, config.OS_RELEASE['NAME'])
12 |
13 |
14 | def set_hostname(hostname):
15 | # network-base.service handles user created persistent settings
16 | current_hostname = get_hostname()
17 | if current_hostname != hostname or not os.path.isfile(config.HOSTNAME):
18 | with open(config.HOSTNAME, mode='w', encoding='utf-8') as out_file:
19 | out_file.write(f'{hostname}\n')
20 | os_tools.execute('systemctl restart network-base')
21 | os_tools.execute('systemctl try-restart avahi-daemon wsdd2')
22 |
--------------------------------------------------------------------------------
/resources/lib/log.py:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: GPL-2.0
2 | # Copyright (C) 2020-present Team LibreELEC (https://libreelec.tv)
3 |
4 | import inspect
5 | import os
6 | import pprint
7 | import sys
8 | from functools import wraps
9 |
10 | from debug_utils import get_exception_message, format_stack_trace, inspect_object
11 |
12 |
13 | DEBUG = 0
14 | INFO = 1
15 | WARNING = 2
16 | ERROR = 3
17 | FATAL = 4
18 | NONE = 5
19 |
20 | _DEFAULT = DEBUG
21 | _HEADER = 'SETTINGS: '
22 |
23 |
24 | try:
25 | import xbmc
26 | _NO_DEBUG_ENV = os.environ.get('DEBUG', 'no') == 'no'
27 | def _log(message, level=_DEFAULT):
28 | if level == DEBUG and _NO_DEBUG_ENV:
29 | return
30 | xbmc.log(message, level)
31 | except ModuleNotFoundError:
32 | def _log(message, level=_DEFAULT):
33 | print(message)
34 |
35 |
36 | def log(message, level=_DEFAULT):
37 | _log(f'{_HEADER}{sys._getframe().f_back.f_code.co_name} # {message}', level)
38 |
39 |
40 | def log_stack_trace(message='', level=_DEFAULT):
41 | """
42 | Log extended stack trace from the point of execution to the starting frame
43 |
44 | The stack trace includes code fragments (if available) and local variables for each frame.
45 | """
46 | message = _HEADER + message
47 | frame_stack = list(reversed(inspect.stack(5)))[:-1]
48 | stack_trace_string = format_stack_trace(frame_stack)
49 | if message:
50 | message += '\n' + stack_trace_string
51 | _log(_HEADER + message, level)
52 |
53 |
54 | def log_object_state(obj, level=_DEFAULT):
55 | """Log all object attributes"""
56 | object_info_string = inspect_object(obj)
57 | _log(_HEADER + object_info_string, level)
58 |
59 |
60 | def log_function(level=_DEFAULT):
61 | def _log_function_1(function):
62 | header = f'{_HEADER}{function.__qualname__} '
63 | @wraps(function)
64 | def _log_function_2(*args, **kwargs):
65 | try:
66 | _log(f'{header}-', level)
67 | for arg in args:
68 | _log(f'{header}< {pprint.pformat(arg)}', level)
69 | for key, value in kwargs.items():
70 | _log(f'{header}< {key}={pprint.pformat(value)}', level)
71 | result = function(*args, **kwargs)
72 | _log(f'{header}> {pprint.pformat(result)}', level)
73 | return result
74 | except Exception as e:
75 | _log(f'{header}# {repr(e)}', ERROR)
76 | outer_stack = list(reversed(inspect.stack(5)))[:-1]
77 | exception_message = get_exception_message(e, outer_stack)
78 | _log(header + exception_message, ERROR)
79 | if 'self' in inspect.getfullargspec(function).args and args:
80 | obj = args[0]
81 | object_state = inspect_object(obj)
82 | _log(header + object_state, ERROR)
83 | e.__traceback__ = None
84 | return _log_function_2
85 | return _log_function_1
86 |
87 |
88 | def utf8ify(pstr):
89 | return pstr.encode('utf-8', 'replace').decode('utf-8')
90 |
91 | def asciify(pstr):
92 | return pstr.encode('ascii', 'replace').decode('utf-8')
93 |
--------------------------------------------------------------------------------
/resources/lib/modules.py:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: GPL-2.0
2 | # Copyright (C) 2020-present Team LibreELEC (https://libreelec.tv)
3 |
4 | import defaults
5 | import log
6 |
7 |
8 | class Module(object):
9 |
10 | @log.log_function()
11 | def __init__(self):
12 | name = self.__class__.__name__
13 | settings = getattr(defaults, name, None)
14 | if settings:
15 | for key, value in settings.items():
16 | setattr(self, key, value)
17 | log.log(f'{name}.{key}={value}')
18 |
19 | def do_init(self):
20 | pass
21 |
22 | def exit(self):
23 | pass
24 |
25 | def start_service(self):
26 | pass
27 |
28 | def stop_service(self):
29 | pass
30 |
--------------------------------------------------------------------------------
/resources/lib/modules/about.py:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: GPL-2.0-or-later
2 | # Copyright (C) 2009-2013 Stephan Raue (stephan@openelec.tv)
3 | # Copyright (C) 2013 Lutz Fiebach (lufie@openelec.tv)
4 | # Copyright (C) 2019-present Team LibreELEC (https://libreelec.tv)
5 |
6 | import log
7 | import oe
8 |
9 |
10 | class about:
11 |
12 | ENABLED = False
13 | menu = {'99': {
14 | 'name': 32196,
15 | 'menuLoader': 'menu_loader',
16 | 'listTyp': 'other',
17 | 'InfoText': 705,
18 | }}
19 |
20 | @log.log_function()
21 | def __init__(self, oeMain):
22 | super().__init__()
23 | self.controls = {}
24 |
25 | @log.log_function()
26 | def menu_loader(self, menuItem):
27 | pass
28 |
29 | @log.log_function()
30 | def exit_addon(self):
31 | oe.winOeMain.close()
32 |
33 | @log.log_function()
34 | def init_controls(self):
35 | pass
36 |
37 | @log.log_function()
38 | def exit(self):
39 | for control in self.controls:
40 | try:
41 | oe.winOeMain.removeControl(self.controls[control])
42 | finally:
43 | self.controls = {}
44 |
45 | @log.log_function()
46 | def do_wizard(self):
47 | oe.winOeMain.set_wizard_title(oe._(32317))
48 | oe.winOeMain.set_wizard_text(oe._(32318))
49 |
--------------------------------------------------------------------------------
/resources/lib/modules/services.py:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: GPL-2.0-or-later
2 | # Copyright (C) 2009-2013 Stephan Raue (stephan@openelec.tv)
3 | # Copyright (C) 2013 Lutz Fiebach (lufie@openelec.tv)
4 | # Copyright (C) 2019-present Team LibreELEC (https://libreelec.tv)
5 |
6 | import os
7 | import shutil
8 | import subprocess
9 |
10 | import xbmcgui
11 |
12 | import log
13 | import modules
14 | import oe
15 |
16 |
17 | xbmcDialog = xbmcgui.Dialog()
18 |
19 | class services(modules.Module):
20 |
21 | ENABLED = False
22 | SAMBA_NMDB = None
23 | SAMBA_SMDB = None
24 | D_SAMBA_SECURE = None
25 | D_SAMBA_WORKGROUP = None
26 | D_SAMBA_USERNAME = None
27 | D_SAMBA_PASSWORD = None
28 | D_SAMBA_MINPROTOCOL = None
29 | D_SAMBA_MAXPROTOCOL = None
30 | D_SAMBA_AUTOSHARE = None
31 | KERNEL_CMD = None
32 | SSH_DAEMON = None
33 | D_SSH_DISABLE_PW_AUTH = None
34 | OPT_SSH_NOPASSWD = None
35 | AVAHI_DAEMON = None
36 | CRON_DAEMON = None
37 | menu = {'7': {
38 | 'name': 32001,
39 | 'menuLoader': 'load_menu',
40 | 'listTyp': 'list',
41 | 'InfoText': 703,
42 | }}
43 |
44 | @log.log_function()
45 | def __init__(self, oeMain):
46 | super().__init__()
47 | self.struct = {
48 | 'samba': {
49 | 'order': 1,
50 | 'name': 32200,
51 | 'not_supported': [],
52 | 'settings': {
53 | 'samba_autostart': {
54 | 'order': 1,
55 | 'name': 32204,
56 | 'value': None,
57 | 'action': 'initialize_samba',
58 | 'type': 'bool',
59 | 'InfoText': 738,
60 | },
61 | 'samba_workgroup': {
62 | 'order': 2,
63 | 'name': 32215,
64 | 'value': "WORKGROUP",
65 | 'action': 'initialize_samba',
66 | 'type': 'text',
67 | 'parent': {
68 | 'entry': 'samba_autostart',
69 | 'value': ['1'],
70 | },
71 | 'InfoText': 758,
72 | },
73 | 'samba_secure': {
74 | 'order': 3,
75 | 'name': 32202,
76 | 'value': None,
77 | 'action': 'initialize_samba',
78 | 'type': 'bool',
79 | 'parent': {
80 | 'entry': 'samba_autostart',
81 | 'value': ['1'],
82 | },
83 | 'InfoText': 739,
84 | },
85 | 'samba_username': {
86 | 'order': 4,
87 | 'name': 32106,
88 | 'value': None,
89 | 'action': 'initialize_samba',
90 | 'type': 'text',
91 | 'parent': {
92 | 'entry': 'samba_secure',
93 | 'value': ['1'],
94 | },
95 | 'InfoText': 740,
96 | },
97 | 'samba_password': {
98 | 'order': 5,
99 | 'name': 32107,
100 | 'value': None,
101 | 'action': 'initialize_samba',
102 | 'type': 'text',
103 | 'parent': {
104 | 'entry': 'samba_secure',
105 | 'value': ['1'],
106 | },
107 | 'InfoText': 741,
108 | },
109 | 'samba_minprotocol': {
110 | 'order': 6,
111 | 'name': 32217,
112 | 'value': 'SMB2',
113 | 'action': 'initialize_samba',
114 | 'type': 'multivalue',
115 | 'values': [
116 | 'SMB1',
117 | 'SMB2',
118 | 'SMB3',
119 | ],
120 | 'parent': {
121 | 'entry': 'samba_autostart',
122 | 'value': ['1'],
123 | },
124 | 'InfoText': 756,
125 | },
126 | 'samba_maxprotocol': {
127 | 'order': 7,
128 | 'name': 32218,
129 | 'value': 'SMB3',
130 | 'action': 'initialize_samba',
131 | 'type': 'multivalue',
132 | 'values': [
133 | 'SMB1',
134 | 'SMB2',
135 | 'SMB3',
136 | ],
137 | 'parent': {
138 | 'entry': 'samba_autostart',
139 | 'value': ['1'],
140 | },
141 | 'InfoText': 757,
142 | },
143 | 'samba_autoshare': {
144 | 'order': 8,
145 | 'name': 32216,
146 | 'value': None,
147 | 'action': 'initialize_samba',
148 | 'type': 'bool',
149 | 'parent': {
150 | 'entry': 'samba_autostart',
151 | 'value': ['1'],
152 | },
153 | 'InfoText': 755,
154 | },
155 | },
156 | },
157 | 'ssh': {
158 | 'order': 2,
159 | 'name': 32201,
160 | 'not_supported': [],
161 | 'settings': {
162 | 'ssh_autostart': {
163 | 'order': 1,
164 | 'name': 32205,
165 | 'value': None,
166 | 'action': 'initialize_ssh',
167 | 'type': 'bool',
168 | 'InfoText': 742,
169 | },
170 | 'ssh_secure': {
171 | 'order': 2,
172 | 'name': 32203,
173 | 'value': None,
174 | 'action': 'initialize_ssh',
175 | 'type': 'bool',
176 | 'parent': {
177 | 'entry': 'ssh_autostart',
178 | 'value': ['1'],
179 | },
180 | 'InfoText': 743,
181 | },
182 | 'ssh_passwd': {
183 | 'order': 3,
184 | 'name': 32209,
185 | 'value': None,
186 | 'action': 'do_sshpasswd',
187 | 'type': 'button',
188 | 'parent': {
189 | 'entry': 'ssh_secure',
190 | 'value': ['0'],
191 | },
192 | 'InfoText': 746,
193 | },
194 | },
195 | },
196 | 'avahi': {
197 | 'order': 3,
198 | 'name': 32207,
199 | 'not_supported': [],
200 | 'settings': {'avahi_autostart': {
201 | 'order': 1,
202 | 'name': 32206,
203 | 'value': None,
204 | 'action': 'initialize_avahi',
205 | 'type': 'bool',
206 | 'InfoText': 744,
207 | }},
208 | },
209 | 'cron': {
210 | 'order': 4,
211 | 'name': 32319,
212 | 'not_supported': [],
213 | 'settings': {'cron_autostart': {
214 | 'order': 1,
215 | 'name': 32320,
216 | 'value': None,
217 | 'action': 'initialize_cron',
218 | 'type': 'bool',
219 | 'InfoText': 745,
220 | }},
221 | },
222 | 'bluez': {
223 | 'order': 6,
224 | 'name': 32331,
225 | 'not_supported': [],
226 | 'settings': {
227 | 'enabled': {
228 | 'order': 1,
229 | 'name': 32344,
230 | 'value': None,
231 | 'action': 'initialize_bluetooth',
232 | 'type': 'bool',
233 | 'InfoText': 720,
234 | },
235 | 'obex_enabled': {
236 | 'order': 2,
237 | 'name': 32384,
238 | 'value': None,
239 | 'action': 'initialize_obex',
240 | 'type': 'bool',
241 | 'parent': {
242 | 'entry': 'enabled',
243 | 'value': ['1'],
244 | },
245 | 'InfoText': 751,
246 | },
247 | 'obex_root': {
248 | 'order': 3,
249 | 'name': 32385,
250 | 'value': None,
251 | 'action': 'initialize_obex',
252 | 'type': 'folder',
253 | 'parent': {
254 | 'entry': 'obex_enabled',
255 | 'value': ['1'],
256 | },
257 | 'InfoText': 752,
258 | },
259 | 'idle_timeout': {
260 | 'order': 4,
261 | 'name': 32400,
262 | 'value': None,
263 | 'action': 'idle_timeout',
264 | 'type': 'multivalue',
265 | 'values': [
266 | '0',
267 | '1',
268 | '3',
269 | '5',
270 | '15',
271 | '30',
272 | '60',
273 | ],
274 | 'parent': {
275 | 'entry': 'enabled',
276 | 'value': ['1'],
277 | },
278 | 'InfoText': 773,
279 | },
280 | },
281 | },
282 | }
283 |
284 | @log.log_function()
285 | def start_service(self):
286 | self.load_values()
287 | self.initialize_samba(service=1)
288 | self.initialize_ssh(service=1)
289 | self.initialize_avahi(service=1)
290 | self.initialize_cron(service=1)
291 | self.initialize_bluetooth(service=1)
292 |
293 | @log.log_function()
294 | def do_init(self):
295 | self.load_values()
296 |
297 | @log.log_function()
298 | def set_value(self, listItem):
299 | self.struct[listItem.getProperty('category')]['settings'][listItem.getProperty('entry')]['value'] = listItem.getProperty('value')
300 |
301 | @log.log_function()
302 | def load_menu(self, focusItem):
303 | oe.winOeMain.build_menu(self.struct)
304 |
305 | @log.log_function()
306 | def load_values(self):
307 | # SAMBA
308 | if os.path.isfile(self.SAMBA_NMDB) and os.path.isfile(self.SAMBA_SMDB):
309 | self.struct['samba']['settings']['samba_autostart']['value'] = oe.get_service_state('samba')
310 | self.struct['samba']['settings']['samba_workgroup']['value'] = oe.get_service_option('samba', 'SAMBA_WORKGROUP',
311 | self.D_SAMBA_WORKGROUP).replace('"', '')
312 | self.struct['samba']['settings']['samba_secure']['value'] = oe.get_service_option('samba', 'SAMBA_SECURE',
313 | self.D_SAMBA_SECURE).replace('true', '1').replace('false', '0').replace('"', '')
314 | self.struct['samba']['settings']['samba_username']['value'] = self.sh_unesc_str(oe.get_service_option('samba', 'SAMBA_USERNAME',
315 | self.D_SAMBA_USERNAME).replace('"', ''))
316 | self.struct['samba']['settings']['samba_password']['value'] = self.sh_unesc_str(oe.get_service_option('samba', 'SAMBA_PASSWORD',
317 | self.D_SAMBA_PASSWORD).replace('"', ''))
318 | self.struct['samba']['settings']['samba_minprotocol']['value'] = oe.get_service_option('samba', 'SAMBA_MINPROTOCOL',
319 | self.D_SAMBA_MINPROTOCOL).replace('"', '')
320 | self.struct['samba']['settings']['samba_maxprotocol']['value'] = oe.get_service_option('samba', 'SAMBA_MAXPROTOCOL',
321 | self.D_SAMBA_MAXPROTOCOL).replace('"', '')
322 | self.struct['samba']['settings']['samba_autoshare']['value'] = oe.get_service_option('samba', 'SAMBA_AUTOSHARE',
323 | self.D_SAMBA_AUTOSHARE).replace('true', '1').replace('false', '0').replace('"', '')
324 | else:
325 | self.struct['samba']['hidden'] = 'true'
326 | # SSH
327 | if os.path.isfile(self.SSH_DAEMON):
328 | self.struct['ssh']['settings']['ssh_autostart']['value'] = oe.get_service_state('sshd')
329 | self.struct['ssh']['settings']['ssh_secure']['value'] = oe.get_service_option('sshd', 'SSHD_DISABLE_PW_AUTH',
330 | self.D_SSH_DISABLE_PW_AUTH).replace('true', '1').replace('false', '0').replace('"', '')
331 | # hide ssh settings if Kernel Parameter is set
332 | with open(self.KERNEL_CMD, 'r') as cmd_file:
333 | cmd_args = cmd_file.read().split(' ')
334 | if 'ssh' in cmd_args:
335 | self.struct['ssh']['settings']['ssh_autostart']['value'] = '1'
336 | self.struct['ssh']['settings']['ssh_autostart']['hidden'] = 'true'
337 | else:
338 | self.struct['ssh']['hidden'] = 'true'
339 | # AVAHI
340 | if os.path.isfile(self.AVAHI_DAEMON):
341 | self.struct['avahi']['settings']['avahi_autostart']['value'] = oe.get_service_state('avahi')
342 | else:
343 | self.struct['avahi']['hidden'] = 'true'
344 | # CRON
345 | if os.path.isfile(self.CRON_DAEMON):
346 | self.struct['cron']['settings']['cron_autostart']['value'] = oe.get_service_state('crond')
347 | else:
348 | self.struct['cron']['hidden'] = 'true'
349 | # BLUEZ / OBEX
350 | if 'bluetooth' in oe.dictModules:
351 | if os.path.isfile(oe.dictModules['bluetooth'].BLUETOOTH_DAEMON):
352 | self.struct['bluez']['settings']['enabled']['value'] = oe.get_service_state('bluez')
353 | if os.path.isfile(oe.dictModules['bluetooth'].OBEX_DAEMON):
354 | self.struct['bluez']['settings']['obex_enabled']['value'] = oe.get_service_state('obexd')
355 | self.struct['bluez']['settings']['obex_root']['value'] = oe.get_service_option('obexd', 'OBEXD_ROOT',
356 | oe.dictModules['bluetooth'].D_OBEXD_ROOT).replace('"', '')
357 | else:
358 | self.struct['bluez']['settings']['obex_enabled']['hidden'] = True
359 | self.struct['bluez']['settings']['obex_root']['hidden'] = True
360 |
361 | value = oe.read_setting('bluetooth', 'idle_timeout')
362 | if not value:
363 | value = '0'
364 | self.struct['bluez']['settings']['idle_timeout']['value'] = oe.read_setting('bluetooth', 'idle_timeout')
365 | else:
366 | self.struct['bluez']['hidden'] = 'true'
367 |
368 | @log.log_function()
369 | def initialize_samba(self, **kwargs):
370 | if 'listItem' in kwargs:
371 | self.set_value(kwargs['listItem'])
372 | options = {}
373 | if self.struct['samba']['settings']['samba_autostart']['value'] == '1':
374 | state = 1
375 | if 'hidden' in self.struct['samba']['settings']['samba_username']:
376 | del self.struct['samba']['settings']['samba_username']['hidden']
377 | if 'hidden' in self.struct['samba']['settings']['samba_password']:
378 | del self.struct['samba']['settings']['samba_password']['hidden']
379 | if self.struct['samba']['settings']['samba_secure']['value'] == '1':
380 | val_secure = 'true'
381 | else:
382 | val_secure = 'false'
383 | if self.struct['samba']['settings']['samba_autoshare']['value'] == '1':
384 | val_autoshare = 'true'
385 | else:
386 | val_autoshare = 'false'
387 | options['SAMBA_WORKGROUP'] = self.struct['samba']['settings']['samba_workgroup']['value']
388 | options['SAMBA_SECURE'] = val_secure
389 | options['SAMBA_AUTOSHARE'] = val_autoshare
390 | options['SAMBA_MINPROTOCOL'] = self.struct['samba']['settings']['samba_minprotocol']['value']
391 | options['SAMBA_MAXPROTOCOL'] = self.struct['samba']['settings']['samba_maxprotocol']['value']
392 | options['SAMBA_USERNAME'] = self.sh_esc_str(self.struct['samba']['settings']['samba_username']['value'])
393 | options['SAMBA_PASSWORD'] = self.sh_esc_str(self.struct['samba']['settings']['samba_password']['value'])
394 | else:
395 | state = 0
396 | self.struct['samba']['settings']['samba_username']['hidden'] = True
397 | self.struct['samba']['settings']['samba_password']['hidden'] = True
398 | oe.set_service('samba', options, state)
399 |
400 | @log.log_function()
401 | def initialize_ssh(self, **kwargs):
402 | if 'listItem' in kwargs:
403 | self.set_value(kwargs['listItem'])
404 | options = {}
405 | if self.struct['ssh']['settings']['ssh_autostart']['value'] == '1':
406 | state = 1
407 | if self.struct['ssh']['settings']['ssh_secure']['value'] == '1':
408 | val = 'true'
409 | options['SSH_ARGS'] = self.OPT_SSH_NOPASSWD
410 | else:
411 | val = 'false'
412 | options['SSH_ARGS'] = '""'
413 | options['SSHD_DISABLE_PW_AUTH'] = val
414 | else:
415 | state = 0
416 | oe.set_service('sshd', options, state)
417 |
418 | @log.log_function()
419 | def initialize_avahi(self, **kwargs):
420 | if 'listItem' in kwargs:
421 | self.set_value(kwargs['listItem'])
422 | options = {}
423 | if self.struct['avahi']['settings']['avahi_autostart']['value'] == '1':
424 | state = 1
425 | else:
426 | state = 0
427 | oe.set_service('avahi', options, state)
428 |
429 | @log.log_function()
430 | def initialize_cron(self, **kwargs):
431 | if 'listItem' in kwargs:
432 | self.set_value(kwargs['listItem'])
433 | options = {}
434 | if self.struct['cron']['settings']['cron_autostart']['value'] == '1':
435 | state = 1
436 | else:
437 | state = 0
438 | oe.set_service('crond', options, state)
439 |
440 | @log.log_function()
441 | def initialize_bluetooth(self, **kwargs):
442 | if 'listItem' in kwargs:
443 | self.set_value(kwargs['listItem'])
444 | options = {}
445 | if self.struct['bluez']['settings']['enabled']['value'] == '1':
446 | state = 1
447 | if 'hidden' in self.struct['bluez']['settings']['obex_enabled']:
448 | del self.struct['bluez']['settings']['obex_enabled']['hidden']
449 | if 'hidden' in self.struct['bluez']['settings']['obex_root']:
450 | del self.struct['bluez']['settings']['obex_root']['hidden']
451 | else:
452 | state = 0
453 | self.struct['bluez']['settings']['obex_enabled']['hidden'] = True
454 | self.struct['bluez']['settings']['obex_root']['hidden'] = True
455 | oe.set_service('bluez', options, state)
456 |
457 | @log.log_function()
458 | def initialize_obex(self, **kwargs):
459 | if 'listItem' in kwargs:
460 | self.set_value(kwargs['listItem'])
461 | options = {}
462 | if self.struct['bluez']['settings']['obex_enabled']['value'] == '1':
463 | state = 1
464 | options['OBEXD_ROOT'] = self.struct['bluez']['settings']['obex_root']['value']
465 | else:
466 | state = 0
467 | oe.set_service('obexd', options, state)
468 |
469 | @log.log_function()
470 | def idle_timeout(self, **kwargs):
471 | if 'listItem' in kwargs:
472 | self.set_value(kwargs['listItem'])
473 | oe.write_setting('bluetooth', 'idle_timeout', self.struct['bluez']['settings']['idle_timeout']['value'])
474 |
475 | @log.log_function()
476 | def do_wizard(self):
477 | oe.winOeMain.set_wizard_title(oe._(32311))
478 |
479 | # Enable samba
480 | self.struct['samba']['settings']['samba_autostart']['value'] = '1'
481 | self.initialize_samba()
482 |
483 | if hasattr(self, 'samba'):
484 | oe.winOeMain.set_wizard_text(f'{oe._(32313)}[CR][CR]{oe._(32312)}')
485 | else:
486 | oe.winOeMain.set_wizard_text(oe._(32312))
487 | oe.winOeMain.set_wizard_button_title(oe._(32316))
488 | self.set_wizard_buttons()
489 |
490 | @log.log_function()
491 | def set_wizard_buttons(self):
492 | if self.struct['ssh']['settings']['ssh_autostart']['value'] == '1':
493 | oe.winOeMain.set_wizard_radiobutton_1(oe._(32201), self, 'wizard_set_ssh', True)
494 | else:
495 | oe.winOeMain.set_wizard_radiobutton_1(oe._(32201), self, 'wizard_set_ssh')
496 | if not 'hidden' in self.struct['samba']:
497 | if self.struct['samba']['settings']['samba_autostart']['value'] == '1':
498 | oe.winOeMain.set_wizard_radiobutton_2(oe._(32200), self, 'wizard_set_samba', True)
499 | else:
500 | oe.winOeMain.set_wizard_radiobutton_2(oe._(32200), self, 'wizard_set_samba')
501 |
502 | @log.log_function()
503 | def wizard_set_ssh(self):
504 | if self.struct['ssh']['settings']['ssh_autostart']['value'] == '1':
505 | self.struct['ssh']['settings']['ssh_autostart']['value'] = '0'
506 | else:
507 | self.struct['ssh']['settings']['ssh_autostart']['value'] = '1'
508 | # ssh button does nothing if "ssh" set on kernel commandline
509 | with open(self.KERNEL_CMD, 'r') as cmd_file:
510 | cmd_args = cmd_file.read().split(' ')
511 | if 'ssh' in cmd_args:
512 | oe.notify('ssh', 'ssh enabled as boot parameter. can not disable')
513 | self.initialize_ssh()
514 | self.load_values()
515 | if self.struct['ssh']['settings']['ssh_autostart']['value'] == '1':
516 | self.wizard_sshpasswd()
517 | self.set_wizard_buttons()
518 |
519 | @log.log_function()
520 | def wizard_set_samba(self):
521 | if self.struct['samba']['settings']['samba_autostart']['value'] == '1':
522 | self.struct['samba']['settings']['samba_autostart']['value'] = '0'
523 | else:
524 | self.struct['samba']['settings']['samba_autostart']['value'] = '1'
525 | self.initialize_samba()
526 | self.load_values()
527 | self.set_wizard_buttons()
528 |
529 | @log.log_function()
530 | def wizard_sshpasswd(self):
531 | SSHresult = False
532 | while SSHresult == False:
533 | changeSSH = xbmcDialog.yesno(oe._(32209), oe._(32210), yeslabel=oe._(32213), nolabel=oe._(32214))
534 | if changeSSH:
535 | SSHresult = True
536 | else:
537 | changeSSHresult = self.do_sshpasswd()
538 | if changeSSHresult:
539 | SSHresult = True
540 | return
541 |
542 | @log.log_function()
543 | def do_sshpasswd(self, **kwargs):
544 | SSHchange = False
545 | newpwd = xbmcDialog.input(oe._(746))
546 | if newpwd:
547 | if newpwd == "libreelec":
548 | if os.path.isfile('/storage/.cache/shadow'):
549 | os.remove('/storage/.cache/shadow')
550 | shutil.copy2('/usr/cache/shadow', '/storage/.cache/shadow')
551 | readout3 = "Retype password"
552 | else:
553 | ssh = subprocess.Popen(["passwd"], shell=False, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, bufsize=0)
554 | readout1 = ssh.stdout.readline()
555 | ssh.stdin.write(f'{newpwd}\n')
556 | readout2 = ssh.stdout.readline()
557 | ssh.stdin.write(f'{newpwd}\n')
558 | readout3 = ssh.stdout.readline()
559 | if "Bad password" in readout3:
560 | xbmcDialog.ok(oe._(32220), oe._(32221))
561 | log.log('Password too weak')
562 | return
563 | elif "Retype password" in readout3:
564 | xbmcDialog.ok(oe._(32222), oe._(32223))
565 | SSHchange = True
566 | else:
567 | xbmcDialog.ok(oe._(32224), oe._(32225))
568 | else:
569 | log.log('User cancelled')
570 | return SSHchange
571 |
572 | def sh_esc_str(self, string):
573 | escape = ''
574 | for c in string:
575 | escape += '\\' + c
576 | return escape
577 |
578 | def sh_unesc_str(self, string):
579 | size = len(string)
580 | if size % 2:
581 | return string
582 | if string[0::2] != '\\' * (size // 2):
583 | return string
584 | return string[1::2]
585 |
--------------------------------------------------------------------------------
/resources/lib/os_tools.py:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: GPL-2.0
2 | # Copyright (C) 2020-present Team LibreELEC (https://libreelec.tv)
3 |
4 | '''This module holds support functions for interacting with the underlying OS.
5 |
6 | Support functions are grouped by purpose:
7 | 1. File access: read / write / copy / move / download
8 | 2. System access: executing system commands
9 | '''
10 |
11 | import os
12 | import subprocess
13 |
14 | import log
15 |
16 |
17 | ### FILE ACCESS ###
18 | def read_shell_setting(file, default=None):
19 | '''Read the first line of a file as the setting'''
20 | setting = default if default else ''
21 | if os.path.isfile(file):
22 | with open(file, mode='r', encoding='utf-8') as data:
23 | setting = data.readline().strip()
24 | # ignore comments
25 | if setting.startswith('#'):
26 | setting = default if default else ''
27 | else:
28 | log.log(f'File not found: {file}', log.DEBUG)
29 | return setting
30 |
31 |
32 | def read_shell_settings(file, defaults=None):
33 | '''Parse settings from text file, placing each value into a dictionary'''
34 | settings = defaults if defaults else {}
35 | if os.path.isfile(file):
36 | with open(file, mode='r', encoding='utf-8') as data:
37 | for line in data:
38 | line = line.strip()
39 | # ignore comments
40 | if not line.startswith('#'):
41 | name, value = line.split('=', 1)
42 | # remove quotes
43 | if value:
44 | value = value.removeprefix('"').removesuffix('"')
45 | settings[name] = value
46 | else:
47 | log.log(f'File not found: {file}', log.DEBUG)
48 | return settings
49 |
50 |
51 | ### SYSTEM ACCESS ###
52 | def execute(command, get_result=False, output_err_msg=True):
53 | '''Run command, waiting for it to finish. Returns: command output, empty string or None'''
54 | log.log(f'Executing command: {command}', log.DEBUG)
55 | try:
56 | cmd_status = subprocess.run(command, shell=True, check=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
57 | except subprocess.CalledProcessError as e:
58 | if output_err_msg:
59 | log.log(f'Command failed: {command}', log.ERROR)
60 | log.log(f'Executed command: {e.cmd}', log.DEBUG)
61 | log.log(f'\nSTART COMMAND OUTPUT:\n{e.stdout.decode()}\nEND COMMAND OUTPUT', log.ERROR)
62 | # return empty string if result wanted to match old behaviour
63 | return '' if get_result else None
64 | # return output if requested, otherwise return None
65 | return cmd_status.stdout.decode() if get_result else None
66 |
--------------------------------------------------------------------------------
/resources/lib/regdomain.py:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: GPL-2.0
2 | # Copyright (C) 2020-present Team LibreELEC (https://libreelec.tv)
3 |
4 | import os
5 |
6 | import config
7 | import os_tools
8 |
9 |
10 | REGDOMAIN_DEFAULT = 'NOT SET (DEFAULT)'
11 | REGDOMAIN_LIST = [REGDOMAIN_DEFAULT] + [
12 | "GLOBAL (00)",
13 | "Afghanistan (AF)",
14 | "Albania (AL)",
15 | "Algeria (DZ)",
16 | "American Samoa (AS)",
17 | "Andorra (AD)",
18 | "Anguilla (AI)",
19 | "Argentina (AR)",
20 | "Armenia (AM)",
21 | "Aruba (AW)",
22 | "Australia (AU)",
23 | "Austria (AT)",
24 | "Azerbaijan (AZ)",
25 | "Bahamas (BS)",
26 | "Bahrain (BH)",
27 | "Bangladesh (BD)",
28 | "Barbados (BB)",
29 | "Belarus (BY)",
30 | "Belgium (BE)",
31 | "Belize (BZ)",
32 | "Bermuda (BM)",
33 | "Bhutan (BT)",
34 | "Bolivia (BO)",
35 | "Bosnia and Herzegovina (BA)",
36 | "Brazil (BR)",
37 | "Brunei Darussalam (BN)",
38 | "Bulgaria (BG)",
39 | "Burkina Faso (BF)",
40 | "Cambodia (KH)",
41 | "Canada (CA)",
42 | "Cayman Islands (KY)",
43 | "Central African Republic (CF)",
44 | "Chad (TD)",
45 | "Chile (CL)",
46 | "China (CN)",
47 | "Christmas Island (CX)",
48 | "Colombia (CO)",
49 | "Costa Rica (CR)",
50 | "Côte d'Ivoire (CI)",
51 | "Croatia (HR)",
52 | "Cuba (CU)",
53 | "Cyprus (CY)",
54 | "Czechia (CZ)",
55 | "Denmark (DK)",
56 | "Dominica (DM)",
57 | "Dominican Republic (DO)",
58 | "Ecuador (EC)",
59 | "Egypt (EG)",
60 | "El Salvador (SV)",
61 | "Estonia (EE)",
62 | "Ethiopia (ET)",
63 | "Finland (FI)",
64 | "France (FR)",
65 | "French Guiana (GF)",
66 | "French Polynesia (PF)",
67 | "Georgia (GE)",
68 | "Germany (DE)",
69 | "Ghana (GH)",
70 | "Greece (GR)",
71 | "Greenland (GL)",
72 | "Grenada (GD)",
73 | "Guadeloupe (GP)",
74 | "Guam (GU)",
75 | "Guatemala (GT)",
76 | "Guyana (GY)",
77 | "Haiti (HT)",
78 | "Honduras (HN)",
79 | "Hong Kong (HK)",
80 | "Hungary (HU)",
81 | "Iceland (IS)",
82 | "India (IN)",
83 | "Indonesia (ID)",
84 | "Iran (IR)",
85 | "Ireland (IE)",
86 | "Israel (IL)",
87 | "Italy (IT)",
88 | "Jamaica (JM)",
89 | "Japan (JP)",
90 | "Jordan (JO)",
91 | "Kazakhstan (KZ)",
92 | "Kenya (KE)",
93 | "Korea (North) (KP)",
94 | "Korea (South) (KR)",
95 | "Kuwait (KW)",
96 | "Latvia (LV)",
97 | "Lebanon (LB)",
98 | "Lesotho (LS)",
99 | "Liechtenstein (LI)",
100 | "Lithuania (LT)",
101 | "Luxembourg (LU)",
102 | "Macao (MO)",
103 | "Malawi (MW)",
104 | "Malaysia (MY)",
105 | "Maldives (MV)",
106 | "Malta (MT)",
107 | "Marshall Islands (MH)",
108 | "Martinique (MQ)",
109 | "Mauritania (MR)",
110 | "Mauritius (MU)",
111 | "Mayotte (YT)",
112 | "Mexico (MX)",
113 | "Micronesia (FM)",
114 | "Moldova (MD)",
115 | "Monaco (MC)",
116 | "Mongolia (MN)",
117 | "Montenegro (ME)",
118 | "Morocco (MA)",
119 | "Nepal (NP)",
120 | "Netherlands (NL)",
121 | "Netherlands Antilles (AN)",
122 | "New Zealand (NZ)",
123 | "Nicaragua (NI)",
124 | "Nigeria (NG)",
125 | "North Macedonia (MK)",
126 | "Northern Mariana Islands (MP)",
127 | "Norway (NO)",
128 | "Oman (OM)",
129 | "Pakistan (PK)",
130 | "Palau (PW)",
131 | "Panama (PA)",
132 | "Papua New Guinea (PG)",
133 | "Paraguay (PY)",
134 | "Peru (PE)",
135 | "Philippines (PH)",
136 | "Poland (PL)",
137 | "Portugal (PT)",
138 | "Puerto Rico (PR)",
139 | "Qatar (QA)",
140 | "Réunion (RE)",
141 | "Romania (RO)",
142 | "Russian Federation (RU)",
143 | "Rwanda (RW)",
144 | "Saint Barthélemy (BL)",
145 | "Saint Kitts and Nevis (KN)",
146 | "Saint Lucia (LC)",
147 | "Saint Martin (MF)",
148 | "Saint Pierre and Miquelon (PM)",
149 | "Saint Vincent and the Grenadines (VC)",
150 | "Samoa (WS)",
151 | "Saudi Arabia (SA)",
152 | "Senegal (SN)",
153 | "Serbia (RS)",
154 | "Singapore (SG)",
155 | "Slovakia (SK)",
156 | "Slovenia (SI)",
157 | "South Africa (ZA)",
158 | "Spain (ES)",
159 | "Sri Lanka (LK)",
160 | "Suriname (SR)",
161 | "Sweden (SE)",
162 | "Switzerland (CH)",
163 | "Syria (SY)",
164 | "Taiwan (TW)",
165 | "Tanzania (TZ)",
166 | "Thailand (TH)",
167 | "Togo (TG)",
168 | "Trinidad and Tobago (TT)",
169 | "Tunisia (TN)",
170 | "Turkey (TR)",
171 | "Turks and Caicos Islands (TC)",
172 | "Uganda (UG)",
173 | "Ukraine (UA)",
174 | "United Arab Emirates (AE)",
175 | "United Kingdom (GB)",
176 | "United States (US)",
177 | "Uraguay (UY)",
178 | "Uzbekistan (UZ)",
179 | "Vanuatu (VU)",
180 | "Venezuela (VE)",
181 | "Vietnam (VN)",
182 | "Virgin Islands (VI)",
183 | "Wallis and Futuna (WF)",
184 | "Yemen (YE)",
185 | "Zimbabwe (ZW)"
186 | ]
187 |
188 |
189 | def get_regdomain():
190 | if not os.path.isfile(config.REGDOMAIN_CONF):
191 | return REGDOMAIN_DEFAULT
192 | code = f'({open(config.REGDOMAIN_CONF).readline().rstrip()[-2:]})'
193 | regdomain = next((l for l in REGDOMAIN_LIST if code in l),
194 | REGDOMAIN_DEFAULT)
195 | return regdomain
196 |
197 |
198 | def set_regdomain(regdomain):
199 | if regdomain == REGDOMAIN_DEFAULT:
200 | if os.path.isfile(config.REGDOMAIN_CONF):
201 | os.remove(config.REGDOMAIN_CONF)
202 | else:
203 | code = regdomain[-3:-1]
204 | with open(config.REGDOMAIN_CONF, 'w') as file:
205 | file.write(f'REGDOMAIN={code}\n')
206 | os_tools.execute(config.SETREGDOMAIN)
207 |
--------------------------------------------------------------------------------
/resources/lib/timezone.py:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: GPL-2.0
2 | # Copyright (C) 2024-present Team LibreELEC (https://libreelec.tv)
3 |
4 | '''This module holds support functions for interacting with timezones.
5 | '''
6 |
7 | import os
8 | from urllib.request import urlopen
9 |
10 | import config
11 | import log
12 | import os_tools
13 |
14 |
15 | def get_timezone():
16 | '''Read timezone setting from file or return default of UTC timezone.'''
17 | return os_tools.read_shell_setting(config.TIMEZONE, default='TIMEZONE=UTC').split('=', 1)[1]
18 |
19 |
20 | def guess_timezone():
21 | '''Guess the device's timezone based on the public IP of the device.'''
22 | def QueryWebServer(url):
23 | '''Query a webserver for a response.'''
24 | try:
25 | response = urlopen(url)
26 | except Exception as err:
27 | log.log(f'Error querying: {url}', log.ERROR)
28 | log.log(err, log.ERROR)
29 | response = None
30 | return response.read().decode('utf-8').strip() if response else None
31 |
32 | my_ip = QueryWebServer('https://icanhazip.com')
33 | return QueryWebServer(f'https://ipapi.co/{my_ip}/timezone') if my_ip else None
34 |
35 |
36 | def list_timezones():
37 | '''List timezones available from tzdata.'''
38 | timezones = []
39 | with open('/usr/share/zoneinfo/tzdata.zi', mode='r', encoding='utf-8') as tz_db:
40 | content = tz_db.read()
41 | for line in content.splitlines():
42 | # if line starts with Z take second field
43 | if line.startswith('Z'):
44 | timezones.append(line.split(' ')[1])
45 | # if line starts with L take third field
46 | elif line.startswith('L'):
47 | timezones.append(line.split(' ')[2])
48 | # sort and return
49 | timezones.sort()
50 | return timezones
51 |
52 |
53 | def set_timezone(timezone):
54 | '''Write new timezone info to .cache file and commit change to system.'''
55 | current_timezone = get_timezone()
56 | if current_timezone != timezone or not os.path.isfile(config.TIMEZONE):
57 | with open(config.TIMEZONE, mode='w', encoding='utf-8') as out_file:
58 | out_file.write(f'TIMEZONE={timezone}\n')
59 | if os.path.isfile(config.TIMEZONE):
60 | os_tools.execute('systemctl restart tz-data')
61 | else:
62 | log.log(f'Failed to write: {config.TIMEZONE}', log.ERROR)
63 | log.log(f'Desired timezone was: {timezone}', log.ERROR)
64 |
--------------------------------------------------------------------------------
/resources/lib/ui_tools.py:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: GPL-2.0
2 | # Copyright (C) 2020-present Team LibreELEC (https://libreelec.tv)
3 |
4 | import xbmcaddon
5 | import xbmcgui
6 |
7 | import log
8 |
9 |
10 | ADDON = xbmcaddon.Addon()
11 | ADDON_ICON = ADDON.getAddonInfo('icon')
12 | ADDON_NAME = ADDON.getAddonInfo('name')
13 |
14 |
15 | @log.log_function()
16 | def notification(message, heading=ADDON_NAME, icon=ADDON_ICON):
17 | xbmcgui.Dialog().notification(heading, message, icon)
18 |
--------------------------------------------------------------------------------
/resources/skins/Default/1080i/service-LibreELEC-Settings-getPasskey.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 2000
4 | no
5 |
6 |
7 | 650
8 | 390
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | 5
19 | 5
20 | 600
21 | 174
22 | dialog-bg-solid.png
23 |
24 |
25 | 17
26 | 16
27 |
28 |
29 | 20
30 | 10
31 | 540
32 | 30
33 | font12
34 | white
35 |
36 | center
37 | true
38 |
39 |
40 | 10
41 | 50
42 | 560
43 | 30
44 | font23_title
45 | blue
46 |
47 | center
48 | true
49 |
50 |
51 | 10
52 | 70
53 | 560
54 | 30
55 | font23_title
56 | blue
57 |
58 | center
59 | true
60 |
61 |
62 | 10
63 | 90
64 | 560
65 | 30
66 | font23_title
67 | blue
68 |
69 | center
70 | true
71 |
72 |
73 | 10
74 | 140
75 | 555
76 | 12
77 |
78 |
79 |
80 |
81 |
82 |
--------------------------------------------------------------------------------
/resources/skins/Default/1080i/service-LibreELEC-Settings-wizard.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 1500
4 | no
5 |
6 |
7 | 300
8 | 200
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | 0
19 | 0
20 | 1320
21 | 680
22 | dialog-bg-solid.png
23 |
24 |
25 | 0
26 | 0
27 | 270
28 | 680
29 | floor.png
30 |
31 |
32 | 2
33 | 2
34 | 270
35 | 676
36 | wizard.png
37 |
38 |
39 | 268
40 | 0
41 | 1052
42 | 50
43 | black-back.png
44 |
45 |
46 | 300
47 | 10
48 | 740
49 | 30
50 | font16caps
51 |
52 | left
53 | center
54 | white
55 | black
56 |
57 |
58 | 268
59 | 576
60 | 1051
61 | 105
62 | black-back.png
63 |
64 |
65 | 269
66 | 575
67 | 1050
68 | 3
69 | separator-grey.png
70 |
71 |
72 | String.IsEmpty(Control.GetLabel(1390))
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 | 300
81 | 120
82 | 1
83 | 1
84 |
85 | false
86 |
87 |
88 | 300
89 | 66
90 | 990
91 | 40
92 | font24_title
93 |
94 | left
95 | blue
96 | black
97 |
98 |
99 | 300
100 | 124
101 | 900
102 | 500
103 | font12
104 |
105 | left
106 | white
107 | black
108 |
109 |
110 |
111 | 300
112 | 400
113 | 750
114 | 20
115 |
116 |
117 | left
118 | blue
119 | black
120 |
121 |
122 | 280
123 | 440
124 | 300
125 | 75
126 |
127 | 45
128 | button-fo.png
129 | button-nofo.png
130 |
131 |
132 | 570
133 | 440
134 | 300
135 | 75
136 |
137 | 45
138 | button-fo.png
139 | button-nofo.png
140 |
141 |
142 | 280
143 | 440
144 | 300
145 | 75
146 | button-fo.png
147 | button-nofo.png
148 |
149 | font13_title
150 | white
151 | center
152 |
153 |
154 | 570
155 | 440
156 | 300
157 | 75
158 | button-fo.png
159 | button-nofo.png
160 |
161 | font13_title
162 | white
163 | center
164 |
165 |
166 |
167 | !String.IsEmpty(Control.GetLabel(1391))
168 |
169 | 300
170 | 140
171 | 1
172 | 1
173 |
174 | false
175 |
176 |
177 | 300
178 | 335
179 | 750
180 | 20
181 |
182 | left
183 | blue
184 | black
185 |
186 |
187 | 278
188 | 370
189 | 1020
190 | 200
191 | dialog-bg.png
192 |
193 |
194 |
195 |
196 | false
197 | 10
198 | 100
199 | 260
200 | 541
201 | 1500
202 | -
203 | 300
204 |
205 |
206 |
207 |
208 |
209 |
210 | 300
211 | 392
212 | 1050
213 | 150
214 | 1500
215 | 1500
216 | 300
217 |
218 | 0
219 | 0
220 |
221 | 0
222 | 2
223 | 974
224 | 48
225 | separator.png
226 |
227 |
228 |
229 | 10
230 | 10
231 | 32
232 | 32
233 | keep
234 | String.IsEqual(ListItem.Property(netType), ethernet)
235 | eth.png
236 |
237 |
238 |
239 | 10
240 | 10
241 | 32
242 | 32
243 | keep
244 | String.IsEqual(ListItem.Property(netType), vpn)
245 | vpn.png
246 |
247 |
248 |
249 | 10
250 | 10
251 | 32
252 | 32
253 | keep
254 | String.IsEqual(ListItem.Property(netType), wifi)
255 | wlan.png
256 |
257 |
258 |
259 | 70
260 | 0
261 | 200
262 | 50
263 | center
264 | font13_title
265 | blue
266 | ListItem.Label
267 | true
268 |
269 |
270 |
271 | 300
272 | 0
273 | 350
274 | 50
275 | center
276 | font12
277 | blue
278 | String.IsEqual(ListItem.Property(State), online) | String.IsEqual(ListItem.Property(State), ready)
279 |
280 |
281 |
282 |
283 | 680
284 | 0
285 | 170
286 | 50
287 | center
288 | font12
289 | blue
290 |
291 |
292 |
293 |
294 | 10
295 | 40
296 | 952
297 | 2
298 | ListItem.Property(Strength)
299 | String.IsEqual(ListItem.Property(netType), wifi)
300 |
301 |
302 |
303 |
304 | separator-grey.png
305 |
306 |
307 |
308 | 930
309 | 15
310 | 20
311 | 20
312 | keep
313 | IntegerGreaterThan(ListItem.Property(Security), 0)
314 | key.png
315 |
316 |
317 |
318 | 0
319 | 0
320 |
321 | 0
322 | 2
323 | 974
324 | 48
325 | separator.png
326 |
327 |
328 | 0
329 | 2
330 | 974
331 | 48
332 | Control.HasFocus(1200)
333 | focus.png
334 |
335 |
336 |
337 |
338 |
339 |
340 | 10
341 | 10
342 | 32
343 | 32
344 | keep
345 | String.IsEqual(ListItem.Property(netType), ethernet)
346 | eth.png
347 |
348 |
349 |
350 | 10
351 | 10
352 | 32
353 | 32
354 | keep
355 | String.IsEqual(ListItem.Property(netType), vpn)
356 | vpn.png
357 |
358 |
359 |
360 | 10
361 | 10
362 | 32
363 | 32
364 | keep
365 | String.IsEqual(ListItem.Property(netType), wifi)
366 | wlan.png
367 |
368 |
369 |
370 | 70
371 | 0
372 | 200
373 | 50
374 | center
375 | font13_title
376 | blue
377 | ListItem.Label
378 | true
379 |
380 |
381 |
382 | 300
383 | 0
384 | 350
385 | 50
386 | center
387 | font12
388 | blue
389 | String.IsEqual(ListItem.Property(State), online) | String.IsEqual(ListItem.Property(State), ready)
390 |
391 |
392 |
393 |
394 | 680
395 | 0
396 | 170
397 | 50
398 | center
399 | font12
400 | blue
401 |
402 |
403 |
404 |
405 | 10
406 | 40
407 | 952
408 | 2
409 | ListItem.Property(Strength)
410 | String.IsEqual(ListItem.Property(netType), wifi)
411 |
412 |
413 |
414 |
415 | separator-grey.png
416 |
417 |
418 |
419 | 930
420 | 15
421 | 20
422 | 20
423 | keep
424 | IntegerGreaterThan(ListItem.Property(Security), 0)
425 | key.png
426 |
427 |
428 |
429 |
430 |
431 |
432 | 970
433 | 586
434 | 300
435 | 75
436 | true
437 | button-fo.png
438 | button-nofo.png
439 |
440 | font13_title
441 | white
442 | center
443 | 1000
444 | 1000
445 | !String.IsEmpty(Control.GetLabel(1500))
446 |
447 |
448 | 320
449 | 586
450 | 300
451 | 75
452 | true
453 | button-fo.png
454 | button-nofo.png
455 |
456 | font13_title
457 | white
458 | center
459 | 1000
460 | 1000
461 | !String.IsEmpty(Control.GetLabel(1501))
462 |
463 |
464 |
465 |
466 |
--------------------------------------------------------------------------------
/resources/skins/Default/media/arrowdown.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LibreELEC/service.libreelec.settings/12b47f4ab54fefd755507cf555c33771b8bc7ed3/resources/skins/Default/media/arrowdown.png
--------------------------------------------------------------------------------
/resources/skins/Default/media/bg.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LibreELEC/service.libreelec.settings/12b47f4ab54fefd755507cf555c33771b8bc7ed3/resources/skins/Default/media/bg.jpg
--------------------------------------------------------------------------------
/resources/skins/Default/media/black-back.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LibreELEC/service.libreelec.settings/12b47f4ab54fefd755507cf555c33771b8bc7ed3/resources/skins/Default/media/black-back.png
--------------------------------------------------------------------------------
/resources/skins/Default/media/bt-audio-card.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LibreELEC/service.libreelec.settings/12b47f4ab54fefd755507cf555c33771b8bc7ed3/resources/skins/Default/media/bt-audio-card.png
--------------------------------------------------------------------------------
/resources/skins/Default/media/bt-camera-photo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LibreELEC/service.libreelec.settings/12b47f4ab54fefd755507cf555c33771b8bc7ed3/resources/skins/Default/media/bt-camera-photo.png
--------------------------------------------------------------------------------
/resources/skins/Default/media/bt-camera-video.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LibreELEC/service.libreelec.settings/12b47f4ab54fefd755507cf555c33771b8bc7ed3/resources/skins/Default/media/bt-camera-video.png
--------------------------------------------------------------------------------
/resources/skins/Default/media/bt-computer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LibreELEC/service.libreelec.settings/12b47f4ab54fefd755507cf555c33771b8bc7ed3/resources/skins/Default/media/bt-computer.png
--------------------------------------------------------------------------------
/resources/skins/Default/media/bt-input-gaming.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LibreELEC/service.libreelec.settings/12b47f4ab54fefd755507cf555c33771b8bc7ed3/resources/skins/Default/media/bt-input-gaming.png
--------------------------------------------------------------------------------
/resources/skins/Default/media/bt-input-keyboard.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LibreELEC/service.libreelec.settings/12b47f4ab54fefd755507cf555c33771b8bc7ed3/resources/skins/Default/media/bt-input-keyboard.png
--------------------------------------------------------------------------------
/resources/skins/Default/media/bt-input-mouse.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LibreELEC/service.libreelec.settings/12b47f4ab54fefd755507cf555c33771b8bc7ed3/resources/skins/Default/media/bt-input-mouse.png
--------------------------------------------------------------------------------
/resources/skins/Default/media/bt-input-tablet.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LibreELEC/service.libreelec.settings/12b47f4ab54fefd755507cf555c33771b8bc7ed3/resources/skins/Default/media/bt-input-tablet.png
--------------------------------------------------------------------------------
/resources/skins/Default/media/bt-modem.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LibreELEC/service.libreelec.settings/12b47f4ab54fefd755507cf555c33771b8bc7ed3/resources/skins/Default/media/bt-modem.png
--------------------------------------------------------------------------------
/resources/skins/Default/media/bt-phone.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LibreELEC/service.libreelec.settings/12b47f4ab54fefd755507cf555c33771b8bc7ed3/resources/skins/Default/media/bt-phone.png
--------------------------------------------------------------------------------
/resources/skins/Default/media/bt-printer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LibreELEC/service.libreelec.settings/12b47f4ab54fefd755507cf555c33771b8bc7ed3/resources/skins/Default/media/bt-printer.png
--------------------------------------------------------------------------------
/resources/skins/Default/media/bt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LibreELEC/service.libreelec.settings/12b47f4ab54fefd755507cf555c33771b8bc7ed3/resources/skins/Default/media/bt.png
--------------------------------------------------------------------------------
/resources/skins/Default/media/button-fo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LibreELEC/service.libreelec.settings/12b47f4ab54fefd755507cf555c33771b8bc7ed3/resources/skins/Default/media/button-fo.png
--------------------------------------------------------------------------------
/resources/skins/Default/media/button-nofo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LibreELEC/service.libreelec.settings/12b47f4ab54fefd755507cf555c33771b8bc7ed3/resources/skins/Default/media/button-nofo.png
--------------------------------------------------------------------------------
/resources/skins/Default/media/connected.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LibreELEC/service.libreelec.settings/12b47f4ab54fefd755507cf555c33771b8bc7ed3/resources/skins/Default/media/connected.png
--------------------------------------------------------------------------------
/resources/skins/Default/media/dialog-bg-solid.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LibreELEC/service.libreelec.settings/12b47f4ab54fefd755507cf555c33771b8bc7ed3/resources/skins/Default/media/dialog-bg-solid.png
--------------------------------------------------------------------------------
/resources/skins/Default/media/dialog-bg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LibreELEC/service.libreelec.settings/12b47f4ab54fefd755507cf555c33771b8bc7ed3/resources/skins/Default/media/dialog-bg.png
--------------------------------------------------------------------------------
/resources/skins/Default/media/do.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LibreELEC/service.libreelec.settings/12b47f4ab54fefd755507cf555c33771b8bc7ed3/resources/skins/Default/media/do.png
--------------------------------------------------------------------------------
/resources/skins/Default/media/eth.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LibreELEC/service.libreelec.settings/12b47f4ab54fefd755507cf555c33771b8bc7ed3/resources/skins/Default/media/eth.png
--------------------------------------------------------------------------------
/resources/skins/Default/media/fanart.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LibreELEC/service.libreelec.settings/12b47f4ab54fefd755507cf555c33771b8bc7ed3/resources/skins/Default/media/fanart.png
--------------------------------------------------------------------------------
/resources/skins/Default/media/favorite.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LibreELEC/service.libreelec.settings/12b47f4ab54fefd755507cf555c33771b8bc7ed3/resources/skins/Default/media/favorite.png
--------------------------------------------------------------------------------
/resources/skins/Default/media/floor.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LibreELEC/service.libreelec.settings/12b47f4ab54fefd755507cf555c33771b8bc7ed3/resources/skins/Default/media/floor.png
--------------------------------------------------------------------------------
/resources/skins/Default/media/focus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LibreELEC/service.libreelec.settings/12b47f4ab54fefd755507cf555c33771b8bc7ed3/resources/skins/Default/media/focus.png
--------------------------------------------------------------------------------
/resources/skins/Default/media/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LibreELEC/service.libreelec.settings/12b47f4ab54fefd755507cf555c33771b8bc7ed3/resources/skins/Default/media/icon.png
--------------------------------------------------------------------------------
/resources/skins/Default/media/icon_button_back.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LibreELEC/service.libreelec.settings/12b47f4ab54fefd755507cf555c33771b8bc7ed3/resources/skins/Default/media/icon_button_back.png
--------------------------------------------------------------------------------
/resources/skins/Default/media/key.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LibreELEC/service.libreelec.settings/12b47f4ab54fefd755507cf555c33771b8bc7ed3/resources/skins/Default/media/key.png
--------------------------------------------------------------------------------
/resources/skins/Default/media/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LibreELEC/service.libreelec.settings/12b47f4ab54fefd755507cf555c33771b8bc7ed3/resources/skins/Default/media/logo.png
--------------------------------------------------------------------------------
/resources/skins/Default/media/radio-button-off.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LibreELEC/service.libreelec.settings/12b47f4ab54fefd755507cf555c33771b8bc7ed3/resources/skins/Default/media/radio-button-off.png
--------------------------------------------------------------------------------
/resources/skins/Default/media/radio-button-on.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LibreELEC/service.libreelec.settings/12b47f4ab54fefd755507cf555c33771b8bc7ed3/resources/skins/Default/media/radio-button-on.png
--------------------------------------------------------------------------------
/resources/skins/Default/media/separator-grey.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LibreELEC/service.libreelec.settings/12b47f4ab54fefd755507cf555c33771b8bc7ed3/resources/skins/Default/media/separator-grey.png
--------------------------------------------------------------------------------
/resources/skins/Default/media/separator.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LibreELEC/service.libreelec.settings/12b47f4ab54fefd755507cf555c33771b8bc7ed3/resources/skins/Default/media/separator.png
--------------------------------------------------------------------------------
/resources/skins/Default/media/unlock.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LibreELEC/service.libreelec.settings/12b47f4ab54fefd755507cf555c33771b8bc7ed3/resources/skins/Default/media/unlock.png
--------------------------------------------------------------------------------
/resources/skins/Default/media/vpn.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LibreELEC/service.libreelec.settings/12b47f4ab54fefd755507cf555c33771b8bc7ed3/resources/skins/Default/media/vpn.png
--------------------------------------------------------------------------------
/resources/skins/Default/media/wizard.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LibreELEC/service.libreelec.settings/12b47f4ab54fefd755507cf555c33771b8bc7ed3/resources/skins/Default/media/wizard.png
--------------------------------------------------------------------------------
/resources/skins/Default/media/wlan.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LibreELEC/service.libreelec.settings/12b47f4ab54fefd755507cf555c33771b8bc7ed3/resources/skins/Default/media/wlan.png
--------------------------------------------------------------------------------
/service.py:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: GPL-2.0-or-later
2 | # Copyright (C) 2009-2013 Stephan Raue (stephan@openelec.tv)
3 | # Copyright (C) 2013 Lutz Fiebach (lufie@openelec.tv)
4 | # Copyright (C) 2019-present Team LibreELEC (https://libreelec.tv)
5 |
6 | import os
7 | import socket
8 | import threading
9 |
10 | import xbmc
11 |
12 | import syspath
13 | import dbus_utils
14 | import log
15 | import oe
16 |
17 |
18 | class Service_Thread(threading.Thread):
19 |
20 | SOCKET = '/var/run/service.libreelec.settings.sock'
21 |
22 | def __init__(self):
23 | threading.Thread.__init__(self)
24 | self.init()
25 |
26 | @log.log_function()
27 | def init(self):
28 | if os.path.exists(self.SOCKET):
29 | os.remove(self.SOCKET)
30 | self.daemon = True
31 | self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
32 | self.sock.setblocking(1)
33 | self.sock.bind(self.SOCKET)
34 | self.sock.listen(1)
35 | self.stopped = False
36 |
37 | @log.log_function()
38 | def run(self):
39 | if oe.read_setting('libreelec', 'wizard_completed') == None:
40 | threading.Thread(target=oe.openWizard).start()
41 | while self.stopped == False:
42 | log.log(f'Waiting', log.INFO)
43 | conn, addr = self.sock.accept()
44 | message = (conn.recv(1024)).decode('utf-8')
45 | conn.close()
46 | log.log(f'Received {message}', log.INFO)
47 | if message == 'openConfigurationWindow':
48 | if not hasattr(oe, 'winOeMain'):
49 | threading.Thread(target=oe.openConfigurationWindow).start()
50 | else:
51 | if oe.winOeMain.visible != True:
52 | threading.Thread(
53 | target=oe.openConfigurationWindow).start()
54 | if message == 'exit':
55 | self.stopped = True
56 |
57 | @log.log_function()
58 | def stop(self):
59 | sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
60 | sock.connect(self.SOCKET)
61 | sock.send(bytes('exit', 'utf-8'))
62 | sock.close()
63 | self.join()
64 | self.sock.close()
65 |
66 |
67 | class Monitor(xbmc.Monitor):
68 |
69 | @log.log_function()
70 | def onScreensaverActivated(self):
71 | if oe.read_setting('bluetooth', 'standby'):
72 | threading.Thread(target=oe.standby_devices).start()
73 |
74 | @log.log_function()
75 | def onDPMSActivated(self):
76 | if oe.read_setting('bluetooth', 'standby'):
77 | threading.Thread(target=oe.standby_devices).start()
78 |
79 | @log.log_function()
80 | def run(self):
81 | dbus_utils.LOOP_THREAD.start()
82 | oe.load_modules()
83 | oe.start_service()
84 | service_thread = Service_Thread()
85 | service_thread.start()
86 | while not self.abortRequested():
87 | if self.waitForAbort(60):
88 | break
89 | if not oe.read_setting('bluetooth', 'standby'):
90 | continue
91 | timeout = oe.read_setting('bluetooth', 'idle_timeout')
92 | if not timeout:
93 | continue
94 | try:
95 | timeout = int(timeout)
96 | except:
97 | continue
98 | if timeout < 1:
99 | continue
100 | if xbmc.getGlobalIdleTime() / 60 >= timeout:
101 | log.log(f'Idle timeout reached', log.DEBUG)
102 | oe.standby_devices()
103 | if hasattr(oe, 'winOeMain') and hasattr(oe.winOeMain, 'visible'):
104 | if oe.winOeMain.visible == True:
105 | oe.winOeMain.close()
106 | oe.stop_service()
107 | service_thread.stop()
108 | dbus_utils.LOOP_THREAD.stop()
109 |
110 |
111 | if __name__ == '__main__':
112 | Monitor().run()
113 |
--------------------------------------------------------------------------------
/syspath.py:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: GPL-2.0
2 | # Copyright (C) 2020-present Team LibreELEC (https://libreelec.tv)
3 |
4 | import os
5 | import sys
6 |
7 | sys.path.append(os.path.join(os.path.dirname(__file__), 'resources', 'lib'))
8 | sys.path.append(os.path.join(os.path.dirname(__file__), 'resources', 'lib', 'modules'))
9 |
--------------------------------------------------------------------------------