Пожалуйста, войдите или зарегистрируйтесь.

VuPlusRu

21 Ноябрь 2018, 00:31:21
Новости:
Наш канал в Telegram

Добавьте в контакты @VuPlusRu , или перейдите по этой ссылке, предварительно зарегистрировавшись в мессенджере: https://t.me/vuplusru

Автор Тема: Пишем плагин сами или случайные уроки по python  (Прочитано 2484 раз)

0 Пользователей и 1 Гость просматривают эту тему.

Оффлайн ака Учкун

  • Спец
  • *
  • СПАСИБО:
  • - Вы поблагодарили: 438
  • - Вас поблагодарили: 3688
  • Сообщений: 895
  • Пол: Мужской
  • Зарегистрирован: 2012-07-15
    Местоположение: город Навои
    Возраст: 53
    • Просмотр профиля

Пишем плагин сами или случайные уроки по python

В чем смысл данной темы?
Ведь не настолько же я наивен, чтобы полагать, что можно вот так взять и с помощью нескольких постов на форуме, научить простого пользователя ресиверов с имиджем на энигме писать плагины.
Да, разумеется это невозможно.
Цель этого FAQ вижу в другом.
Исходя из своего опыта изучения языка программирования python, знаю, что самое неприятное в этом деле это при всей этой для начала очень нудной зубрежке, совершенное непонимание того, что как же эту чертову теорию соотнести применительно к нашим имиджам на энигме.
То есть как недавно сказал один пользователь
Цитировать (выделенное)
.......без практики мне python нафиг не нужен......
Что же понять его можно.

Вот и постараюсь показать как соотнести, даже еще не самое возможно углубленное изучение языка python с практикой.
И возможно затем, получив некое вдохновение вы возьметесь-таки за более углубленное изучение python.
То есть вы поняли, задача этого FAQ, сделать процесс изучения python веселее, если кто решился-таки изучать его ради того, чтобы научиться писать или хотя бы править плагины...........

Итак, начнем.
Для начала определим свою задачу.
Чтобы было наиболее наглядно, нам с вами нужно написать плагин (прямо в этой теме), в котором бы отображался весь необходимый процесс плагинописания. Сам питоновский код и все необходимые действия с имиджем.
Да и еще, чтобы такого плагина еще не было бы написано (иначе какой смысл) и чтобы он был полезен для нас.

И вот какой плагин мы напишем.
Многие из нас частенько устанавливают имиджи с нуля.
При этом мы довели этот процесс до автоматизма.
Установили имидж, быстренько накатили настройки и пользуемся.
Так вот, кому как, а мне лично каждый раз при этом приходится вручную переписывать файл settings в имидже, чтобы внести туда настройки тюнера. Много "тарелок", сложное подключение спутников к тюнеру и через дайсики протокола 2.0, а затем в конце еще и дайсик протокола 1.1.
Дримбоксэдит передает все настройки кроме настроек тюнера.
Конечно переписать вручную файл сеттингс вроде нетяжело и недолго, но почему бы не автоматизировать этот процесс? Тем более что есть пользователи, которые как огня боятся что-нибудь в имидже править вручную.

Решено, это будет плагин, который будет сохранять настройку наших тюнеров, а затем восстанавливать эти настройки во вновь установленных имиджах.

Какой плагин написать решили, теперь нам надо подготовить софт, с помощью которого собственно и будем творить.

Разумеется сперва-наперва устанавливаем у себя на компе собственно саму среду программирования python.
Как и любое свободное ПО, python скачиваем с официального сайта, то есть вот отсюда http://www.python.org/getit/.
В наших имиджах (практически во всех) установлен Python версии 2.7.
Потому именно эту версию питона нужно скачать и установить.
Как скачать с сайта и как установить думаю показывать нет необходимости, ибо если не разберетесь с этим, далее эту тему читать нет смысла.....

После установки python, если вы работаете на винде, обязательно проверьте, а добавился ли путь к python в переменную path.
Для этого открываем
Панель управления-Система
Далее во вкладке Дополнительно или Дополнительные параметры системы (смотря какая у вас винда) находим кнопочку Переменные среды и нажав на нее, видим это окошко



И в нижнем окне нажав на пункт "Path" нажимаем Изменить... и проверяем, есть ли там путь к python. Если нет, добавляем, есттественно узнав сначала, куда же установился python.
У меня например он установился в папку C:\Python27 и я вот так добавил путь к нему в переменную path, просто прописав в начало этой переменной C:\Python27\; то есть отделил этот путь от остальных записей точкой с запятой.....



Собственно в IDLE самого питона мы не будем писать плагин, так как есть более юзабельное ПО для этого.
Но для компиляции на компе-то, да и для работы в консоли винды нам питон нужен будет........

Сам плагин мы будем писать в очень продвинутом свободном (опенсурч) редакторе под названием Geany.
Последнюю версию всегда можете скачать здесь http://www.geany.org/Download/Releases

Запускаем этот самый Geany и настраиваем так, чтобы эта продвинутая прога удобно подсвечивала нам синтаксис питона.
Идем во вкладку Правка-Настройки-Редактор-Отображение и ставим настройки как показана на скрине. Здесь главное пункт - Обратить цвета подсветки синтаксиса (будет подсвечивать синтаксис питона очень удобно для чтения)








Пожалуй это вся подготовительная работа.
Далее приступим к написанию непосредственно кода.

Продолжение следует (по наличию свободного времени, сегодня или завтра)......

  • gi 9995 vu+ ultimo
Собака лает, караван идет....

Эти пользователи поблагодарили Вас за сообщение:

Оффлайн ака Учкун

  • Спец
  • *
  • СПАСИБО:
  • - Вы поблагодарили: 438
  • - Вас поблагодарили: 3688
  • Сообщений: 895
  • Пол: Мужской
  • Зарегистрирован: 2012-07-15
    Местоположение: город Навои
    Возраст: 53
    • Просмотр профиля

Пишем плагин сами или случайные уроки по python
« Ответ #1 : 01 Декабрь 2013, 10:45:35 »
Продолжим.
Но сначала, как водится, снова лирическое отступление.
Enigma2 на наших ресах это операционная система (ОС) на линуксе, такая же как Ubuntu, Mandriva, Slax и т.д.
Хотите продвинуться дальше, изучайте устройство этой ОС енигма2, вникайте во все исходники.
А уж где система (имидж) хранит свои настройки, а откуда из имиджа можно вытянуть какие сведения это нужно знать подавно.
Вобщем потихоньку вместе с изучением питона, изучайте и имидж......

Также надеюсь, хоть немножко "позубрили" питон, например хотя бы здесь http://younglinux.info/python.php.
Хотя бы азы, что такое строки, списки, словари и их встроенные методы, простые операторы if-else, for, выражения, кортежи и т.д........
В этой теме невозможно охватить все, будем выполнять только свою задачу, как использовать получаемые знания на имидже, и подразумевается, что питон вы уже изучаете.......

Начнем решать нашу задачу.
Вкратце повторим суть задачи.

Задание.
- написать плагин для наших имиджей на энигме2, который бы одним кликом сохранял настройки нашего тюнера, затем будучи установленным на другой "чистый" имидж, одним кликом восстановить настройки тюнера. Не ахти какой нужный плагин))), но суть - такого плагина нет и мы его напишем.

Решение
При написании плагина, как и при решении любых задач в программировании, решение начинается с разработки самого алгоритма решения задачи.
Алгоритм - это проще говоря, последовательность шагов, при точном выполнении которых, задача окажется решенной.
В нашем случае задача выглядит так:

1. Вытащить из имиджа настройки тюнера, и сохранить эти настройки в файл.
2. Сохранить плагин с этими настройками и в последующем установить плагин с этими сохраненными настройками на вновь установленный нами имидж, ну и применить эти настройки в новом имидже.

Вроде бы все просто. Вот теперь оба этих пункта по очереди детально будем осуществлять.
Пункт первый, так как же вытащить из имиджа настройки тюнера?
Вот мы и начали работать непосредственно с имиджем.
В результате изучения энигмы2 узнаем, что настройки тюнера (тюнеров) имидж хранит (и использует оттуда) в файле
/etc/enigma2/settings

Далее вступают в дело наши (пусть даже пока скудные) знания в питоне.
Теперь разработаем непосредственно алгоритм по пункту номер один.

а) открыть файл /etc/enigma2/settings для чтения
б) прочитать файл построчно
в) закрыть файл
г) выделить строки с настройкой тюнера (тюнеров)
д) открыть другой файл (вернее создать) с правами на запись и записать туда эти строки с настройками тюнера
е) закрыть файл

Как видите все очень просто и код будет простой.
Открываем Geany, идем во вкладку Файл-Создать из шаблона, выбираем main.py.
Откроется это окно.






Далее идем во вкладку Документ-Установить окончания строк, выбираем "Заменить окончания строк на LF (Unix)".
Далее из окна удаляем готовый код и начнем.
По порядку

а) открыть файл /etc/enigma2/settings для чтения.
a = open("/etc/enigma2/settings", "r")Результат открывания файла присвоили переменной a (просто произвольная буква).

Далее прочитываем файл
б) прочитать файл построчно
b = a.read()Опять присваиваем переменной b (снова любой произвольный знак).
Здесь нужны разъяснения.
Как питон читает текстовый файл, состоящий из строк?
Он читает его как одну единую строку, заменяя переходы на следующую строку на знак обратного слеша с латинской буквой n, то есть \n.

Спойлер   :
Хотя правда здесь я намеренно (чтобы вы постигли сути) путаю понятия на самом деле.
Ну то есть, не питон так читает, а на самом деле такова структура самого текстового файла.

Можем это легко проверить.
Открываем файл /etc/enigma2/settings и смотрим. У меня он выглядит так:

Спойлер   :
config.av.scaler_sharpness=17
config.av.policy_169=scale
config.av.videorate.1080i=multi
config.av.policy_43=scale
config.av.videoport=DVI
config.av.videomode.DVI=1080i
config.misc.rcused=0
config.misc.firstrun=false
config.misc.initialchannelselection=false
config.misc.startCounter=247
config.misc.languageselected=false
config.misc.epgcache_filename=/media/usb/epg.dat
config.misc.lastrotorposition=850
config.misc.videowizardenabled=false
config.usage.movielist_trashcan_reserve=40
config.usage.allowed_timeshift_paths=['/media/hdd/']
config.usage.show_event_progress_in_ser vicelist=barleft
config.usage.hide_zap_errors=true
config.usage.servicetype_icon_mode=1
config.usage.service_icon_enable=true
config.usage.multiepg_ask_bouquet=true
config.usage.alternative_number_mode=true
config.usage.movielist_trashcan_days=8
config.usage.hide_number_markers=true
config.usage.quickzap_bouquet_change=true
config.usage.hide_ci_messages=true
config.usage.show_second_infobar=6
config.usage.screen_saver=5
config.radio.lastroot=1:7:1:0:0:0:0:0:0:0:FROM BOUQUET "bouquets.radio" ORDER BY bouquet;1:7:2:0:0:0:0:0:0:0:FROM BOUQUET "userbouquet.favourites.radio" ORDER BY bouquet;
config.radio.lastservice=1:0:2:1D:2:1:3848FF4:0:0:0:
config.plugins.smoothhide.eff=3
config.plugins.ExtraChannelSelection.co lselremain=20
config.plugins.ExtraChannelSelection.te xt=true
config.plugins.ExtraChannelSelection.pi comode=1
config.plugins.ExtraChannelSelection.fo ntperc=2
config.plugins.ExtraChannelSelection.pi cbar=4
config.plugins.ExtraChannelSelection.co lnamesel=34
config.plugins.ExtraChannelSelection.co lpercsel=35
config.plugins.ExtraChannelSelection.co lbordersel=31
config.plugins.ExtraChannelSelection.fo ntnum=7
config.plugins.ExtraChannelSelection.fo ntsat=6
config.plugins.ExtraChannelSelection.ok mode=true
config.plugins.ExtraChannelSelection.co lselnum=25
config.plugins.ExtraChannelSelection.co levent=1
config.plugins.ExtraChannelSelection.ba rpercmode=true
config.plugins.ExtraChannelSelection.co lborder=34
config.plugins.ExtraChannelSelection.co lormode=false
config.plugins.ExtraChannelSelection.co lremain=17
config.plugins.ExtraChannelSelection.co lname=25
config.plugins.ExtraChannelSelection.pe rcmode=3
config.plugins.ExtraChannelSelection.ba rmode=2
config.plugins.ExtraChannelSelection.fo ntrem=5
config.plugins.ExtraChannelSelection.ep gext=true
config.plugins.ExtraChannelSelection.fo nttxt=5
config.plugins.ExtraChannelSelection.li stmode=true
config.plugins.ExtraChannelSelection.do ubmode=true
config.plugins.ExtraChannelSelection.co lperc=6
config.plugins.ExtraChannelSelection.co lnum=9
config.plugins.ExtraChannelSelection.fo ntend=7
config.plugins.ExtraChannelSelection.co ltext=4
config.plugins.ExtraChannelSelection.co leventsel=24
config.plugins.ExtraChannelSelection.co lend=4
config.plugins.ExtraChannelSelection.co lselend=6
config.plugins.brightnesssetup.brightne ssstandby=0
config.plugins.EncryptedChannel.enabled=true
config.plugins.epanel.time=4
config.plugins.epanel.TransponderTime=1
config.plugins.epanel.onoff=1
config.plugins.epgd.checkepgfile=true
config.plugins.epgd.weekday=0
config.plugins.xModem.mainmenu=true
config.plugins.QuickSignal.enabled=false
config.plugins.QuickButton.backupdirs=['/etc/']
config.plugins.QuickButton.okexitstate=true
config.plugins.NumberZapExt.acount=true
config.plugins.NumberZapExt.enable=true
config.plugins.NumberZapExt.picons=true
config.plugins.configurationbackup.back updirs=['/etc/default_gw', '/etc/enigma2/', '/etc/hostname', '/etc/network/interfaces', '/etc/resolv.conf', '/etc/wpa_supplicant.ath0.conf', '/etc/wpa_supplicant.conf', '/etc/wpa_supplicant.wlan0.conf']
config.timezone.val=(GMT+05:00) Islamabad, Karachi, Tashkent
config.Nims.1.configMode=advanced
config.Nims.1.advanced.sats=558
config.Nims.1.advanced.sat.558.lnb=1
config.Nims.1.advanced.lnb.1.threshold=10750
config.Nims.1.advanced.lnb.1.lofh=10750
config.Nims.1.advanced.lnb.1.lof=user_defined
config.Nims.1.advanced.lnb.1.lofl=10750
config.Nims.1.powerMeasurement=false
config.Nims.0.configMode=advanced
config.Nims.0.advanced.sats=560
config.Nims.0.advanced.sat.130.lnb=3
config.Nims.0.advanced.sat.600.lnb=13
config.Nims.0.advanced.sat.850.lnb=7
config.Nims.0.advanced.sat.48.lnb=14
config.Nims.0.advanced.sat.915.lnb=9
config.Nims.0.advanced.sat.420.lnb=12
config.Nims.0.advanced.sat.750.lnb=5
config.Nims.0.advanced.sat.560.tonemode=on
config.Nims.0.advanced.sat.560.lnb=18
config.Nims.0.advanced.sat.90.lnb=2
config.Nims.0.advanced.sat.965.lnb=11
config.Nims.0.advanced.sat.900.lnb=8
config.Nims.0.advanced.sat.935.lnb=10
config.Nims.0.advanced.sat.530.lnb=1
config.Nims.0.advanced.sat.800.lnb=6
config.Nims.0.advanced.lnb.11.diseqcMod e=1_1
config.Nims.0.advanced.lnb.11.uncommitt edDiseqcCommand=1
config.Nims.0.advanced.lnb.11.fastDiseq c=true
config.Nims.0.advanced.lnb.11.commandOr der=cut
config.Nims.0.advanced.lnb.11.sequenceR epeat=true
config.Nims.0.advanced.lnb.11.commitedD iseqcCommand=BB
config.Nims.0.advanced.lnb.10.diseqcMod e=1_1
config.Nims.0.advanced.lnb.10.uncommitt edDiseqcCommand=4
config.Nims.0.advanced.lnb.10.fastDiseq c=true
config.Nims.0.advanced.lnb.10.commandOr der=cut
config.Nims.0.advanced.lnb.10.sequenceR epeat=true
config.Nims.0.advanced.lnb.10.commitedD iseqcCommand=AA
config.Nims.0.advanced.lnb.13.diseqcMod e=1_1
config.Nims.0.advanced.lnb.13.uncommitt edDiseqcCommand=2
config.Nims.0.advanced.lnb.13.fastDiseq c=true
config.Nims.0.advanced.lnb.13.commandOr der=cut
config.Nims.0.advanced.lnb.13.sequenceR epeat=true
config.Nims.0.advanced.lnb.13.commitedD iseqcCommand=AA
config.Nims.0.advanced.lnb.12.diseqcMod e=1_1
config.Nims.0.advanced.lnb.12.uncommitt edDiseqcCommand=2
config.Nims.0.advanced.lnb.12.fastDiseq c=true
config.Nims.0.advanced.lnb.12.commandOr der=cut
config.Nims.0.advanced.lnb.12.sequenceR epeat=true
config.Nims.0.advanced.lnb.12.commitedD iseqcCommand=BA
config.Nims.0.advanced.lnb.14.diseqcMod e=1_1
config.Nims.0.advanced.lnb.14.uncommitt edDiseqcCommand=1
config.Nims.0.advanced.lnb.14.commitedD iseqcCommand=BA
config.Nims.0.advanced.lnb.14.sequenceR epeat=true
config.Nims.0.advanced.lnb.14.fastDiseq c=true
config.Nims.0.advanced.lnb.14.commandOr der=cut
config.Nims.0.advanced.lnb.18.lof=user_defined
config.Nims.0.advanced.lnb.18.diseqcMod e=1_1
config.Nims.0.advanced.lnb.18.uncommitt edDiseqcCommand=6
config.Nims.0.advanced.lnb.18.commandOr der=cut
config.Nims.0.advanced.lnb.18.threshold=10750
config.Nims.0.advanced.lnb.18.lofh=10750
config.Nims.0.advanced.lnb.18.lofl=10750
config.Nims.0.advanced.lnb.18.fastDiseq c=true
config.Nims.0.advanced.lnb.1.diseqcMode=1_1
config.Nims.0.advanced.lnb.1.uncommitte dDiseqcCommand=2
config.Nims.0.advanced.lnb.1.fastDiseqc=true
config.Nims.0.advanced.lnb.1.commandOrd er=cut
config.Nims.0.advanced.lnb.1.sequenceRe peat=true
config.Nims.0.advanced.lnb.1.commitedDi seqcCommand=BB
config.Nims.0.advanced.lnb.3.sequenceRe peat=true
config.Nims.0.advanced.lnb.3.diseqcMode=1_1
config.Nims.0.advanced.lnb.3.uncommitte dDiseqcCommand=5
config.Nims.0.advanced.lnb.3.commandOrd er=cut
config.Nims.0.advanced.lnb.3.fastDiseqc=true
config.Nims.0.advanced.lnb.2.sequenceRe peat=true
config.Nims.0.advanced.lnb.2.diseqcMode=1_1
config.Nims.0.advanced.lnb.2.uncommitte dDiseqcCommand=3
config.Nims.0.advanced.lnb.2.commandOrd er=cut
config.Nims.0.advanced.lnb.2.fastDiseqc=true
config.Nims.0.advanced.lnb.5.diseqcMode=1_1
config.Nims.0.advanced.lnb.5.uncommitte dDiseqcCommand=1
config.Nims.0.advanced.lnb.5.fastDiseqc=true
config.Nims.0.advanced.lnb.5.commandOrd er=cut
config.Nims.0.advanced.lnb.5.sequenceRe peat=true
config.Nims.0.advanced.lnb.5.commitedDi seqcCommand=AA
config.Nims.0.advanced.lnb.5.powerMeasu rement=false
config.Nims.0.advanced.lnb.7.diseqcMode=1_1
config.Nims.0.advanced.lnb.7.uncommitte dDiseqcCommand=4
config.Nims.0.advanced.lnb.7.fastDiseqc=true
config.Nims.0.advanced.lnb.7.commandOrd er=cut
config.Nims.0.advanced.lnb.7.sequenceRe peat=true
config.Nims.0.advanced.lnb.7.commitedDi seqcCommand=BA
config.Nims.0.advanced.lnb.6.diseqcMode=1_1
config.Nims.0.advanced.lnb.6.uncommitte dDiseqcCommand=1
config.Nims.0.advanced.lnb.6.lof=c_band
config.Nims.0.advanced.lnb.6.fastDiseqc=true
config.Nims.0.advanced.lnb.6.sequenceRe peat=true
config.Nims.0.advanced.lnb.6.commitedDi seqcCommand=AB
config.Nims.0.advanced.lnb.6.commandOrd er=cut
config.Nims.0.advanced.lnb.9.diseqcMode=1_1
config.Nims.0.advanced.lnb.9.uncommitte dDiseqcCommand=4
config.Nims.0.advanced.lnb.9.fastDiseqc=true
config.Nims.0.advanced.lnb.9.commandOrd er=cut
config.Nims.0.advanced.lnb.9.sequenceRe peat=true
config.Nims.0.advanced.lnb.9.commitedDi seqcCommand=BB
config.Nims.0.advanced.lnb.8.diseqcMode=1_1
config.Nims.0.advanced.lnb.8.uncommitte dDiseqcCommand=1
config.Nims.0.advanced.lnb.8.lof=c_band
config.Nims.0.advanced.lnb.8.fastDiseqc=true
config.Nims.0.advanced.lnb.8.sequenceRe peat=true
config.Nims.0.advanced.lnb.8.commitedDi seqcCommand=BB
config.Nims.0.advanced.lnb.8.commandOrd er=cut
config.seek.selfdefined_46=60
config.seek.selfdefined_13=15
config.seek.selfdefined_79=300
config.osd.language=ru_RU
config.tv.lastroot=1:7:1:0:0:0:0:0:0:0:FROM BOUQUET "bouquets.tv" ORDER BY bouquet;1:7:1:0:0:0:0:0:0:0:FROM BOUQUET "userbouquet.dbe00.tv" ORDER BY bouquet;
config.tv.lastservice=1:0:1:25D:C:1:3522F80:0:0:0:
config.pep.mosquito_noise_reduction=3
config.pep.digital_contour_removal=2
config.pep.saturation=160
config.pep.sharpness=151
config.pep.block_noise_reduction=3
config.recording.margin_before=3
config.recording.keep_timers=7
config.recording.margin_after=5
config.recording.offline_decode_delay=1000
config.skin.primary_skin=classplus_hd/skin.xml
config.epg.mhw=true
config.epg.histminutes=45
config.hdmicec.fixed_physical_address=1.0.0.0
config.hdmicec.minimum_send_interval=100
config.hdmicec.control_receiver_standby=true
config.hdmicec.control_receiver_wakeup=true
config.hdmicec.tv_wakeup_detection=wakeup
config.hdmicec.volume_forwarding=true
config.audio.volume=60
config.movielist.videodirs=['/hdd/movie/']
config.movielist.btn_text=sort

А теперь вводя предыдущий код, читаем этот файл через python (заодно научимся работать непосредственно в питоне).
Для этого открываем любую телнетовскую прогу.
Например телнет в програмке DCC и логинимся в имидже:



И запускаем питон, предустановленный в имидже, просто написав команду python



И вводим тот самый код по очереди
a = open("/etc/enigma2/settings", "r")
b = a.read()

а затем попросим питон вывести на экран значение переменной b (то есть просто пишем b и нажимаем Enter)

Ввели? Убедились?

Далее обязательно закрываем файл, который открывали ранее для чтения (никогда не забывайте сделать это)
в) закрыть файл
a.close()
А вот следующий пункт выделить строки с настройкой тюнера (тюнеров) выполнить не так просто ввиду именно того, что результат чтения это только одна единая строка.
Это один из нюансов работы со строками. Конечно существует много способов обойти эту проблему. Рассмотрим один из них.
Для этого воспользуемся встроенным методом строк split, который создает список из строк, разделив именно на этих знаках \n (удалив эти знаки), снова присвоив результат какой-то переменной
c = b.split('\n')
В результате получим список, состоящий из строк (из тех самых строк файла settings).
И желательно этот код продолжаем вводить в телнете (где запустили питон в имидже).
Это нужно еще, чтобы убедиться что какую-нибудь синтаксическую ошибку не допускаем.
Я всегда так делаю, пишу код и тут же ввожу в питоне.....
Можете также "приказать питону" вывести результат c и получите примерно такой результат
Спойлер   :
>>>с = b.split('\n')
>>>c
['config.Nims.0.advanced.lnb.6.commandOrd er=cut', 'config.Nims.0.advanced.
nb.9.diseqcMode=1_1', 'config.Nims.0.advanced.lnb.9.uncommitte dDiseqcCommand=4'
 'config.Nims.0.advanced.lnb.9.fastDiseqc=true', 'config.Nims.0.advanced.lnb.9.
ommandOrder=cut', 'config.Nims.0.advanced.lnb.9.sequenceRe peat=true', 'config.N
ms.0.advanced.lnb.9.commitedDiseqcComma nd=BB', 'config.Nims.0.advanced.lnb.8.di
eqcMode=1_1', 'config.Nims.0.advanced.lnb.8.uncommitte dDiseqcCommand=1', 'confi
.Nims.0.advanced.lnb.8.lof=c_band', 'config.Nims.0.advanced.lnb.8.fastDiseqc=tr
e', 'config.Nims.0.advanced.lnb.8.sequenceRe peat=true', 'config.Nims.0.advanced
lnb.8.commitedDiseqcCommand=BB', 'config.Nims.0.advanced.lnb.8.commandOrd er=cut
, 'config.seek.selfdefined_46=60', 'config.seek.selfdefined_13=15', 'config.see
.selfdefined_79=300', 'config.osd.language=ru_RU', 'config.tv.lastroot=1:7:1:0:
:0:0:0:0:0:FROM BOUQUET "bouquets.tv" ORDER BY bouquet;1:7:1:0:0:0:0:0:0:0:FROM
BOUQUET "userbouquet.dbe00.tv" ORDER BY bouquet;', 'config.tv.lastservice=1:0:1
25D:C:1:3522F80:0:0:0:', 'config.pep.mosquito_noise_reduction=3', 'config.pep.d
gital_contour_removal=2', 'config.pep.saturation=160', 'config.pep.sharpness=15
', 'config.pep.block_noise_reduction=3', 'config.recording.margin_before=3', 'c
nfig.recording.keep_timers=7', 'config.recording.margin_after=5', 'config.recor
ing.offline_decode_delay=1000', 'config.skin.primary_skin=classplus_hd/skin.xml
, 'config.epg.mhw=true', 'config.epg.histminutes=45', 'config.hdmicec.fixed_phy
ical_address=1.0.0.0', 'config.hdmicec.minimum_send_interval=100', 'config.hdmi
ec.control_receiver_standby=true', 'config.hdmicec.control_receiver_wakeup=true
, 'config.hdmicec.tv_wakeup_detection=wakeup', 'config.hdmicec.volume_forwardin
=true', 'config.audio.volume=60', "config.movielist.videodirs=['/hdd/movie/']",
'config.movielist.btn_text=sort', '']

Вот теперь можем из этого списка выдергивать члены-строки, которые относятся к настройкам тюнера (тюнеров).
Для этого воспользуемся другим встроенным методом строк __contains__, который выделяет строки по содержанию, проверяя наличие текста в строке, который передан этому методу в качестве аргумента.
А в файле сеттингс, как мы можем легко выяснить, абсолютно все строки с настройками тюнеров содержат "слово" Nims.
То есть в этом случае мы включаем логику. И вообще, учтите в программировании без логики очень-очень трудно.
С логикой надо очень сильно дружит.........
Значит чтобы "выделить" настройки тюнеров, мы сначала создаем пустой список, а потом добавляем туда все строчки-члены предыдущего списка, которые содержат "слово" Nims. Применив оператор for для этого.

г) выделить строки с настройкой тюнера (тюнеров)

d = []
for x in c:
   if x.__contains__('Nims'):
      d.append(x)

Использовали еще один встроенный метод (но уже списка теперь) append.
Все это простые операторы и простые методы строк и списков.
Предыдущий код звучит так:
"Каждый элемент х из списка с, если он содержит подстроку Nims, добавить в новый список d".
В итоге мы получили список из строк с настройками тюнера (тюнеров).
Но список мы не можем записать в файл как строки. Соответственно теперь проведем обратную операцию, воспользовавшись другим встроенным методом join. Этот метод прямая противоположность методу split, склеивает строки из списка, вот так:

e = '\n'.join(d)
Так как питон требует в конце файла пустую строку, логика нам подсказывает, что к полученному нам бы нужно добавить символ переноса строки, то есть (включите логику и поймете, что я прав):

f =e + '\n'
Давайте взглянем в окно Geany и проверим, одно и то же ли мы с вами пишем. Чем хорош Geany, вам стоит поставить двоеточие и нажать Enter, табуляция (или пробелы, смотря как настроите) любезно будет вставлена самой прогой.



Теперь весь этот код можете ввести в окно терминала, где вы вошли в питон на имидже (по одной строке), а вконце введите f и увидите, что результатом является одна строка в памяти....

Далее создаем другой файл и записываем туда настройки тюнера.
Так как пока просто пишем код, а не плагин непосредственно, пока будем создавать файл в папке темп (чтобы проверить код) (файл скажем назовем mysettings).
То есть открываем (создаем) файл в папке темп с правами записи и записываем туда последнюю полученную строку:

g = open("/tmp/mysettings","w")
g.write(f)

И закрываем файл (обязательно)

е) закрыть файл

g.close()
Полученный код.





И введя весь этот код в терминале имиджа с вводом в питон, убеждаемся, что да код верный, вот он файл и его содержание.








Конечно, полученный результат пока мало похоже на плагин, но дойдем и до этого......


Продолжение следует......


« Последнее редактирование: 01 Декабрь 2013, 10:56:27 от ака Учкун »
  • gi 9995 vu+ ultimo
Собака лает, караван идет....

Эти пользователи поблагодарили Вас за сообщение:

Оффлайн ака Учкун

  • Спец
  • *
  • СПАСИБО:
  • - Вы поблагодарили: 438
  • - Вас поблагодарили: 3688
  • Сообщений: 895
  • Пол: Мужской
  • Зарегистрирован: 2012-07-15
    Местоположение: город Навои
    Возраст: 53
    • Просмотр профиля

Пишем плагин сами или случайные уроки по python
« Ответ #2 : 01 Декабрь 2013, 16:05:32 »
С кодом, с помощью которого будем сохранять настройки тюнера (тюнеров) разобрались.
Теперь из этой второй части
2. Сохранить плагин с этими настройками и в последующем установить плагин с этими сохраненными настройками на вновь установленный нами имидж, ну и применить эти настройки в новом имидже.

будем разбираться с кодом, который будет восстанавливать настройки на вновь установленном имидже.

То есть оформление непосредственно самого плагина оставим напоследок. Для любой программной задачи, главное код.

С помощью значит этого кода, мы поняли, что сохраним настройки

a = open("/etc/enigma2/settings", "r")
b = a.read()
a.close()
c = b.split('\n')
d = []
for x in c:
if x.__contains__('Nims'):
d.append(x)
e = '\n'.join(d)
f = e + '\n'
g = open("/tmp/mysettings","w")
g.write(f)
g.close()

Конечно при оформлении плагина изменим путь сохранения настроек с папки темп в другую нужную папку.
Затем пользователь получается сохранить физически плагин с настройками куда нибудь на комп скажем, установит имидж, скопирует папку плагина скажем в папку /usr/lib/enigma2/python/Plugins/Extensions/, перегрузится, откроет окно плагина и выберет восстановление настроек.
Вот сейчас нужно написать код, который и будет задействован после именно этого выбора восстановления пользователем.

Алгоритм в данном случае также достаточно прост (вроде бы):
а) открыть ранее сохраненный файл на чтение
б) прочитать файл
в) закрыть файл
г) открыть файл /etc/enigma2/settings,
д) удалить из него строчки, касающиеся настроек тюнера
е) и наоборот записать туда ранее сохраненные строчки с настройками тюнера.

По пунктам будем решать задачу. Пишем код.

а) открыть ранее сохраненный файл на чтение
Пока мы сохраняли файл в папку темп, следовательно
a = open("/tmp/mysettings", "r")
Ну и прочитать файл
б) прочитать файл
b = a.read()
Спойлер   :
Здесь обращаю внимания на имена переменных a или b придумывайте любые имена (я для сокращения кода называю одной буквой), лишь бы они не совпадали со встроенными или другими именами и случаем не переписывали ничего.......

в) закрыть файл
a.close()

А вот с пунктами г, д, е немного незадача.
То есть согласно выработанному нами алгоритму, мы должны открыть файл /etc/enigma2/settings и удалить из него определенные строчки, и наоборот записать туда другие строчки из нашего ранее сохраненного файла.
А так как мы уже знаем, что файл settings это текстовый файл состоящий из последовательности символов (переход на другую строчку тоже символ \n), то бишь это строковый файл, ее нельзя изменять. Из питона знаем строка неизменяемая последовательность.
Соответственно, исходя из этого обстоятельства мы перепишем наш последний алгоритм действий:

а) открыть ранее сохраненный файл на чтение (уже выполнили)
б) прочитать файл  (уже выполнили)
в) закрыть файл  (уже выполнили)
г) открыть файл /etc/enigma2/settings для чтения
д) удалить из него строчки, касающиеся настроек тюнера
е) и наоборот записать туда ранее сохраненные строчки с настройками тюнера.
д) прочитать файл /etc/enigma2/settings
e) закрыть файл /etc/enigma2/settings
ж) методом split создать список строк
и) удалить из этого списка те строки в которых есть подстрока Nims (списки как известно можно изменять)
к) Список с оставшимися строками с помощью метода join вновь объединить в строку
л) методом простой конкатенации соединить строки полученные из файлов  /etc/enigma2/settings и /tmp/mysettings и записать новый файл settings
м) этим новым файлом заменить файл /etc/enigma2/settings


Ого, задача как видим усложнилась (из-за неизменяемости строк в питоне), но она все же по-прежнему выполнима.
Спойлер   :
Еще раз подчеркну, чтобы придумать такой алгоритм, кроме собственно знаний питона (что строки неизменяемы, но списки-то изменяемы), нужна железная логика, только и только логика помогает придумывать правильные, точные алгоритмы....

Идем дальше по пунктам.
г) открыть файл /etc/enigma2/settings для чтения
i = open("/etc/enigma2/settings", "r")
д) прочитать файл /etc/enigma2/settings
k = i.read()
e) закрыть файл /etc/enigma2/settings
i.close()
е) методом split создать список строк
m = k.split('\n')
Спойлер   :
В процессе написания кода время от времени не забываем вводить это непосредственно в питон и смотреть результаты, требуя от питона вывести полученное значение той или иной переменной....

и) удалить из этого списка те строки в которых есть подстрока Nims
Решим эту задачу от обратного, то есть сохраним в этом списке только те строки, в которых нет подстроки (то бишь просто "слова")  Nims:
v = []
for x in m:
if not x.__contains__('Nims'):
v.append(x)

То бишь последний код означает:
Спойлер   :
"для каждой строки x в списке m, если эта строка НЕ СОДЕРЖИТ (not) подстроку Nims, добавить в новый список v

к) Список с оставшимися строками с помощью метода join вновь объединить в строку
z = '\n'.join(v)
Спойлер   :
Вот здесь уже не требуется добавлять в конец строки знак перехода на новую, так как этот знак уже там есть (снова об этом говорит только логика, если вы его включили)....

л) методом простой конкатенации соединить строки полученные из файлов  /etc/enigma2/settings и /tmp/mysettings и записать новый файл settings
new = z + bЭто есть простая конкатенация, то есть сложение двух строк, получаем одну объединенную строку.
Создаем в папке темп новый файл settings (с правами на запись) и пишем туда полученное:

s = open("/tmp/settings", "w")
s.write(new)

Закрываем файл (действие обязательное)
s.close()
Вот весь код второго этапа (восстановление настроек)

a = open("/tmp/mysettings", "r")
b = a.read()
a.close()
i = open("/etc/enigma2/settings", "r")
k = i.read()
i.close()
m = k.split('\n')
v = []
for x in m:
if not x.__contains__('Nims'):
v.append(x)
z = '\n'.join(v)
new = z + b
s = open("/tmp/settings", "w")
s.write(new)
s.close()

Или так на экране в програмке Geany:




Чтобы проверить, не ошиблись ли где, снова открываем телнет в програмке DCC, запускаем питон на нем, дав команду
python
И строчку за строчкой вводим написанный нами код.

Спойлер   :
Если вдруг не знаете, в консоль (а терминал это и есть консоль) можно вводить текст, просто скопировав, а затем в окне терминала просто нажимаем правую кнопку мыши....

Все нормально, файл сеттингс в папке темп создался (проверяйте сами)



Остается последнее, собственно применить эти настройки, то есть в нашем случае просто заменить файл settings находящийся в папке /etc/enigma2/, другим файлом settings созданным нами в папке темп.
Здесь есть вот какой нюанс.
Этот файл (/etc/enigma2/settings) является системным, в котором имидж хранить свои настройки, соответственно любые записи которые мы туда впишем, имидж при перезагрузке перепишет на свои.
Чтобы этого не произошло, нужно остановит имидж, перезаписать этот файл и вновь запустит. Тогда имидж будет думать, что сам сохранил эти настройки при предыдущем отключении и применит эти настройки.
Но так как, если мы остановим имидж, остановится естественно и плагин наш, задачу замены этого файла мы будем решат скриптом, естественно заложив в плагин запуск этого скрипта в нужный момент. Код запуска этого скрипта (в нужный момент) напишем, когда будем оформлять интерфейс плагина (код очень простой).
 А сам скрипт тоже простой, это уже обычная командная строка.......

#!/bin/sh
echo ""
echo ""
init 4
rm -rf /etc/enigma2/settings
cp /tmp/settings /etc/enigma2/settings
rm -rf /tmp/settings
init 3
exit 0

Это простые команды удаления и копирования. Можно добавить еще вывод сообщений в консоль (хотя пользователи ее не читают)....

#!/bin/sh
echo ""
echo ""
echo "Restoring settings"
echo ""
echo ""
echo "GUI will restart now!"
echo ""
echo ""
init 4
rm -rf /etc/enigma2/settings
cp /tmp/settings /etc/enigma2/settings
rm -rf /tmp/settings
init 3
exit 0

Этот скрипт положим наверно вовнутрь плагина и плагин запустит его в нужный момент.

Собственно, непосредственно с самой задачей в питоне мы справились.
Осталось оформить все это в виде плагина....

Далее будем именно это рассматривать...

Продолжение следует......

« Последнее редактирование: 01 Декабрь 2013, 16:34:43 от ака Учкун »
  • gi 9995 vu+ ultimo
Собака лает, караван идет....

Эти пользователи поблагодарили Вас за сообщение:

Оффлайн ака Учкун

  • Спец
  • *
  • СПАСИБО:
  • - Вы поблагодарили: 438
  • - Вас поблагодарили: 3688
  • Сообщений: 895
  • Пол: Мужской
  • Зарегистрирован: 2012-07-15
    Местоположение: город Навои
    Возраст: 53
    • Просмотр профиля

Пишем плагин сами или случайные уроки по python
« Ответ #3 : 03 Декабрь 2013, 21:05:21 »
Если изучали питон, знаете, что графический интерфейс создается к примеру с помощью модуля Tkinter.
Так как мы перед собой ставим задачу научится писАть или хотя бы править плагины на имидже enigma2, сразу скажу, забудьте про Tkinter.
Нам врядь ли понадобится напрямую работать с этим модулем.
Дело в том, что разработчики enigma2 уже позаботились о графическом интерфейсе для плагинов в том числе.
В имидже уже имеются готовые модули окон (Screen), которые достаточно в плагине только импортировать.
Эти окна-Screen находятся в имидже по пути /usr/lib/enigma2/python/Screen/.
К примеру, если вы разработаете плагин-плеер для какого-нибудь видеоформата, можете использовать любой из этих окон-screen
Infobar
DVD

Также известно, что вообще питон очень богат на готовые библиотечные модули, которыми просто нужно пользоваться, а кроме того еще и изучая enigma2,
мы узнаем что в имидже по пути /usr/lib/enigma2/python/Components/ находятся также немало модулей, которыми тоже нужно пользоваться.

Ну вот и попытаемся написать интерфейс плагина с использованием всего этого.

Снова подготовим програмку Geany для написания кода.
Тот код, который мы уже написали относится к двум событиям в плагине, то есть две части написанного нами кода это есть два события.
Первое событие назовем - Сохранение текущих настроек тюнера (тюнеров).
Второе событие - Применение ранее сохраненных настроек тюнера (тюнеров).


Нам остается написать весь остальной код для окончательного оформления плагина.
Порядок действий нашей дальнейшей работы:
1. Определить какое окно-Screen нам нужно импортировать и написать инструкцию __init__ со всем необходимыми виджетами,
с нужным акшинмапом и так далее.
2. Затем сразу определится с разработкой главного окна в xml.
3. Разработать меню и обработать события элементов меню и кнопок.
4. При необходимости написать (воспользовавшись готовым шаблоном) языковую часть плагина с файлами .po и .mo
5. Последний штрих - выбрать в каком меню имиджа нужно отобразить плагин и написать код запуска.......


По порядку.
1. Определить какое окно-Screen нам нужно импортировать и написать инструкцию __init__ со всем необходимыми виджетами.

Откроем новый файл снова по шаблону main.py и не забываем про униксовые окончания строк.
Очищаем окно Geany от шаблонного кода и приступаем.

Как уже сказал, окно будем просто импортировать из готового /usr/lib/enigma2/python/Screen/.
Нам в данном случае подходит окно-screen собственно под названием Screen.
Значит первой строкой нашего кода будет импорт этого модуля

from Screens.Screen import Screen

Спойлер   :
Как импортировать модули, когда через from-import, а когда через import, а в каких случаях импортировать весь модуль через
звездочку вы уже надеюсь почитали. Также как и про переменную path, из-за которого собственно и не надо указывать
полный путь к папке Screens.... Это тоже еще только азы питона....

Здесь нужно разьяснение. Более продвинувшись в питоне и открыв в имидже этот файл Screen, сами разберетесь в его коде, а пока скажу вот что.
В этом файле разработано скажем "эфемерное" окно. Там нет ни размеров, и естественно ни виджетов-элементов....
Все это мы сами напишем.
Импортировав  Screen мы тутже его применяем.

То есть сперва-наперва создаем класс, придумав название, в нашем случае скажем NimSettings и передаем ему в качестве аргумента (вернее как суперкласс) этот самый Screen:
 
class NimSettings(Screen):
Так как при вызове этого класса (читай - главного окна плагина), сразу же мы должны лицезреть не пустое окно-Screen,
то есть требуется гарантировать чтобы окно (то бишь класс) сразу содержал такие атрибуты как скажем меню, кнопки, название окна,
создаем инструкцию-функцию с помощью метода под названием __init__ (название встроенное, а тело метода создаем сами).
Не знаю, сумел ли я объяснить (я то сам тоже не сразу понял), но методом __init__ следует пользоваться если необходимо, чтобы интерпретатор
автоматически вызывал метод при вызове самого класса, без необходимости вызова по имени метода.....


Спойлер   :
Не отчаивайтесь, даже если не поняли. В процессе затем поймете.
Пока просто имейте ввиду, любые атрибуты внутри метода __init__ присваиваются классу автоматом при вызове самого класса.
А остальные атрибуты этого класса необходимо будет вызывать по имени, например так
имя_класса.имя_метода()
А нужно или не нужно применять метод __init__ будете решать сами, в данном случае нужно, так как это окно менюшки плагина.....

Вот и начнем конструировать первую обязательную в нашем случае функцию (__init__) для класса-окна (далее для правильного восприятия и понимания буду писать сразу весь код сначала):

class NimSettings(Screen):
    def __init__(self, session):
   
      
      
   
Почему в скобках у метода __init__ мы записали два аргумента self и session?
self - атрибут обязательный, означающий экземпляр объекта. То есть интерпретатор при вызове объекта создает его экземпляр, потому self обязателен.
Может немного сложно, но понимание роли self имеет ключевое значение.
А session, это атрибут ожидаемый от вызывающей функции....

Добавляем из суперкласса (то есть из импортируемого Screen) вызываем метод __init__ (обязательно):

class NimSettings(Screen):
    def __init__(self, session):
    Screen.__init__(self, session)

      
Спойлер   :
Почему здесь session, изучите сам файл Screen и увидите там
def getRelatedScreen(self, name):
      if name == "session":
         return self.session.screen

вот поэтому.....
         


Спойлер   :
Так скрупулезно прохожу каждый пункт, хотя честно пока это вещи в принципе элементарные, но хочу чтобы мы каждый шаг совершали только понимаюче,
каждую букву кода буквально осмыслывали, откуда же взялось это и так далее...
Тогда из нас толк выйдет....


Продолжаем оформлять наш метод __init__ и приступаем непосредственно к элементам самого окна.
Здесь опять нужно отступление.
Смотрите вот предыдущую строчку мы совершенно не зря вписали, не зря импортировали инициализацию модуля Screen из
одноименного файла в папке Screens. Потому что далее будем использовать атрибуты-методы из него, а также из модулей, который уже импортирует он.
Например из компонента GUISkin находящегося в папке Components уже.
Далее буду просто упоминать из какого модуля какой метод.....

Вот воспользуемся методом setTitle, который разработан уже в компоненте GUISkin (откройте его и поизучайте), чтобы сконструировать
название окна меню, передав этому методу в качестве аргумента непосредственно придуманное нами название окна в виде строки:

self.setTitle("Plugin for restoring tuner settings")
И тут же изменим эту строчку, чтобы это самое название переводилось имиджем на русский.
Что нужно сделать для этого. Нужно импортировать gettext (сделаем потом) и указать ему, что строку нужно переводить, для
этого достаточно взять строку в скобки и перед скобками вставить нижнее подчеркивание, то есть вот так

self.setTitle(_("Plugin for restoring tuner settings"))
Весь код сначала класса

class NimSettings(Screen):
    def __init__(self, session):
    Screen.__init__(self, session)
self.setTitle(_("Plugin for restoring tuner settings"))
      
Правда если действительно изучите GUISkin, то увидите что также совершенно равноценно этому будет и простой виджет

self["Title"] = StaticText(_("Plugin for restoring tuner settings"))
И нужно будет создать виджет с сурчом "Title", и это действительно тоже самое.....
Кстати вот таким макаром self["Title"] - добавление к self строки в квадратных скобках, создаются виджеты в методе __init__


Спойлер   :
Правда в этом варианте нам нужно будет указать, собственно откуда взяли метод StaticText , который мы "одолжим" у одноименного модуля-компонента из папки /usr/lib/enigma2/python/Components/Sources/StaticText
То есть добавить этот модуль в импортируемые (в самое начало нашего кода)
from Components.Sources.StaticText import StaticText

Так, название самого окна меню создали. Теперь подумаем, что еще будет в нашем меню.
а) В нашем случае нужно не конфиг-меню (то есть с ответами да-нет, с выбором вариантов), а простое меню из двух пунктов.
Первый будет "Сохранение настроек тюнеров",
Второй будет "Восстановление настроек тюнеров".
б) И кроме меню, наверно нужен еще   простой текстовый виджет, где будет написано "Нажмите ОК для выбора действия", ведь всегда найдутся непонятливые,
что для выбора нужного пункта на нем просто нужно нажать ОК.   
в) Ну и одна наверно только кнопка - красная с надписью "Выход" или "Назад", кому как нравится.


Все это конечно внутри метода __init__
Меню создадим тоже в виде виджета. И мы знаем что наше меню это список.
Поэтому снова воспользуемся готовым модулем List из папки Sources имиджа, импортируем этот модуль (в самом начале кода)

from Components.Sources.List import List
В методе __init__ создаем для начала пустой список (назвав его как хотим):
nashemenu = []
И далее создаем виджет меню, передав модулю List этот список (который затем заполним) в качестве аргумента:

self["menu"] = List(nashemenu)
И весь код сначала класса

class NimSettings(Screen):
    def __init__(self, session):
    Screen.__init__(self, session)
self.setTitle(_("Plugin for restoring tuner settings"))
nashemenu = []
self["menu"] = List(nashemenu)
      

Следующий б) текстовый виджет
Для вывода простого текста воспользуемся модулем Label из компонентов (для интереса изучайте в папке /usr/lib/enigma2/python/Components/Label)
Как обычно импортируем его в начале кода

from Components.Label import Label
Кстати на этот момент весь наш импорт

from Screens.Screen import Screen
from Components.Sources.List import List
from Components.Label import Label

И пишем код виджета с возможностью перевода

self["text"] = Label(_("Press OK for action"))
И создаем красную кнопку, также виджетом

self["red_key"] = Label(_("Close"))
И весь код сначала класса

class NimSettings(Screen):
    def __init__(self, session):
    Screen.__init__(self, session)
self.setTitle(_("Plugin for restoring tuner settings"))
nashemenu = []
self["menu"] = List(nashemenu)
self["text"] = Label(_("Press OK for action"))
self["red_key"] = Label(_("Close"))
      
      
Нужно также создать акшинмап, то есть функцию для кеймапа, то бишь действия при нажатии кнопок.
Для этого перво-наперво импортируем модуль ActionMap из компонентов

from Components.ActionMap import ActionMap
А сам код сначала напишу, потом поясню.

self["shortcuts"] = ActionMap(["ShortcutActions", "WizardActions"],
{
"cancel": self.cancel,
"back": self.cancel,
"red": self.cancel,
"ok": self.action,
})
         
Итак здесь self["shortcuts"] понятно название, но shortcuts произвольно, можете назвать как хотите, главное уже то, что справа от знака присваивания =
В качестве аргументов импортируемому модулю ActionMap передаются, сначала названия контекстов кеймапа имиджа.
Ну то есть в данном случае это два контекста "ShortcutActions", "WizardActions". Их мы берем из файла кеймап.хмл имиджа. Они там прописаны как
map context=
Надеюсь обьяснять где находится кеймап.хмл не нужно.
А вот второй аргумент, это словарный, справа названия кнопок из тех самых двух контекстов, но нужные только нам, а справа названия функций (сами придумаем), а тело самых этих функций,
то есть обработчики событий напишем впоследствии дальше......

И последнее в методе __init__ собственно должны написать название инструкции по созданию списка меню, который у нас пока пуст как помните....
Название также произольное....
Тело функции допишем впоследствии...

self.createList()
Итого пока весь импорт и весь класс

from Screens.Screen import Screen
from Components.Sources.List import List
from Components.Label import Label


class NimSettings(Screen):
    def __init__(self, session):
    Screen.__init__(self, session)
self.setTitle(_("Plugin for restoring tuner settings"))
nashemenu = []
self["menu"] = List(nashemenu)
self["text"] = Label(_("Press OK for action"))
self["red_key"] = Label(_("Close"))
self["shortcuts"] = ActionMap(["ShortcutActions", "WizardActions"],
{
"cancel": self.cancel,
"back": self.cancel,
"red": self.cancel,
"ok": self.action,
})
self.createList()





      
      
Вообще-то в самом начале класса должен быть хмловский код окна-Screen, и затем уже метод __init__, но так как этот хмловский код без этого метода не создашь,
порядок действий выбран таков.

Далее, с помощью уже не питона, а хмл создадим само окно.
А затем закончим код класса, разработкой функций cancel, action, createList...

И в самом конце оформим вызов плагина.......

На сегодня все пока.
Думаю, поняли из вышенаписанного каждую строчку кода, начиная - почему классу в качестве аргумента передали модуль Screen, заканчивая - как создавать акшинмап.....

Продолжение следует.......



« Последнее редактирование: 03 Декабрь 2013, 21:14:33 от ака Учкун »
  • gi 9995 vu+ ultimo
Собака лает, караван идет....

Эти пользователи поблагодарили Вас за сообщение:

Оффлайн vadim72

  • Активный участник
  • ***
  • СПАСИБО:
  • - Вы поблагодарили: 74
  • - Вас поблагодарили: 40
  • Сообщений: 112
  • Пол: Мужской
  • Зарегистрирован: 2012-07-11
    Местоположение: россия
    • Просмотр профиля

Пишем плагин сами или случайные уроки по python
« Ответ #4 : 07 Декабрь 2013, 05:18:46 »
отлично написано  и главное доступным языком огромное спасибо за начало развития этого направления
конечно кому как а мне пришлось три раза перечитывать и ещё раза три наверное перечитаю чтобы закрепить и запомнить
некоторые моменты работы с терминалом у меня вышли с ошибкой но ничего допёрло как нужно сделать
d = []
for x in c:
   if x.__contains__('Nims'):
      d.append(x)
здесь у кого не получилось, нужно нажать 2 раза интер ,потом только новую команду вводить
команды можно вводить частями по несколько сразу - проверил  получилось
у меня давно такой вопрос крутился
почему некоторые команды вводятся с отступами в право - так по моему во всех языках пишут и имеет ли значения сколько отступа нужно использовать ?
ждём продолжения по наличию свободного времени у вас
у меня тоже начались командировки под конец года
 
  • azbox

Оффлайн ака Учкун

  • Спец
  • *
  • СПАСИБО:
  • - Вы поблагодарили: 438
  • - Вас поблагодарили: 3688
  • Сообщений: 895
  • Пол: Мужской
  • Зарегистрирован: 2012-07-15
    Местоположение: город Навои
    Возраст: 53
    • Просмотр профиля

Пишем плагин сами или случайные уроки по python
« Ответ #5 : 07 Декабрь 2013, 06:20:46 »
........
ждём продолжения по наличию свободного времени у вас
у меня тоже начались командировки под конец года

Вчерась приехал с командировки.
Не знаю у тебя как, у меня командировки всегда внезапные черт возьми.
С этим ФАКом завелся и так хотел его закончить и на тебе командировка на несколько дней......

Надеюсь сегодня меня оставят в покое и допишу уж сегодня-завтра уроки эти....

.......
у меня давно такой вопрос крутился
почему некоторые команды вводятся с отступами в право - так по моему во всех языках пишут и имеет ли значения сколько отступа нужно использовать ?
......

Надо, надо все же учить питон, пойми только на основе моих уроков невозможно научиться даже редактировать что-то в питоне.
То, о чем ты спрашиваешь это составные инструкции, после знака двоеточия (после заглавия) идет отступ-вложение.
А использовать сколько знаков отступов или табуляцию, это на выбор программиста, как ему удобно. Но обычно используют 4 знака отступа, либо одну табуляцию.
Я лично использую табуляцию.
Но все это повторюсь - всего лишь азы питона.

.......
некоторые моменты работы с терминалом у меня вышли с ошибкой но ничего допёрло как нужно сделать
d = []
for x in c:
   if x.__contains__('Nims'):
      d.append(x)
здесь у кого не получилось, нужно нажать 2 раза интер ,потом только новую команду вводить
команды можно вводить частями по несколько сразу - проверил  получилось
.....

Хе, горе от ума называется, я почему-то думал, что любой догадается, что сначала нужно выйти из блока-инструкции а потом ввести следующую команду.
Сейчас понял, откуда, если даже не знаете что такое собственно составная инструкция.
Проще говоря, при интерактивном вводе, если пошли отступы в коде, после последней строки с отступом, вы должны выйти из составной инструкции сначала.
То есть питон ожидает следующую строчку внутри составной инструкции. А нужно вводить уже строчку кода за пределами составной инструкции, то есть нажимая еще раз ОК даете понять питону, что инструкция закончилась.

Но опять-таки ребята, это снова же азы питона, если собственно вообще не будете изучать питон, понять до конца смысл моих уроков не сможете.
Вы будете пытаться их вызубрить, а не понять, забудете через два дня все.

Если хотим хоть даже на самом низком, но профессиональном уровне овладеть питоном, подходите к этому академически.
  • gi 9995 vu+ ultimo
Собака лает, караван идет....

Эти пользователи поблагодарили Вас за сообщение:

Оффлайн ака Учкун

  • Спец
  • *
  • СПАСИБО:
  • - Вы поблагодарили: 438
  • - Вас поблагодарили: 3688
  • Сообщений: 895
  • Пол: Мужской
  • Зарегистрирован: 2012-07-15
    Местоположение: город Навои
    Возраст: 53
    • Просмотр профиля

Пишем плагин сами или случайные уроки по python
« Ответ #6 : 07 Декабрь 2013, 11:21:04 »
Продолжаем.

Напоминаю полученный на этот момент код плагина

from Screens.Screen import Screen
from Components.Sources.List import List
from Components.Label import Label


class NimSettings(Screen):
def __init__(self, session):
Screen.__init__(self, session)
self.setTitle(_("Plugin for restoring tuner settings"))
nashemenu = []
self["menu"] = List(nashemenu)
self["text"] = Label(_("Press OK for action"))
self["red_key"] = Label(_("Close"))
self["shortcuts"] = ActionMap(["ShortcutActions", "WizardActions"],
{
"cancel": self.cancel,
"back": self.cancel,
"red": self.cancel,
"ok": self.action,
})
self.createList()
      
Ну и кроме того, коды по сохранению настроек и применению настроек, которые мы в самом начале разработали, держим пока в уме (они сохранены на диске)......

Из этого кода например из части действий нажатия кнопок думаю вы поняли, что вот эти три ключа "cancel", "back", "red" это разновидности красной кнопки в разных имиджах и в разных ресах. В некоторых ресах есть еще и кнопка "назад" например........

Разработаем конструкцию самого окна-меню плагина.
В принципе это уже не питон.
Это уже xml.
То есть нужно разработать окно-Screen этого плагина для скина.
Это уже чисто построение каркаса в скиностроении.
Поэтому подробно показывать как построил каркас на основе уже готовых виджетов в инструкции __init__ не буду. Как строить каркасы в скинах читайте в другом FAQ здесь FAQ: Переделка скина для начинающих
Поясню только основное.
Каркас для скина размещается в самом начале класса, то есть сразу за заглавием класса
class NimSettings(Screen):
и синтаксис такой: переменной skin присваивается весь текст-каркас этого окна.
Ну то есть
skin = каркас_скина
Только так как каркас скина это многострочный текст, по правилам питона он берется в тройные кавычки
"""каркас_скина_в_виде_многострочного_текс та"""

Вобщем создаем каркас окна-Screen с названием точно таким же как название класса (это обязательно), title можем пустой оставить или написать что угодно(все равно применится self.setTitle), атрибуты (размер скина, расположение на экране) придумываем как нам нужно, и добавляем все виджеты (красную кнопку, виджет меню, виджет текст) из инструкции  __init__
Я обычно строю каркас плагина в окне e2skinner.
Беру какой-нибудь похожий каркас и меняю там виджеты на свои.
Здесь главное не ошибится например в сурчах.
Вот к примеру кнопку можно оформить как через компонент Label, то есть так (как в нашем примере):
self["red_key"] = Label(_("Close"))а можно и через сурч StaticText, то есть так:
self["red_key"] = StaticText(_("Close"))
В первом случае сам виджет в каркасе будет выглядеть так, просто через name =...:
<widget name="red_key" position="215,408" zPosition="2" size="165,30" font="Regular; 20" halign="center" valign="center" backgroundColor="#41000000" foregroundColor="#00dddddd" transparent="1" />А во втором случае это будет через source и через рендер, так:
<widget source="red_key" render="Label" position="215,408" zPosition="2" size="165,30" font="Regular; 20" halign="center" valign="center" backgroundColor="#41000000" foregroundColor="#00dddddd" transparent="1" />
Тонкости совсем несложные, думаю быстро разберетесь.
А меню само будем строить через рендер ListBox и с помощью TemplatedMultiContent
Вобщем итого получаем такой код вместе с хмл, то есть с каркасом:

from Screens.Screen import Screen
from Components.Sources.List import List
from Components.Label import Label


class NimSettings(Screen):
skin = """
<screen name="NimSettings" position="center,center" size="595,450" title="Backup settings for current skin">
  <widget name="text" position="69,339" size="500,30" foregroundColor="#00009a00" font="Regular;22" halign="right" transparent="1" />
  <ePixmap position="215,438" zPosition="1" size="165,2" pixmap="/usr/lib/enigma2/python/Plugins/Extensions/TunerSettingsRestore/images/red.png" alphatest="blend" />
  <widget name="red_key" position="215,408" zPosition="2" size="165,30" font="Regular; 20" halign="center" valign="center" backgroundColor="#41000000" foregroundColor="#00dddddd" transparent="1" />
  <widget source="menu" render="Listbox" position="15,10" size="570,100" scrollbarMode="showOnDemand" transparent="1">
    <convert type="TemplatedMultiContent">
      {"template": [
        MultiContentEntryText(pos = (15, 5), size = (570, 30), font=0, flags = RT_HALIGN_LEFT, text = 0)
        ],
        "fonts": [gFont("Regular", 23)],
        "itemHeight": 40
      }
    </convert>
  </widget>
</screen>"""

def __init__(self, session):
Screen.__init__(self, session)
self.setTitle(_("Plugin for restoring tuner settings"))
nashemenu = []
self["menu"] = List(nashemenu)
self["text"] = Label(_("Press OK for action"))
self["red_key"] = Label(_("Close"))
self["shortcuts"] = ActionMap(["ShortcutActions", "WizardActions"],
{
"cancel": self.cancel,
"back": self.cancel,
"red": self.cancel,
"ok": self.action,
})
self.createList()


Спойлер   :
На самом деле конечно, здесь очень много нюансов, как впрочем вообще в плагиностроении.....
Этот самый каркас, разработанный нами, не обязательно будет применен в имидже.
Для парсера в имидже, более приоритетное значение имеет текущий скин.
То есть если текущем скине есть окно-Screen с этим названием (с названием этого класса), то будет применено
именно окно-Screen из текущего скина.
Также можно вообще не разрабатывать окно-Screen, а воспользоваться одним из универсальных
окон-Screen. Например универсальное окно Setup в имидже Пли, в котором даже есть description
как знаете. В том случае естественно нужно название виджетов привести в соответствии с
тим окном Setup. Но мы в нашем случае никак не могли воспользоваться этим окном Setup,
так как там меню конфиговое, а у нас нет......

      
Пришла очередь разработать функции self.cancel, self.action, self.createList.
Сначала createList, то есть меню плагина, оно пока пустое.
С помощью встроенного атрибута append добавляем в этот пустой список два пункта, а затем
этот уже непустой список передаем в качестве аргумента методу setList модуля List (чтобы понять, изучите
импортированный нами List из папки Sources), то есть так:

def createList(self):
nashemenu = []
nashemenu.append((_("Save tuner settings"), "save"))
nashemenu.append((_("Restore tuner settings"), "restore"))
self["menu"].setList(nashemenu)
   
Разберем каждую строчку снова.
nashemenu = []     # Просто присвоили (снова) пустой список переменной nashemenu
nashemenu.append((_("Save tuner settings"), "save"))  # добавили один элемент списка, то есть попросту первую строчку меню.

Здесь нужно понять вот что. Встроенный метод списков append добавить в список первый атрибут, который мы ему передали,
то есть вот это _("Save tuner settings"), а второй атрибут в данном случае будет просто индексом.
Этот второй атрибут-индекс, в данном случае наша питоновская импровизация, для того чтобы впоследствии
именно по нему, по второму атрибуту-индексу определить собственно в какой строчке нажал кнопку ОК пользователь.
Это именно питоновская импровизация, вы же можете пойти другим путем и определить это дело по-другому,
использую другие богатые возможности питона.
Понимание этого потихоньку придет к вам, если будете вникать в смысл, а не тупо копировать.....
Пока же просто имейте ввиду, что именно по этим двум "словам"-индексам "save" и "restore" мы будем определять,
в какой строчке пользователь нажал кнопку ОК (то есть хочет сохранить настройки или наоборот применить ранее сохраненные).

self["menu"].setList(nashemenu) # Это опять-таки применение метода setList из импортированного модуля List

Чтобы не путаться, пишем снова весь код, который получили

from Screens.Screen import Screen
from Components.Sources.List import List
from Components.Label import Label


class NimSettings(Screen):
skin = """
<screen name="NimSettings" position="center,center" size="595,450" title="Backup settings for current skin">
  <widget name="text" position="69,339" size="500,30" foregroundColor="#00009a00" font="Regular;22" halign="right" transparent="1" />
  <ePixmap position="215,438" zPosition="1" size="165,2" pixmap="/usr/lib/enigma2/python/Plugins/Extensions/TunerSettingsRestore/images/red.png" alphatest="blend" />
  <widget name="red_key" position="215,408" zPosition="2" size="165,30" font="Regular; 20" halign="center" valign="center" backgroundColor="#41000000" foregroundColor="#00dddddd" transparent="1" />
  <widget source="menu" render="Listbox" position="15,10" size="570,100" scrollbarMode="showOnDemand" transparent="1">
    <convert type="TemplatedMultiContent">
      {"template": [
        MultiContentEntryText(pos = (15, 5), size = (570, 30), font=0, flags = RT_HALIGN_LEFT, text = 0)
        ],
        "fonts": [gFont("Regular", 23)],
        "itemHeight": 40
      }
    </convert>
  </widget>
</screen>"""

def __init__(self, session):
Screen.__init__(self, session)
self.setTitle(_("Plugin for restoring tuner settings"))
nashemenu = []
self["menu"] = List(nashemenu)
self["text"] = Label(_("Press OK for action"))
self["red_key"] = Label(_("Close"))
self["shortcuts"] = ActionMap(["ShortcutActions", "WizardActions"],
{
"cancel": self.cancel,
"back": self.cancel,
"red": self.cancel,
"ok": self.action,
})
self.createList()

def createList(self):
nashemenu = []
nashemenu.append((_("Save tuner settings"), "save"))
nashemenu.append((_("Restore tuner settings"), "restore"))
self["menu"].setList(nashemenu)
      

Следующая функция, это действие, происходящее при нажатии красной кнопки (или exit), то есть функция self.cancel , так как это всего лишь закрытие окна, это самая простая функция:

def cancel(self):
self.close()

Тут ничего объяснять не надо, close он и в африке close....

Осталась главная функция - это действие, которое будет происходит при нажатии кнопки ОК, то есть функция    self.action

Продолжение следует.....

« Последнее редактирование: 09 Декабрь 2013, 17:27:28 от ака Учкун »
  • gi 9995 vu+ ultimo
Собака лает, караван идет....

Эти пользователи поблагодарили Вас за сообщение:

Оффлайн ака Учкун

  • Спец
  • *
  • СПАСИБО:
  • - Вы поблагодарили: 438
  • - Вас поблагодарили: 3688
  • Сообщений: 895
  • Пол: Мужской
  • Зарегистрирован: 2012-07-15
    Местоположение: город Навои
    Возраст: 53
    • Просмотр профиля

Пишем плагин сами или случайные уроки по python
« Ответ #7 : 08 Декабрь 2013, 10:50:27 »
Ну и теперь функция self.action, то есть обработчик событий при нажатии кнопки ОК.
Вот здесь наконец нам понадобится тот самый код, который мы в самом начале разработали.
Это главная функция, которая и составляет смысл нашего плагина.
В качестве аргумента функции, кроме собственно self, создадим аргумент для вычисления выбранного пункта меню и назовем по смыслу currentSelect и по умолчанию присвоим этому аргументу значение "Ложь", то есть так:

def action(self, currentSelect = None):
Попробую пояснить.
Если просто создать аргумент (не приравнивая его к значению "Ложь") и далее проверять какая эта строка, при первом прохождении функции (то есть при первой проверке, на каком пункте курсор) полученное значение будет присвоино этому аргументу и при следующей проверке(если вы это сделали до перезагрузки) поведение будет непредсказуемым, то есть окажется что курсор не на той строчке или на двух строчках сразу (так как предыдущее значение-то не сбросилось, а сохранилось).
Именно чтобы избежать этого, каждый раз при начале проверки, значение переменной-аргумента currentSelect обнуляется и сам код именно поэтому начнем с условия "Если нет выбора"- if currentSelect is None:

def action(self, currentSelect = None):
if currentSelect is None:

и высчитываем спокойно текущую строчку:

currentSelect = self["menu"].getCurrent()[1]
Тут очень просто self["menu"] это как известно из инструкции __init__ и есть импортированный модуль List, а у этого модуля есть метод для вычисления текущей строки getCurrent() (проверяйте это, открыв и изучив сам модуль List). А [1] - это как мы знаем по питону, простое "выдергивание" первого индекса из элемента. Также по питону знаем, что индексация начинается с нуля, то бишь элемент номер 1 - это на самом деле второй элемент, так как первым является нулевой элемент. То есть вышенаписанный код находит, что текущая строка это -(_("Save tuner settings"), "save")
Здесь индекс 0 - _("Save tuner settings"), а индекс 1 - "save".
Так как мы запросили индекс 1 (а не индекс 0), то есть [1], мы получаем строку "save"

Соответственно если курсор стоит на второй строчке, к нам вернется строка "restore".
Все логично и очень просто.


Спойлер   :
Вот для этого мы и придумывали индексы при добавлении строк к списку.
Но еще раз повторюсь, это импровизация, и это разумеется не единственный способ выяснить на какой строчке находится курсор. Если включите логику, можно симпровизировать и какой-нибудь другой, может еще более логичный способ сделать это. В любом случае в такой импровизации всегда гораздо больше логики, чем углубленных знаний питона на самом деле. Это еще один аргумент в пользу того, что в программировании логичность мышления программиста имеет первостепеннное значение.......

Вот полученный код этой функции пока:

def action(self, currentSelect = None):
if currentSelect is None:
currentSelect = self["menu"].getCurrent()[1]
         
Далее еще проще. Если полученное значение "save", то понятное дело это означает что пользователь потребовал сохранения настроек(нажал кнопку ОК на пункте "Сохранить настройки").
Соответственно написав if selectEntry is "save": за ним пишем тот самый код (из начала урока) по сохранению настроек.
Но прежде чем написать это, рассмотрим варианты.
К примеру ведь может оказаться что пользователь уже сохранял настройки (в заранее указанную папку).
Либо пользователь случайно нажал кнопку ОК в этой строчке, а на самом деле хотел нажать на другой строчке. Конечно можем на все эти обстоятельства плюнуть и всегда сохранять настройки в файл (если уже есть перезапишется). Но это неумно и не защищает пользователя от ошибочного нажатия кнопки ОК.
Поэтому напишем код таким образом (просто добавится еще одно вложение - а существует ли файл уже):
if currentSelect is "save":
   if fileExists(путь_к_файлу + 'имя_файла'):

   
В коде появилось что-то новое. Разберем по порядку.
Здесь воспользовались методом fileExists, который мы не будем сами разрабатывать, а как всегда "одолжим" у существующего модуля в имидже Directories (из папки Tools).
Если интересно узнать (должно быть интересно, если хотим расти), как работает этот метод, идем по пути /usr/lib/enigma2/python/Tools/ и открывая модуль
Directories - изучаем там содержимое метода. Этот метод просто проверяет наличие или отстутвие файла, который ему передан в качестве аргумента.
Конечно обязательно импортируем модуль в начале кода плагина:
from Tools.Directories fileExistsТеперь самое время нам разобраться с этим
путь_к_файлу + 'имя_файла'
Определимся куда будем сохранять файл настроек. Для этого сначала придумаем название нашему плагу. Пусть будет по смыслу так - TunerSettingsRestore.
И создадим внутри плагина папку backup и сохраним туда настройки.
Плагин наш будет находится в папке Extensions, сам файл пусть как первоначально придумали назовем mysettings, соответственно получаем:
if currentSelect is "save":
if fileExists('/usr/lib/enigma2/python/Plugins/Extensions/TunerSettingsRestore/backup/' + 'mysettings'):
   
Или весь код сначала с учетом импорта:

from Screens.Screen import Screen
from Components.Sources.List import List
from Components.ActionMap import ActionMap
from Components.Label import Label
from Tools.Directories fileExists


class NimSettings(Screen):
skin = """
<screen name="NimSettings" position="center,center" size="595,450" title="Backup settings for current skin">
  <widget name="text" position="69,339" size="500,30" foregroundColor="#00009a00" font="Regular;22" halign="right" transparent="1" />
  <ePixmap position="215,438" zPosition="1" size="165,2" pixmap="/usr/lib/enigma2/python/Plugins/Extensions/TunerSettingsRestore/images/red.png" alphatest="blend" />
  <widget name="red_key" position="215,408" zPosition="2" size="165,30" font="Regular; 20" halign="center" valign="center" backgroundColor="#41000000" foregroundColor="#00dddddd" transparent="1" />
  <widget source="menu" render="Listbox" position="15,10" size="570,100" scrollbarMode="showOnDemand" transparent="1">
    <convert type="TemplatedMultiContent">
      {"template": [
        MultiContentEntryText(pos = (15, 5), size = (570, 30), font=0, flags = RT_HALIGN_LEFT, text = 0)
        ],
        "fonts": [gFont("Regular", 23)],
        "itemHeight": 40
      }
    </convert>
  </widget>
</screen>"""

def __init__(self, session):
Screen.__init__(self, session)
self.setTitle(_("Plugin for restoring tuner settings"))
nashemenu = []
self["menu"] = List(nashemenu)
self["text"] = Label(_("Press OK for action"))
self["red_key"] = Label(_("Close"))
self["shortcuts"] = ActionMap(["ShortcutActions", "WizardActions"],
{
"cancel": self.cancel,
"back": self.cancel,
"red": self.cancel,
"ok": self.action,
})
self.createList()

def createList(self):
nashemenu = []
nashemenu.append((_("Save tuner settings"), "save"))
nashemenu.append((_("Restore tuner settings"), "restore"))
self["menu"].setList(nashemenu)

def cancel(self):
self.close()

def action(self, currentSelect = None):
if currentSelect is None:
currentSelect = self["menu"].getCurrent()[1]
if currentSelect is "save":
if fileExists('/usr/lib/enigma2/python/Plugins/Extensions/TunerSettingsRestore/backup/' + 'mysettings'):

А код функции action пока приняла этот вид:

def action(self, currentSelect = None):
if currentSelect is None:
currentSelect = self["menu"].getCurrent()[1]
if currentSelect is "save":
if fileExists('/usr/lib/enigma2/python/Plugins/Extensions/TunerSettingsRestore/backup/' + 'mysettings'):

Итак, что же делать, если файл уже существует?
Надо предоставить пользователю выбор, либо вернуться в меню плагина, либо, если он хочет, перезаписать файл.
Для этого вызовем окно выбора с помощью встроенного метода openWithCallback и существующего в имидже модуля MessageBox.
Для начала выполним необходимый импорт нужного нам модуля.
from Screens.MessageBox import MessageBoxПервым аргументом у метода openWithCallback идет название функции (назовем saveset), которая будет выполнена при положительном ответе (при отрицательном просто выход из окна назад). а вторым аргументом мы ему передадим импортированный  MessageBox, а далее уже аргументы соответственно самого MessageBox.
Открываем модуль MessageBox по пути /usr/lib/enigma2/python/Screens/ и из его метода __init__ узнаем какие атрибуты ему нужны. Для наглядности приведу эти аргументы:
(self, session, text, type = TYPE_YESNO, timeout = -1, close_on_any_key = False, default = True, enable_input = True, msgBoxID = None, picon = None, simple = False, list = [])
Как видим ему обязательно нужно передать только сам собственно text, а остальные аргументы имеют значения по умолчанию и если мы не собираемся их менять, то можно их вообще не указывать.
По порядку:

а) Как text передадим _("Backup file is already exists!\nDo you want rewrite backup file?"), думаю понятно (знак \n - просто перенос строки)
б) type = TYPE_YESNO, нас вполне устраивает, нам нужен именно тип TYPE_YESNO, значит пропускаем.
в) timeout = -1, а вот это непорядок (-1 означает нет), ставим таймаут 6 секунд timeout = 6,
г) close_on_any_key = False, устраивает, мы не собираемся закрыть окно любой кнопкой
д) default = True, вот здесь надо подумать, True здесь означает, что курсор будет на строчке - "да", мы
поставим на строчку "нет" на всякий пожарный, чтобы уберечь пользователя от ошибок, то есть default = False,
е) остальные атрибуты вообще не трогаем и оставляем по умолчанию.

И получаем такой вызов окна:

self.session.openWithCallback(self.saveset, MessageBox,_("Backup file is already exists!\nDo you want rewrite backup file?"), timeout = 6, default = False)
Обратите внимание, мы вообще не указали тип окна YESNO или другой, просто в данном случае нам нужен именно YESNO, а он применется по умолчанию, если нужен другой тип окна, тогда нужно указывать...
Дополнительную нужную функцию self.saveset разработаем после того, как закончим с функцией action.

То есть понятно, выведя окно сообщения, мы спросили у пользователя, что настройки бекапа уже существуют, нужно ли их перезаписать, и по умолчанию поставили курсор на ответе "нет", на всякий случай.....
При ответе "да" будет запущена функция self.saveset, которая перезапишет настройки (разработаем впоследствии), при ответе "нет" возврат в предыдущее окно.

Полученный код функции:

def action(self, currentSelect = None):
if currentSelect is None:
currentSelect = self["menu"].getCurrent()[1]
if currentSelect is "save":
if fileExists('/usr/lib/enigma2/python/Plugins/Extensions/TunerSettingsRestore/backup/' + 'mysettings'):
self.session.openWithCallback(self.saveset, MessageBox,_("Backup file is already exists!\nDo you want rewrite backup file?"), timeout = 6, default = False)

Далее код, если файл не существует. Здесь за условием else: (то бишь если файл не существует) запишем какраз таки от самый код сохранения настроек, который мы разрабатывали  самом начале, то есть так:

def action(self, currentSelect = None):
if currentSelect is None:
currentSelect = self["menu"].getCurrent()[1]
if currentSelect is "save":
if fileExists('/usr/lib/enigma2/python/Plugins/Extensions/TunerSettingsRestore/backup/' + 'mysettings'):
self.session.openWithCallback(self.saveset, MessageBox,_("Backup file is already exists!\nDo you want rewrite backup file?"), timeout = 6, default = False)
else:
a = open("/etc/enigma2/settings", "r")
b = a.read()
a.close()
c = b.split('\n')
d = []
for x in c:
if x.__contains__('Nims'):
d.append(x)
e = '\n'.join(d)
f = e + '\n'
g = open("/usr/lib/enigma2/python/Plugins/Extensions/TunerSettingsRestore/backup/mysettings","w")
g.write(f)
g.close()

Только естественно теперь указали путь сохранения настроек туда, куда нам надо, то есть /usr/lib/enigma2/python/Plugins/Extensions/TunerSettingsRestore/backup/
               
И далее, восстановление настроек, то есть если нажата ОК в строчке с сохранением настроек, то есть с индексом "restore", то есть:

elif currentSelect is "restore":
Здесь тоже нужно придумать часть (которую программисты называют "защитой от дураков"), например для случая, если собственно сохраненного файла настроек-то нет, а также, в случае если даже и есть такие настройки, еще раз спросить пользователя, дейчтвительно ли хочет....
Как вы понимаете, если файла настроек нет, то и нечего восстанавливать.
Поэтому проверим наличие файла и при отсутствии оного, просто покажем сообщение, что этого файла нет и вернемся в предыдущее окно.
Воспользуемся другим встроенным методом текущей сессии open и также тем же модулем MessageBox.
Метод open текущей сессии требует только аргумент с названием окна (MessageBox) и далее также управление передается собственно модулю MessageBox.
И так как на этот раз нам нужен другой тип окна TYPE_INFO(а не который по умолчанию), на этот раз явно укажем этот тип. И получим такой код вызова окна сообщения:

elif currentSelect is "restore":
if not fileExists('/usr/lib/enigma2/python/Plugins/Extensions/TunerSettingsRestore/backup/' + 'mysettings'):
self.session.open(MessageBox, _("Backup file not exists!"), MessageBox.TYPE_INFO, timeout = 6)

Спойлер   :
Этот код звучит так: "Если нажата кнопка ОК в строчке восстановления, и если файла бекапа не существует, то вывести сообщение что этого файла нет и все"

Далее если тот файл есть выводим сообщение, что сейчас будет имидж остановлен (тем самым скриптом), и перезапущен с новыми настройками, но пользователь может отменить и передумать.
То есть это будет опять метод openWithCallback, функцию, которую он запустить при положительном ответе, назовем self.restoreset, остальное вы уже по типу пройденного поймете:

elif fileExists('/usr/lib/enigma2/python/Plugins/Extensions/TunerSettingsRestore/backup/' + 'mysettings'):
self.session.openWithCallback(self.restoreset, MessageBox, _("Do not be afraid, now image will be stopped and restarted for the restore tuner settings.\nRestore settings?"), timeout = 6)

Функция self.restoreset будет находиться за пределами функции self.action, поэтому разработаем ее после.

Итого, теперь весь полученный нами код нашего плагина на этот момент:

from Screens.Screen import Screen
from Components.Sources.List import List
from Components.ActionMap import ActionMap
from Components.Label import Label
from Tools.Directories import fileExists
from Screens.MessageBox import MessageBox


class NimSettings(Screen):
skin = """
<screen name="NimSettings" position="center,center" size="595,450" title="Backup settings for current skin">
  <widget name="text" position="69,339" size="500,30" foregroundColor="#00009a00" font="Regular;22" halign="right" transparent="1" />
  <ePixmap position="215,438" zPosition="1" size="165,2" pixmap="/usr/lib/enigma2/python/Plugins/Extensions/TunerSettingsRestore/images/red.png" alphatest="blend" />
  <widget name="red_key" position="215,408" zPosition="2" size="165,30" font="Regular; 20" halign="center" valign="center" backgroundColor="#41000000" foregroundColor="#00dddddd" transparent="1" />
  <widget source="menu" render="Listbox" position="15,10" size="570,100" scrollbarMode="showOnDemand" transparent="1">
    <convert type="TemplatedMultiContent">
      {"template": [
        MultiContentEntryText(pos = (15, 5), size = (570, 30), font=0, flags = RT_HALIGN_LEFT, text = 0)
        ],
        "fonts": [gFont("Regular", 23)],
        "itemHeight": 40
      }
    </convert>
  </widget>
</screen>"""

def __init__(self, session):
Screen.__init__(self, session)
self.setTitle(_("Plugin for restoring tuner settings"))
nashemenu = []
self["menu"] = List(nashemenu)
self["text"] = Label(_("Press OK for action"))
self["red_key"] = Label(_("Close"))
self["shortcuts"] = ActionMap(["ShortcutActions", "WizardActions"],
{
"cancel": self.cancel,
"back": self.cancel,
"red": self.cancel,
"ok": self.action,
})
self.createList()

def createList(self):
nashemenu = []
nashemenu.append((_("Save tuner settings"), "save"))
nashemenu.append((_("Restore tuner settings"), "restore"))
self["menu"].setList(nashemenu)

def cancel(self):
self.close()

def action(self, currentSelect = None):
if currentSelect is None:
currentSelect = self["menu"].getCurrent()[1]
if currentSelect is "save":
if fileExists('/usr/lib/enigma2/python/Plugins/Extensions/TunerSettingsRestore/backup/' + 'mysettings'):
self.session.openWithCallback(self.saveset, MessageBox,_("Backup file is already exists!\nDo you want rewrite backup file?"), timeout = 6, default = False)
else:
a = open("/etc/enigma2/settings", "r")
b = a.read()
a.close()
c = b.split('\n')
d = []
for x in c:
if x.__contains__('Nims'):
d.append(x)
e = '\n'.join(d)
f = e + '\n'
g = open("/usr/lib/enigma2/python/Plugins/Extensions/TunerSettingsRestore/backup/mysettings","w")
g.write(f)
g.close()
elif currentSelect is "restore":
if not fileExists('/usr/lib/enigma2/python/Plugins/Extensions/TunerSettingsRestore/backup/' + 'mysettings'):
self.session.open(MessageBox, _("Backup file not exists!"), MessageBox.TYPE_INFO, timeout = 6)
elif fileExists('/usr/lib/enigma2/python/Plugins/Extensions/TunerSettingsRestore/backup/' + 'mysettings'):
self.session.openWithCallback(self.restoreset, MessageBox, _("Do not be afraid, now image will be stopped and restarted for the restore tuner settings.\nRestore settings?"), timeout = 6)

               
Остается в классе разработать дополнительно появившиеся функции self.saveset и self.restoreset.

Продолжение следует....

 
« Последнее редактирование: 09 Декабрь 2013, 17:28:47 от ака Учкун »
  • gi 9995 vu+ ultimo
Собака лает, караван идет....

Эти пользователи поблагодарили Вас за сообщение:

Оффлайн ака Учкун

  • Спец
  • *
  • СПАСИБО:
  • - Вы поблагодарили: 438
  • - Вас поблагодарили: 3688
  • Сообщений: 895
  • Пол: Мужской
  • Зарегистрирован: 2012-07-15
    Местоположение: город Навои
    Возраст: 53
    • Просмотр профиля

Пишем плагин сами или случайные уроки по python
« Ответ #8 : 08 Декабрь 2013, 18:02:26 »
Прежде чем разработаем последние две функции класса, сначала в предыдущем коде внесем маленькое дополнение.
В функции action, в ветке сохранения настроек(когда ранее сохраненного файла не оказалось), мы просто сохранили настройки. А нужно бы по логике вещей выдать сообщение, чтобы пользователь понял, что настройки успешно сохранились. Поэтому в той части кода, сразу за cохранением настроек исходя из логики добавим вывод сообщения, что настройки успешно сохранены, то есть вот так:
self.session.open(MessageBox, _("Settings successfully saved!"), MessageBox.TYPE_INFO, timeout = 6)И весь код приобретает вид:

from Screens.Screen import Screen
from Components.Sources.List import List
from Components.ActionMap import ActionMap
from Components.Label import Label
from Tools.Directories import fileExists
from Screens.MessageBox import MessageBox


class NimSettings(Screen):
skin = """
<screen name="NimSettings" position="center,center" size="595,450" title="Backup settings for current skin">
  <widget name="text" position="69,339" size="500,30" foregroundColor="#00009a00" font="Regular;22" halign="right" transparent="1" />
  <ePixmap position="215,438" zPosition="1" size="165,2" pixmap="/usr/lib/enigma2/python/Plugins/Extensions/TunerSettingsRestore/images/red.png" alphatest="blend" />
  <widget name="red_key" position="215,408" zPosition="2" size="165,30" font="Regular; 20" halign="center" valign="center" backgroundColor="#41000000" foregroundColor="#00dddddd" transparent="1" />
  <widget source="menu" render="Listbox" position="15,10" size="570,100" scrollbarMode="showOnDemand" transparent="1">
    <convert type="TemplatedMultiContent">
      {"template": [
        MultiContentEntryText(pos = (15, 5), size = (570, 30), font=0, flags = RT_HALIGN_LEFT, text = 0)
        ],
        "fonts": [gFont("Regular", 23)],
        "itemHeight": 40
      }
    </convert>
  </widget>
</screen>"""

def __init__(self, session):
Screen.__init__(self, session)
self.setTitle(_("Plugin for restoring tuner settings"))
nashemenu = []
self["menu"] = List(nashemenu)
self["text"] = Label(_("Press OK for action"))
self["red_key"] = Label(_("Close"))
self["shortcuts"] = ActionMap(["ShortcutActions", "WizardActions"],
{
"cancel": self.cancel,
"back": self.cancel,
"red": self.cancel,
"ok": self.action,
})
self.createList()

def createList(self):
nashemenu = []
nashemenu.append((_("Save tuner settings"), "save"))
nashemenu.append((_("Restore tuner settings"), "restore"))
self["menu"].setList(nashemenu)

def cancel(self):
self.close()

def action(self, currentSelect = None):
if currentSelect is None:
currentSelect = self["menu"].getCurrent()[1]
if currentSelect is "save":
if fileExists('/usr/lib/enigma2/python/Plugins/Extensions/TunerSettingsRestore/backup/' + 'mysettings'):
self.session.openWithCallback(self.saveset, MessageBox,_("Backup file is already exists!\nDo you want rewrite backup file?"), timeout = 6, default = False)
else:
a = open("/etc/enigma2/settings", "r")
b = a.read()
a.close()
c = b.split('\n')
d = []
for x in c:
if x.__contains__('Nims'):
d.append(x)
e = '\n'.join(d)
f = e + '\n'
g = open("/usr/lib/enigma2/python/Plugins/Extensions/TunerSettingsRestore/backup//mysettings","w")
g.write(f)
g.close()
self.session.open(MessageBox, _("Settings successfully saved!"), MessageBox.TYPE_INFO, timeout = 6)
elif currentSelect is "restore":
if not fileExists('/usr/lib/enigma2/python/Plugins/Extensions/TunerSettingsRestore/backup/' + 'mysettings'):
self.session.open(MessageBox, _("Backup file not exists!"), MessageBox.TYPE_INFO, timeout = 6)
elif fileExists('/usr/lib/enigma2/python/Plugins/Extensions/TunerSettingsRestore/backup/' + 'mysettings'):
self.session.openWithCallback(self.restoreset, MessageBox, _("Do not be afraid, now image will be stopped and restarted for the restore tuner settings.\nRestore settings?"), timeout = 6)




               
Последние две функции нашего класса.
self.saveset это просто сохранение настроек (после подтверждения о перезаписи существующего файла):

def saveset(self, answer):
if answer is True:
a = open("/etc/enigma2/settings", "r")
b = a.read()
a.close()
c = b.split('\n')
d = []
for x in c:
if x.__contains__('Nims'):
d.append(x)
e = '\n'.join(d)
f = e + '\n'
g = open("/usr/lib/enigma2/python/Plugins/Extensions/TunerSettingsRestore/backup//mysettings","w")
g.write(f)
g.close()
self.session.open(MessageBox, _("Settings successfully saved!"), MessageBox.TYPE_INFO, timeout = 6)
         
Это тот самый код для сохранения, уже разбирали по буквочкам. Здесь у функции присутствует аргумент answer и соответственно код выполнится, если if answer is True:, то есть при получении положительного ответа....

И последняя функция нашего класса self.restoreset, которая будет задействована после того, как пользователь нажал ОК в пункте сохранения настроек и подтвердил затем сохранение.
Наконец-то именно здесь применим тот код для сохранения, который разрабатывали в самом начале, вот так:

def restoreset(self, answer):
if answer is True:
a = open("/usr/lib/enigma2/python/Plugins/Extensions/TunerSettingsRestore/backup/mysettings", "r")
b = a.read()
a.close()
i = open("/etc/enigma2/settings", "r")
k = i.read()
i.close()
m = k.split('\n')
v = []
for x in m:
if not x.__contains__('Nims'):
v.append(x)
z = '\n'.join(v)
new = z + b
s = open("/tmp/settings", "w")
s.write(new)
s.close()
         

Это тот самый код, что разрабатывали в самом начале урока, за исключением пути сохранения
файла настроек (если помните тогда мы сохраняли временно в папку темп).

Здесь остается только добавить запуск скрипта с восстановлением настроек.
Напомню текст скрипта:

#!/bin/sh
echo ""
echo ""
echo "Restoring settings"
echo ""
echo ""
echo "GUI will restart now!"
echo ""
echo ""
init 4
rm -rf /etc/enigma2/settings
cp /tmp/settings /etc/enigma2/settings
rm -rf /tmp/settings
init 3
exit 0

Сохраним этот скрипт в папку с плагином, создав для этого отдельную папку script, и назвав скажем файл скрипта 'restore_settings.sh'.

В таком разе код запуска скрипта будет выглядеть так:

from Screens.Console import Console
import os
script = "/usr/lib/enigma2/python/Plugins/Extensions/TunerSettingsRestore/script/restore_settings.sh"
os.chmod(script, 0755)
self.session.open(Console, cmdlist=[script])

Соответственно функция restoreset примет вид:

def restoreset(self, answer):
if answer is True:
a = open("/usr/lib/enigma2/python/Plugins/Extensions/TunerSettingsRestore/backup/mysettings", "r")
b = a.read()
a.close()
i = open("/etc/enigma2/settings", "r")
k = i.read()
i.close()
m = k.split('\n')
v = []
for x in m:
if not x.__contains__('Nims'):
v.append(x)
z = '\n'.join(v)
new = z + b
s = open("/tmp/settings", "w")
s.write(new)
s.close()
from Screens.Console import Console
import os
script = "/usr/lib/enigma2/python/Plugins/Extensions/TunerSettingsRestore/script/restore_settings.sh"
os.chmod(script, 0755)
self.session.open(Console, cmdlist=[script])
         
         
Код класса в плагине(то есть меню плагина, со всеми действиями с этим меню) полностью готов.
А ведь мы создали целый модуль собственный! И причем абсолютно рабочий.....
Вот он:

from Screens.Screen import Screen
from Components.Sources.List import List
from Components.ActionMap import ActionMap
from Components.Label import Label
from Tools.Directories import fileExists
from Screens.MessageBox import MessageBox


class NimSettings(Screen):
skin = """
<screen name="NimSettings" position="center,center" size="595,450" title="Backup settings for current skin">
  <widget name="text" position="69,339" size="500,30" foregroundColor="#00009a00" font="Regular;22" halign="right" transparent="1" />
  <ePixmap position="215,438" zPosition="1" size="165,2" pixmap="/usr/lib/enigma2/python/Plugins/Extensions/TunerSettingsRestore/images/red.png" alphatest="blend" />
  <widget name="red_key" position="215,408" zPosition="2" size="165,30" font="Regular; 20" halign="center" valign="center" backgroundColor="#41000000" foregroundColor="#00dddddd" transparent="1" />
  <widget source="menu" render="Listbox" position="15,10" size="570,100" scrollbarMode="showOnDemand" transparent="1">
    <convert type="TemplatedMultiContent">
      {"template": [
        MultiContentEntryText(pos = (15, 5), size = (570, 30), font=0, flags = RT_HALIGN_LEFT, text = 0)
        ],
        "fonts": [gFont("Regular", 23)],
        "itemHeight": 40
      }
    </convert>
  </widget>
</screen>"""

def __init__(self, session):
Screen.__init__(self, session)
self.setTitle(_("Plugin for restoring tuner settings"))
nashemenu = []
self["menu"] = List(nashemenu)
self["text"] = Label(_("Press OK for action"))
self["red_key"] = Label(_("Close"))
self["shortcuts"] = ActionMap(["ShortcutActions", "WizardActions"],
{
"cancel": self.cancel,
"back": self.cancel,
"red": self.cancel,
"ok": self.action,
})
self.createList()

def createList(self):
nashemenu = []
nashemenu.append((_("Save tuner settings"), "save"))
nashemenu.append((_("Restore tuner settings"), "restore"))
self["menu"].setList(nashemenu)

def cancel(self):
self.close()

def action(self, currentSelect = None):
if currentSelect is None:
currentSelect = self["menu"].getCurrent()[1]
if currentSelect is "save":
if fileExists('/usr/lib/enigma2/python/Plugins/Extensions/TunerSettingsRestore/backup/' + 'mysettings'):
self.session.openWithCallback(self.saveset, MessageBox,_("Backup file is already exists!\nDo you want rewrite backup file?"), timeout = 6, default = False)
else:
a = open("/etc/enigma2/settings", "r")
b = a.read()
a.close()
c = b.split('\n')
d = []
for x in c:
if x.__contains__('Nims'):
d.append(x)
e = '\n'.join(d)
f = e + '\n'
g = open("/usr/lib/enigma2/python/Plugins/Extensions/TunerSettingsRestore/backup/mysettings","w")
g.write(f)
g.close()
self.session.open(MessageBox, _("Settings successfully saved!"), MessageBox.TYPE_INFO, timeout = 6)
elif currentSelect is "restore":
if not fileExists('/usr/lib/enigma2/python/Plugins/Extensions/TunerSettingsRestore/backup/' + 'mysettings'):
self.session.open(MessageBox, _("Backup file not exists!"), MessageBox.TYPE_INFO, timeout = 6)
elif fileExists('/usr/lib/enigma2/python/Plugins/Extensions/TunerSettingsRestore/backup/' + 'mysettings'):
self.session.openWithCallback(self.restoreset, MessageBox, _("Do not be afraid, now image will be stopped and restarted for the restore tuner settings.\nRestore settings?"), timeout = 6)

def saveset(self, answer):
if answer is True:
a = open("/etc/enigma2/settings", "r")
b = a.read()
a.close()
c = b.split('\n')
d = []
for x in c:
if x.__contains__('Nims'):
d.append(x)
e = '\n'.join(d)
f = e + '\n'
g = open("/usr/lib/enigma2/python/Plugins/Extensions/TunerSettingsRestore/backup/mysettings","w")
g.write(f)
g.close()
self.session.open(MessageBox, _("Settings successfully saved!"), MessageBox.TYPE_INFO, timeout = 6)

def restoreset(self, answer):
if answer is True:
a = open("/usr/lib/enigma2/python/Plugins/Extensions/TunerSettingsRestore/backup/mysettings", "r")
b = a.read()
a.close()
i = open("/etc/enigma2/settings", "r")
k = i.read()
i.close()
m = k.split('\n')
v = []
for x in m:
if not x.__contains__('Nims'):
v.append(x)
z = '\n'.join(v)
new = z + b
s = open("/tmp/settings", "w")
s.write(new)
s.close()
from Screens.Console import Console
import os
script = "/usr/lib/enigma2/python/Plugins/Extensions/TunerSettingsRestore/script/restore_settings.sh"
os.chmod(script, 0755)
self.session.open(Console, cmdlist=[script])

         
И осталось дело за совсем малым, написать код вызова плагина и если нужно добавить локализацию
для менюшек и сообщений нашего плага.

Вызов плагина. Тут очень просто.
Тоже ничего придумывать питоновского вобщем-то не надо.
Об этом тоже позаботились создатели имиджей.

В самом конце нашего кода, после тела класса NimSettings создаем функцию Plugins, который в качестве аргументов будет ожидать аргументы словарного типа (то бишь **kwargs), эта функция будет возвращать модуль PluginDescriptor, аргументы для которой мы придумаем.

def Plugins(path, **kwargs):
return PluginDescriptor(**kwargs)

Сам модуль PluginDescriptor импортируем из файла Plugin.py из папки Plugins

from Plugins.Plugin import PluginDescriptor
Открываем этот самый Plugin.py и изучаем какие же аргументы нужно передать этому самому модулю PluginDescriptor, для этого достаточно просмотреть аргументы его инструкции __init__
Вот эти аргументы:

def __init__(self, name = "Plugin", where = [ ], description = "", icon = None, fnc = None, wakeupfnc = None, needsRestart = None, internal = False, weight = 0):
Рассмотрим по одной.
а) name = "Plugin"  #название плагина, у нас будет name = "Restore Tuner settings"
б) where = [ ]  # в каком меню показать плагин, нам достаточно показать в списке плагинов, запишем where = [PluginDescriptor.WHERE_PLUGINMENU]
в) description = ""   #  описание плагина, запишем description = "Plugin for save Tuner settings"
г) icon = None  # пропустим, так как у нас нет собственной иконки для плага
д) fnc = None  # собственно что нужно задействовать при выборе плагина, запишем функцию, которую назовем произвольно, например fnc = main
е) остальные атрибуты оставляем по умолчанию....

Впишем эти аргументы нами придуманные в функцию вызова плагина, добавив при необходимости скобки с нижним подчеркиванием для переводимости
при необходимости:

def Plugins(path, **kwargs):
return PluginDescriptor(name = _("Restore Tuner settings"), where = [PluginDescriptor.WHERE_PLUGINMENU], description = _("Plugin for save Tuner settings"), fnc = main)
   
   
И до этой функции предпоследним напишем функцию main, которая просто при выборе строчки с плагином (в списке плагинов)
и запустит наш класс NimSettings:

def main(session, **kwargs):
session.open(NimSettings)
   
   
Все. Наш плагин готов в принципе к использованию.
Осталось только два нюанса.
Первый.
Если мы хотим, чтобы плагин был русскоязычным, нужно заложить в плагин локализуемость и добавить файлы локализации.
Сильно углубляться тут в код не буду. В этом случае-то всегда можете использовать готовый шаблон, да и код достаточно прост.

Для создания переводимости меню и сообщений плагина (кроме тех скобок и нижнего подчеркивания, что мы уже добавляли в плагин)
нужно для начала импортировать

from Components.Language import language
from Tools.Directories import resolveFilename, SCOPE_PLUGINS, SCOPE_LANGUAGE
from os import environ, system
import gettext

Затем в самом начале кода плагина тоже (сразу за импортами) прописать вот такой простой код

lang = language.getLanguage()
environ["LANGUAGE"] = lang[:2]
gettext.bindtextdomain("enigma2", resolveFilename(SCOPE_LANGUAGE))
gettext.textdomain("enigma2")
gettext.bindtextdomain("NimSettings", "%s%s" % (resolveFilename(SCOPE_PLUGINS), "Extensions/TunerSettingsRestore/locale/"))


def _(txt):
t = gettext.dgettext("NimSettings", txt)
if t == txt:
t = gettext.gettext(txt)
return t


Если хотите разобрать этот код по буквочкам, изучаем gettext.py, Language.py и os.py (в имидже).
А так понятно "NimSettings" - это так мы назовем файл локализации для плагина, который будет находится,
как и указано в этом коде    Extensions/TunerSettingsRestore/locale/   

А сам файл локализации будем создавать лучше и быстрей всего из готового шаблона.
Создайте себе шаблон например взяв айл локали вашего другого плагина, и просто изменив название
создавать новый файл локали.
К файлам локали (po и mo) тоже есть свои требования, объяснять их не задача нашей темы.   


Вот теперь код, который получился у нас окончательно. Наш plugin.py

from Screens.Screen import Screen
from Components.Sources.List import List
from Components.ActionMap import ActionMap
from Components.Label import Label
from Tools.Directories import fileExists, resolveFilename, SCOPE_PLUGINS, SCOPE_LANGUAGE
from Screens.MessageBox import MessageBox
from Components.Language import language
from Plugins.Plugin import PluginDescriptor
from os import environ, system
import gettext


lang = language.getLanguage()
environ["LANGUAGE"] = lang[:2]
gettext.bindtextdomain("enigma2", resolveFilename(SCOPE_LANGUAGE))
gettext.textdomain("enigma2")
gettext.bindtextdomain("NimSettings", "%s%s" % (resolveFilename(SCOPE_PLUGINS), "Extensions/TunerSettingsRestore/locale/"))


def _(txt):
t = gettext.dgettext("NimSettings", txt)
if t == txt:
t = gettext.gettext(txt)
return t


class NimSettings(Screen):
skin = """
<screen name="NimSettings" position="center,center" size="595,450" title="Backup settings for current skin">
  <widget name="text" position="69,339" size="500,30" foregroundColor="#00009a00" font="Regular;22" halign="right" transparent="1" />
  <ePixmap position="215,438" zPosition="1" size="165,2" pixmap="/usr/lib/enigma2/python/Plugins/Extensions/TunerSettingsRestore/images/red.png" alphatest="blend" />
  <widget name="red_key" position="215,408" zPosition="2" size="165,30" font="Regular; 20" halign="center" valign="center" backgroundColor="#41000000" foregroundColor="#00dddddd" transparent="1" />
  <widget source="menu" render="Listbox" position="15,10" size="570,100" scrollbarMode="showOnDemand" transparent="1">
    <convert type="TemplatedMultiContent">
      {"template": [
        MultiContentEntryText(pos = (15, 5), size = (570, 30), font=0, flags = RT_HALIGN_LEFT, text = 0)
        ],
        "fonts": [gFont("Regular", 23)],
        "itemHeight": 40
      }
    </convert>
  </widget>
</screen>"""

def __init__(self, session):
Screen.__init__(self, session)
self.setTitle(_("Plugin for restoring tuner settings"))
nashemenu = []
self["menu"] = List(nashemenu)
self["text"] = Label(_("Press OK for action"))
self["red_key"] = Label(_("Close"))
self["shortcuts"] = ActionMap(["ShortcutActions", "WizardActions"],
{
"cancel": self.cancel,
"back": self.cancel,
"red": self.cancel,
"ok": self.action,
})
self.createList()

def createList(self):
nashemenu = []
nashemenu.append((_("Save tuner settings"), "save"))
nashemenu.append((_("Restore tuner settings"), "restore"))
self["menu"].setList(nashemenu)

def cancel(self):
self.close()

def action(self, currentSelect = None):
if currentSelect is None:
currentSelect = self["menu"].getCurrent()[1]
if currentSelect is "save":
if fileExists('/usr/lib/enigma2/python/Plugins/Extensions/TunerSettingsRestore/backup/' + 'mysettings'):
self.session.openWithCallback(self.saveset, MessageBox,_("Backup file is already exists!\nDo you want rewrite backup file?"), timeout = 6, default = False)
else:
a = open("/etc/enigma2/settings", "r")
b = a.read()
a.close()
c = b.split('\n')
d = []
for x in c:
if x.__contains__('Nims'):
d.append(x)
e = '\n'.join(d)
f = e + '\n'
g = open("/usr/lib/enigma2/python/Plugins/Extensions/TunerSettingsRestore/backup/mysettings","w")
g.write(f)
g.close()
self.session.open(MessageBox, _("Settings successfully saved!"), MessageBox.TYPE_INFO, timeout = 6)
elif currentSelect is "restore":
if not fileExists('/usr/lib/enigma2/python/Plugins/Extensions/TunerSettingsRestore/backup/' + 'mysettings'):
self.session.open(MessageBox, _("Backup file not exists!"), MessageBox.TYPE_INFO, timeout = 6)
elif fileExists('/usr/lib/enigma2/python/Plugins/Extensions/TunerSettingsRestore/backup/' + 'mysettings'):
self.session.openWithCallback(self.restoreset, MessageBox, _("Do not be afraid, now image will be stopped and restarted for the restore tuner settings.\nRestore settings?"), timeout = 6)

def saveset(self, answer):
if answer is True:
a = open("/etc/enigma2/settings", "r")
b = a.read()
a.close()
c = b.split('\n')
d = []
for x in c:
if x.__contains__('Nims'):
d.append(x)
e = '\n'.join(d)
f = e + '\n'
g = open("/usr/lib/enigma2/python/Plugins/Extensions/TunerSettingsRestore/backup/mysettings","w")
g.write(f)
g.close()
self.session.open(MessageBox, _("Settings successfully saved!"), MessageBox.TYPE_INFO, timeout = 6)

def restoreset(self, answer):
if answer is True:
a = open("/usr/lib/enigma2/python/Plugins/Extensions/TunerSettingsRestore/backup/mysettings", "r")
b = a.read()
a.close()
i = open("/etc/enigma2/settings", "r")
k = i.read()
i.close()
m = k.split('\n')
v = []
for x in m:
if not x.__contains__('Nims'):
v.append(x)
z = '\n'.join(v)
new = z + b
s = open("/tmp/settings", "w")
s.write(new)
s.close()
from Screens.Console import Console
import os
script = "/usr/lib/enigma2/python/Plugins/Extensions/TunerSettingsRestore/script/restore_settings.sh"
os.chmod(script, 0755)
self.session.open(Console, cmdlist=[script])

def main(session, **kwargs):
session.open(NimSettings)

def Plugins(path, **kwargs):
return PluginDescriptor(name = _("Restore Tuner settings"), where = [PluginDescriptor.WHERE_PLUGINMENU], description = _("Plugin for save Tuner settings"), fnc = main)

   
Спойлер   :
Кстати как закончите код, в окне Geany в верхней панельке сразу нажмите "Скомпилировать",
это еще один способ выявить ошибки в коде. А ошибки неизбежны, в основном конечно из-за
невнимательности. Я вот например уже нашел таковые ошибки в предыдущих постах и уже исправил там....

Файл локали тоже скажем создали.
Остался последний нюанс.
Файл __init__.py в папке плагина.
Смысл этого файла:
а) присутствие этого файла нужно, если из этой директории (то есть из папки плагина) потребуется импорт
какого-то модуля. Например, если ваш плагин будет состоять из нескольких файлов-модулей (пакетов).
б) если заведомо нужно объявлять атрибуты для этой директории. В нашем случае не нужно.

Потому оставляем просто пустой (все равно униксовый должен быть, хоть и пустой) файл __init__.py


Вот теперь все.
Наш плагин полностью готов.
Наверно вместе со мной создавали параллельно файлы плагина?

Вот такая папка с файлами плагина должна была получиться, которую в архиве приложил.
Забрасываем эту папку в имидж по пути

/usr/lib/enigma2/python/Plugins/Extensions/

Перегружаемся.
И заходя в меню списка плагинов, видим наш плагин














Поздравляю
Вы вместе со мной написали свой первый рабочий плагин!
         
А если серъезно, достиг ли я цели, которую поставил перед написанием плагина публично?
Целью была показать новичкам изучающим питон, как нудную зубрежку питона можно и нужно применить в плагиностроении.
Если бы например когда я только начал изучать питон, набрел бы на такой ФАК, как бы я сэкономил свое время....
А может кого-то и подстегну к плагиностроению и в нашем полку плагинописателей прибудет возможно?

Надеюсь кому-то помог.....

« Последнее редактирование: 09 Декабрь 2013, 17:31:10 от ака Учкун »
  • gi 9995 vu+ ultimo
Собака лает, караван идет....

Эти пользователи поблагодарили Вас за сообщение: