+ The installation script will also install a feed source that enables a convenient upgrade to the latest version with the following commands or automatically as part of a DreamOS upgrade:
+
+
apt-get update
+
apt-get upgrade
+
+
+
diff --git a/docs/tvmagazinecockpit.sh b/docs/tvmagazinecockpit.sh
new file mode 100755
index 0000000..b512d54
--- /dev/null
+++ b/docs/tvmagazinecockpit.sh
@@ -0,0 +1,8 @@
+#!/bin/sh
+rm -f /etc/apt/sources.list.d/cockpit.list
+apt-get update
+apt-get install -y apt-transport-https
+echo deb [trusted=yes] https://apt.fury.io/dream-alpha ./ > /etc/apt/sources.list.d/cockpit.list
+apt-get update
+apt-get install -y enigma2-plugin-extensions-tvmagazinecockpit
+systemctl restart enigma2
diff --git a/logos/123TV.png b/logos/123TV.png
new file mode 100755
index 0000000..ef4670a
Binary files /dev/null and b/logos/123TV.png differ
diff --git a/logos/13TH.png b/logos/13TH.png
new file mode 100755
index 0000000..fd21201
Binary files /dev/null and b/logos/13TH.png differ
diff --git a/logos/2NEO.png b/logos/2NEO.png
new file mode 100755
index 0000000..804122a
Binary files /dev/null and b/logos/2NEO.png differ
diff --git a/logos/3PLUS.png b/logos/3PLUS.png
new file mode 100755
index 0000000..1f93dcb
Binary files /dev/null and b/logos/3PLUS.png differ
diff --git a/logos/3SAT.png b/logos/3SAT.png
new file mode 100755
index 0000000..d0141c5
Binary files /dev/null and b/logos/3SAT.png differ
diff --git a/logos/ADULT.png b/logos/ADULT.png
new file mode 100755
index 0000000..5b1366b
Binary files /dev/null and b/logos/ADULT.png differ
diff --git a/logos/AETV.png b/logos/AETV.png
new file mode 100755
index 0000000..e7bf93f
Binary files /dev/null and b/logos/AETV.png differ
diff --git a/logos/ALJAZ.png b/logos/ALJAZ.png
new file mode 100755
index 0000000..3233945
Binary files /dev/null and b/logos/ALJAZ.png differ
diff --git a/logos/ALPHA.png b/logos/ALPHA.png
new file mode 100755
index 0000000..2f722b5
Binary files /dev/null and b/logos/ALPHA.png differ
diff --git a/logos/AMS.png b/logos/AMS.png
new file mode 100755
index 0000000..023ff71
Binary files /dev/null and b/logos/AMS.png differ
diff --git a/logos/ANIXE.png b/logos/ANIXE.png
new file mode 100755
index 0000000..70c56d1
Binary files /dev/null and b/logos/ANIXE.png differ
diff --git a/logos/APLAN.png b/logos/APLAN.png
new file mode 100755
index 0000000..da460cb
Binary files /dev/null and b/logos/APLAN.png differ
diff --git a/logos/ARD.png b/logos/ARD.png
new file mode 100755
index 0000000..29549ed
Binary files /dev/null and b/logos/ARD.png differ
diff --git a/logos/ARTE.png b/logos/ARTE.png
new file mode 100755
index 0000000..9e93807
Binary files /dev/null and b/logos/ARTE.png differ
diff --git a/logos/ARTS.png b/logos/ARTS.png
new file mode 100755
index 0000000..316b9a6
Binary files /dev/null and b/logos/ARTS.png differ
diff --git a/logos/ATV-A.png b/logos/ATV-A.png
new file mode 100755
index 0000000..9301a40
Binary files /dev/null and b/logos/ATV-A.png differ
diff --git a/logos/ATV.png b/logos/ATV.png
new file mode 100755
index 0000000..c8f0d54
Binary files /dev/null and b/logos/ATV.png differ
diff --git a/logos/ATV2.png b/logos/ATV2.png
new file mode 100755
index 0000000..f8e4ead
Binary files /dev/null and b/logos/ATV2.png differ
diff --git a/logos/AXN.png b/logos/AXN.png
new file mode 100755
index 0000000..cea4ee2
Binary files /dev/null and b/logos/AXN.png differ
diff --git a/logos/BBC-E.png b/logos/BBC-E.png
new file mode 100755
index 0000000..d735773
Binary files /dev/null and b/logos/BBC-E.png differ
diff --git a/logos/BBC-N.png b/logos/BBC-N.png
new file mode 100755
index 0000000..03398a5
Binary files /dev/null and b/logos/BBC-N.png differ
diff --git a/logos/BBC.png b/logos/BBC.png
new file mode 100755
index 0000000..c43766e
Binary files /dev/null and b/logos/BBC.png differ
diff --git a/logos/BBC1.png b/logos/BBC1.png
new file mode 100755
index 0000000..8141bd8
Binary files /dev/null and b/logos/BBC1.png differ
diff --git a/logos/BBC2.png b/logos/BBC2.png
new file mode 100755
index 0000000..3533ead
Binary files /dev/null and b/logos/BBC2.png differ
diff --git a/logos/BBC4.png b/logos/BBC4.png
new file mode 100755
index 0000000..15ea3f5
Binary files /dev/null and b/logos/BBC4.png differ
diff --git a/logos/BE1.png b/logos/BE1.png
new file mode 100755
index 0000000..acefbd2
Binary files /dev/null and b/logos/BE1.png differ
diff --git a/logos/BERG.png b/logos/BERG.png
new file mode 100755
index 0000000..2650972
Binary files /dev/null and b/logos/BERG.png differ
diff --git a/logos/BIBEL.png b/logos/BIBEL.png
new file mode 100755
index 0000000..97b68ab
Binary files /dev/null and b/logos/BIBEL.png differ
diff --git a/logos/BILD.png b/logos/BILD.png
new file mode 100755
index 0000000..bcdd364
Binary files /dev/null and b/logos/BILD.png differ
diff --git a/logos/BLIZZ.png b/logos/BLIZZ.png
new file mode 100755
index 0000000..2f81a31
Binary files /dev/null and b/logos/BLIZZ.png differ
diff --git a/logos/BLM.png b/logos/BLM.png
new file mode 100755
index 0000000..740ba73
Binary files /dev/null and b/logos/BLM.png differ
diff --git a/logos/BLUM.png b/logos/BLUM.png
new file mode 100755
index 0000000..d053983
Binary files /dev/null and b/logos/BLUM.png differ
diff --git a/logos/BLUM2.png b/logos/BLUM2.png
new file mode 100755
index 0000000..236af41
Binary files /dev/null and b/logos/BLUM2.png differ
diff --git a/logos/BLUM3.png b/logos/BLUM3.png
new file mode 100755
index 0000000..39b9d2d
Binary files /dev/null and b/logos/BLUM3.png differ
diff --git a/logos/BOOM.png b/logos/BOOM.png
new file mode 100755
index 0000000..e31c4a5
Binary files /dev/null and b/logos/BOOM.png differ
diff --git a/logos/BR-N.png b/logos/BR-N.png
new file mode 100755
index 0000000..930f52a
Binary files /dev/null and b/logos/BR-N.png differ
diff --git a/logos/BR-S.png b/logos/BR-S.png
new file mode 100755
index 0000000..26b67f2
Binary files /dev/null and b/logos/BR-S.png differ
diff --git a/logos/BR.png b/logos/BR.png
new file mode 100755
index 0000000..9333601
Binary files /dev/null and b/logos/BR.png differ
diff --git a/logos/BULI.png b/logos/BULI.png
new file mode 100755
index 0000000..5aacf07
Binary files /dev/null and b/logos/BULI.png differ
diff --git a/logos/BUTV.png b/logos/BUTV.png
new file mode 100755
index 0000000..325893e
Binary files /dev/null and b/logos/BUTV.png differ
diff --git a/logos/C-NET.png b/logos/C-NET.png
new file mode 100755
index 0000000..c007094
Binary files /dev/null and b/logos/C-NET.png differ
diff --git a/logos/C5.png b/logos/C5.png
new file mode 100755
index 0000000..232cae9
Binary files /dev/null and b/logos/C5.png differ
diff --git a/logos/CC.png b/logos/CC.png
new file mode 100755
index 0000000..b085f6d
Binary files /dev/null and b/logos/CC.png differ
diff --git a/logos/CENTE.png b/logos/CENTE.png
new file mode 100755
index 0000000..1b19d13
Binary files /dev/null and b/logos/CENTE.png differ
diff --git a/logos/CH21.png b/logos/CH21.png
new file mode 100755
index 0000000..66e75f4
Binary files /dev/null and b/logos/CH21.png differ
diff --git a/logos/CIN.png b/logos/CIN.png
new file mode 100755
index 0000000..bd47175
Binary files /dev/null and b/logos/CIN.png differ
diff --git a/logos/CIN1.png b/logos/CIN1.png
new file mode 100755
index 0000000..e73990f
Binary files /dev/null and b/logos/CIN1.png differ
diff --git a/logos/CIN24.png b/logos/CIN24.png
new file mode 100755
index 0000000..696196f
Binary files /dev/null and b/logos/CIN24.png differ
diff --git a/logos/CLASS.png b/logos/CLASS.png
new file mode 100755
index 0000000..ec06c0e
Binary files /dev/null and b/logos/CLASS.png differ
diff --git a/logos/CNBC.png b/logos/CNBC.png
new file mode 100755
index 0000000..38bedc0
Binary files /dev/null and b/logos/CNBC.png differ
diff --git a/logos/CNN-M.png b/logos/CNN-M.png
new file mode 100755
index 0000000..073d387
Binary files /dev/null and b/logos/CNN-M.png differ
diff --git a/logos/CNN-T.png b/logos/CNN-T.png
new file mode 100755
index 0000000..bc9ddfe
Binary files /dev/null and b/logos/CNN-T.png differ
diff --git a/logos/CNN.png b/logos/CNN.png
new file mode 100755
index 0000000..b9088e0
Binary files /dev/null and b/logos/CNN.png differ
diff --git a/logos/CPLUS.png b/logos/CPLUS.png
new file mode 100755
index 0000000..d8b6960
Binary files /dev/null and b/logos/CPLUS.png differ
diff --git a/logos/CPLUSC.png b/logos/CPLUSC.png
new file mode 100755
index 0000000..c4c65ad
Binary files /dev/null and b/logos/CPLUSC.png differ
diff --git a/logos/CPLUSD.png b/logos/CPLUSD.png
new file mode 100755
index 0000000..497bfac
Binary files /dev/null and b/logos/CPLUSD.png differ
diff --git a/logos/CPLUSS.png b/logos/CPLUSS.png
new file mode 100755
index 0000000..38d2ac5
Binary files /dev/null and b/logos/CPLUSS.png differ
diff --git a/logos/CRIN.png b/logos/CRIN.png
new file mode 100755
index 0000000..89c3b12
Binary files /dev/null and b/logos/CRIN.png differ
diff --git a/logos/DATV.png b/logos/DATV.png
new file mode 100755
index 0000000..be5f186
Binary files /dev/null and b/logos/DATV.png differ
diff --git a/logos/DAZN.png b/logos/DAZN.png
new file mode 100755
index 0000000..c7d2878
Binary files /dev/null and b/logos/DAZN.png differ
diff --git a/logos/DCM.png b/logos/DCM.png
new file mode 100755
index 0000000..6fb03fe
Binary files /dev/null and b/logos/DCM.png differ
diff --git a/logos/DISNE.png b/logos/DISNE.png
new file mode 100755
index 0000000..a5ceb9e
Binary files /dev/null and b/logos/DISNE.png differ
diff --git a/logos/DJUN.png b/logos/DJUN.png
new file mode 100755
index 0000000..6c817a6
Binary files /dev/null and b/logos/DJUN.png differ
diff --git a/logos/DMAX.png b/logos/DMAX.png
new file mode 100755
index 0000000..6074946
Binary files /dev/null and b/logos/DMAX.png differ
diff --git a/logos/DMC.png b/logos/DMC.png
new file mode 100755
index 0000000..3c541fa
Binary files /dev/null and b/logos/DMC.png differ
diff --git a/logos/DMF.png b/logos/DMF.png
new file mode 100755
index 0000000..416158d
Binary files /dev/null and b/logos/DMF.png differ
diff --git a/logos/DR1.png b/logos/DR1.png
new file mode 100755
index 0000000..6e89089
Binary files /dev/null and b/logos/DR1.png differ
diff --git a/logos/DR2.png b/logos/DR2.png
new file mode 100755
index 0000000..ecf62f1
Binary files /dev/null and b/logos/DR2.png differ
diff --git a/logos/DRTV.png b/logos/DRTV.png
new file mode 100755
index 0000000..ed95fb0
Binary files /dev/null and b/logos/DRTV.png differ
diff --git a/logos/DWF.png b/logos/DWF.png
new file mode 100755
index 0000000..bd3ba4a
Binary files /dev/null and b/logos/DWF.png differ
diff --git a/logos/DWTV.png b/logos/DWTV.png
new file mode 100755
index 0000000..bfc39ce
Binary files /dev/null and b/logos/DWTV.png differ
diff --git a/logos/DXD.png b/logos/DXD.png
new file mode 100755
index 0000000..eb90a5e
Binary files /dev/null and b/logos/DXD.png differ
diff --git a/logos/E!.png b/logos/E!.png
new file mode 100755
index 0000000..e974527
Binary files /dev/null and b/logos/E!.png differ
diff --git a/logos/ENGB.png b/logos/ENGB.png
new file mode 100755
index 0000000..702e399
Binary files /dev/null and b/logos/ENGB.png differ
diff --git a/logos/EOTV.png b/logos/EOTV.png
new file mode 100755
index 0000000..d5b4049
Binary files /dev/null and b/logos/EOTV.png differ
diff --git a/logos/ES1.png b/logos/ES1.png
new file mode 100755
index 0000000..e3a5d7a
Binary files /dev/null and b/logos/ES1.png differ
diff --git a/logos/EURO-D.png b/logos/EURO-D.png
new file mode 100755
index 0000000..5179592
Binary files /dev/null and b/logos/EURO-D.png differ
diff --git a/logos/EURO-S.png b/logos/EURO-S.png
new file mode 100755
index 0000000..2468c88
Binary files /dev/null and b/logos/EURO-S.png differ
diff --git a/logos/EURO.png b/logos/EURO.png
new file mode 100755
index 0000000..46af26f
Binary files /dev/null and b/logos/EURO.png differ
diff --git a/logos/EURO2.png b/logos/EURO2.png
new file mode 100755
index 0000000..7ca1b8f
Binary files /dev/null and b/logos/EURO2.png differ
diff --git a/logos/EURON.png b/logos/EURON.png
new file mode 100755
index 0000000..40ed6df
Binary files /dev/null and b/logos/EURON.png differ
diff --git a/logos/EX-SP.png b/logos/EX-SP.png
new file mode 100755
index 0000000..e9a5018
Binary files /dev/null and b/logos/EX-SP.png differ
diff --git a/logos/FAMTV.png b/logos/FAMTV.png
new file mode 100755
index 0000000..e17aa9f
Binary files /dev/null and b/logos/FAMTV.png differ
diff --git a/logos/FATV.png b/logos/FATV.png
new file mode 100755
index 0000000..9347625
Binary files /dev/null and b/logos/FATV.png differ
diff --git a/logos/FES.png b/logos/FES.png
new file mode 100755
index 0000000..480d70d
Binary files /dev/null and b/logos/FES.png differ
diff --git a/logos/FFTV.png b/logos/FFTV.png
new file mode 100755
index 0000000..2b8362a
Binary files /dev/null and b/logos/FFTV.png differ
diff --git a/logos/FLN.png b/logos/FLN.png
new file mode 100755
index 0000000..9c79a8e
Binary files /dev/null and b/logos/FLN.png differ
diff --git a/logos/FOOD.png b/logos/FOOD.png
new file mode 100755
index 0000000..d292a1a
Binary files /dev/null and b/logos/FOOD.png differ
diff --git a/logos/FOX.png b/logos/FOX.png
new file mode 100755
index 0000000..5c5c091
Binary files /dev/null and b/logos/FOX.png differ
diff --git a/logos/FR24E.png b/logos/FR24E.png
new file mode 100755
index 0000000..58d94a5
Binary files /dev/null and b/logos/FR24E.png differ
diff --git a/logos/FR24F.png b/logos/FR24F.png
new file mode 100755
index 0000000..2d0f970
Binary files /dev/null and b/logos/FR24F.png differ
diff --git a/logos/FRA2.png b/logos/FRA2.png
new file mode 100755
index 0000000..06e2bf3
Binary files /dev/null and b/logos/FRA2.png differ
diff --git a/logos/FRA3.png b/logos/FRA3.png
new file mode 100755
index 0000000..b55c44f
Binary files /dev/null and b/logos/FRA3.png differ
diff --git a/logos/FRA4.png b/logos/FRA4.png
new file mode 100755
index 0000000..0b1a97b
Binary files /dev/null and b/logos/FRA4.png differ
diff --git a/logos/FRA5.png b/logos/FRA5.png
new file mode 100755
index 0000000..b305486
Binary files /dev/null and b/logos/FRA5.png differ
diff --git a/logos/FRAO.png b/logos/FRAO.png
new file mode 100755
index 0000000..f298aa8
Binary files /dev/null and b/logos/FRAO.png differ
diff --git a/logos/FREESHOP.png b/logos/FREESHOP.png
new file mode 100755
index 0000000..f865006
Binary files /dev/null and b/logos/FREESHOP.png differ
diff --git a/logos/GEO.png b/logos/GEO.png
new file mode 100755
index 0000000..05315ff
Binary files /dev/null and b/logos/GEO.png differ
diff --git a/logos/GOLD.png b/logos/GOLD.png
new file mode 100755
index 0000000..20bf154
Binary files /dev/null and b/logos/GOLD.png differ
diff --git a/logos/GUSTO.png b/logos/GUSTO.png
new file mode 100755
index 0000000..97572ab
Binary files /dev/null and b/logos/GUSTO.png differ
diff --git a/logos/HDDIS.png b/logos/HDDIS.png
new file mode 100755
index 0000000..384bcc1
Binary files /dev/null and b/logos/HDDIS.png differ
diff --git a/logos/HDSPO.png b/logos/HDSPO.png
new file mode 100755
index 0000000..b45f853
Binary files /dev/null and b/logos/HDSPO.png differ
diff --git a/logos/HEALTH.png b/logos/HEALTH.png
new file mode 100755
index 0000000..8148632
Binary files /dev/null and b/logos/HEALTH.png differ
diff --git a/logos/HEIMA.png b/logos/HEIMA.png
new file mode 100755
index 0000000..5642c74
Binary files /dev/null and b/logos/HEIMA.png differ
diff --git a/logos/HGTV.png b/logos/HGTV.png
new file mode 100755
index 0000000..e409e4d
Binary files /dev/null and b/logos/HGTV.png differ
diff --git a/logos/HH1.png b/logos/HH1.png
new file mode 100755
index 0000000..3c203e5
Binary files /dev/null and b/logos/HH1.png differ
diff --git a/logos/HISHD.png b/logos/HISHD.png
new file mode 100755
index 0000000..9c1ac24
Binary files /dev/null and b/logos/HISHD.png differ
diff --git a/logos/HR.png b/logos/HR.png
new file mode 100755
index 0000000..68eb371
Binary files /dev/null and b/logos/HR.png differ
diff --git a/logos/HSE.png b/logos/HSE.png
new file mode 100755
index 0000000..4fa7fcd
Binary files /dev/null and b/logos/HSE.png differ
diff --git a/logos/JUKE.png b/logos/JUKE.png
new file mode 100755
index 0000000..4f79e21
Binary files /dev/null and b/logos/JUKE.png differ
diff --git a/logos/JUNIO.png b/logos/JUNIO.png
new file mode 100755
index 0000000..7a2e17d
Binary files /dev/null and b/logos/JUNIO.png differ
diff --git a/logos/K1.png b/logos/K1.png
new file mode 100755
index 0000000..b4248da
Binary files /dev/null and b/logos/K1.png differ
diff --git a/logos/K1CLA.png b/logos/K1CLA.png
new file mode 100755
index 0000000..454e7c5
Binary files /dev/null and b/logos/K1CLA.png differ
diff --git a/logos/K1DOKU.png b/logos/K1DOKU.png
new file mode 100755
index 0000000..3488127
Binary files /dev/null and b/logos/K1DOKU.png differ
diff --git a/logos/KIKA.png b/logos/KIKA.png
new file mode 100755
index 0000000..e42e652
Binary files /dev/null and b/logos/KIKA.png differ
diff --git a/logos/KINOW.png b/logos/KINOW.png
new file mode 100755
index 0000000..d01cca9
Binary files /dev/null and b/logos/KINOW.png differ
diff --git a/logos/KTV.png b/logos/KTV.png
new file mode 100755
index 0000000..a6b43f2
Binary files /dev/null and b/logos/KTV.png differ
diff --git a/logos/LAUNE.png b/logos/LAUNE.png
new file mode 100755
index 0000000..a06b1a3
Binary files /dev/null and b/logos/LAUNE.png differ
diff --git a/logos/LEITV.png b/logos/LEITV.png
new file mode 100755
index 0000000..d702683
Binary files /dev/null and b/logos/LEITV.png differ
diff --git a/logos/LUSTP.png b/logos/LUSTP.png
new file mode 100755
index 0000000..569add6
Binary files /dev/null and b/logos/LUSTP.png differ
diff --git a/logos/MAPO.png b/logos/MAPO.png
new file mode 100755
index 0000000..2955211
Binary files /dev/null and b/logos/MAPO.png differ
diff --git a/logos/MASPO.png b/logos/MASPO.png
new file mode 100755
index 0000000..3f6e449
Binary files /dev/null and b/logos/MASPO.png differ
diff --git a/logos/MDR-SN.png b/logos/MDR-SN.png
new file mode 100755
index 0000000..ca09bec
Binary files /dev/null and b/logos/MDR-SN.png differ
diff --git a/logos/MDR-ST.png b/logos/MDR-ST.png
new file mode 100755
index 0000000..44b02cd
Binary files /dev/null and b/logos/MDR-ST.png differ
diff --git a/logos/MDR-TH.png b/logos/MDR-TH.png
new file mode 100755
index 0000000..8552603
Binary files /dev/null and b/logos/MDR-TH.png differ
diff --git a/logos/MDR.png b/logos/MDR.png
new file mode 100755
index 0000000..5e2bbb0
Binary files /dev/null and b/logos/MDR.png differ
diff --git a/logos/MELODIETV.png b/logos/MELODIETV.png
new file mode 100755
index 0000000..55e74dc
Binary files /dev/null and b/logos/MELODIETV.png differ
diff --git a/logos/MEZZO.png b/logos/MEZZO.png
new file mode 100755
index 0000000..1caf4a9
Binary files /dev/null and b/logos/MEZZO.png differ
diff --git a/logos/MFTV1.png b/logos/MFTV1.png
new file mode 100755
index 0000000..553568c
--- /dev/null
+++ b/logos/MFTV1.png
@@ -0,0 +1,2 @@
+
+AccessDeniedAccess DeniedMD9S2GW7F0CSKRHFMvMdp5u4+fIGFFZDW9IsW+cA82tZawH91tm7FAuzcK4gBP0kIpBaFFs3738CZu64wbK1f6c3r7o=
\ No newline at end of file
diff --git a/logos/MOTOR.png b/logos/MOTOR.png
new file mode 100755
index 0000000..bd88732
Binary files /dev/null and b/logos/MOTOR.png differ
diff --git a/logos/MOVTV.png b/logos/MOVTV.png
new file mode 100755
index 0000000..f00e913
Binary files /dev/null and b/logos/MOVTV.png differ
diff --git a/logos/MTV-B.png b/logos/MTV-B.png
new file mode 100755
index 0000000..848e585
Binary files /dev/null and b/logos/MTV-B.png differ
diff --git a/logos/MTV-D.png b/logos/MTV-D.png
new file mode 100755
index 0000000..e68b243
Binary files /dev/null and b/logos/MTV-D.png differ
diff --git a/logos/MTV-H.png b/logos/MTV-H.png
new file mode 100755
index 0000000..867a128
Binary files /dev/null and b/logos/MTV-H.png differ
diff --git a/logos/MTV-L.png b/logos/MTV-L.png
new file mode 100755
index 0000000..056cc5f
Binary files /dev/null and b/logos/MTV-L.png differ
diff --git a/logos/MTV.png b/logos/MTV.png
new file mode 100755
index 0000000..e775686
Binary files /dev/null and b/logos/MTV.png differ
diff --git a/logos/MUE2.png b/logos/MUE2.png
new file mode 100755
index 0000000..cfd3b99
Binary files /dev/null and b/logos/MUE2.png differ
diff --git a/logos/Makefile.am b/logos/Makefile.am
new file mode 100644
index 0000000..e51c92b
--- /dev/null
+++ b/logos/Makefile.am
@@ -0,0 +1,2 @@
+installdir = $(libdir)/enigma2/python/Plugins/Extensions/TVMagazineCockpit/logos
+install_DATA = *.png
diff --git a/logos/N-GHD.png b/logos/N-GHD.png
new file mode 100755
index 0000000..3d0f2c4
Binary files /dev/null and b/logos/N-GHD.png differ
diff --git a/logos/N-GW.png b/logos/N-GW.png
new file mode 100755
index 0000000..9c807dd
Binary files /dev/null and b/logos/N-GW.png differ
diff --git a/logos/N24DOKU.png b/logos/N24DOKU.png
new file mode 100755
index 0000000..3c93706
Binary files /dev/null and b/logos/N24DOKU.png differ
diff --git a/logos/N3.png b/logos/N3.png
new file mode 100755
index 0000000..72017e5
Binary files /dev/null and b/logos/N3.png differ
diff --git a/logos/NAUCH.png b/logos/NAUCH.png
new file mode 100755
index 0000000..7ef8d1f
Binary files /dev/null and b/logos/NAUCH.png differ
diff --git a/logos/NDR-HH.png b/logos/NDR-HH.png
new file mode 100755
index 0000000..f8c8f60
Binary files /dev/null and b/logos/NDR-HH.png differ
diff --git a/logos/NDR-MV.png b/logos/NDR-MV.png
new file mode 100755
index 0000000..24f7ad6
Binary files /dev/null and b/logos/NDR-MV.png differ
diff --git a/logos/NDR-NI.png b/logos/NDR-NI.png
new file mode 100755
index 0000000..59019ef
Binary files /dev/null and b/logos/NDR-NI.png differ
diff --git a/logos/NDR-SH.png b/logos/NDR-SH.png
new file mode 100755
index 0000000..00a4a95
Binary files /dev/null and b/logos/NDR-SH.png differ
diff --git a/logos/NDR.png b/logos/NDR.png
new file mode 100755
index 0000000..b1f4669
Binary files /dev/null and b/logos/NDR.png differ
diff --git a/logos/NHK.png b/logos/NHK.png
new file mode 100755
index 0000000..4b16ded
Binary files /dev/null and b/logos/NHK.png differ
diff --git a/logos/NICK.png b/logos/NICK.png
new file mode 100755
index 0000000..386cafa
Binary files /dev/null and b/logos/NICK.png differ
diff --git a/logos/NICKJ.png b/logos/NICKJ.png
new file mode 100755
index 0000000..1efe1e6
Binary files /dev/null and b/logos/NICKJ.png differ
diff --git a/logos/NICKT.png b/logos/NICKT.png
new file mode 100755
index 0000000..acef210
Binary files /dev/null and b/logos/NICKT.png differ
diff --git a/logos/NL1.png b/logos/NL1.png
new file mode 100755
index 0000000..4506086
Binary files /dev/null and b/logos/NL1.png differ
diff --git a/logos/NL2.png b/logos/NL2.png
new file mode 100755
index 0000000..84087a2
Binary files /dev/null and b/logos/NL2.png differ
diff --git a/logos/NL3.png b/logos/NL3.png
new file mode 100755
index 0000000..c35b7a5
Binary files /dev/null and b/logos/NL3.png differ
diff --git a/logos/NOWUS.png b/logos/NOWUS.png
new file mode 100755
index 0000000..16b3f08
Binary files /dev/null and b/logos/NOWUS.png differ
diff --git a/logos/NTV.png b/logos/NTV.png
new file mode 100755
index 0000000..ce9a786
Binary files /dev/null and b/logos/NTV.png differ
diff --git a/logos/OE24TV.png b/logos/OE24TV.png
new file mode 100755
index 0000000..ac7a5f4
Binary files /dev/null and b/logos/OE24TV.png differ
diff --git a/logos/ORF1.png b/logos/ORF1.png
new file mode 100755
index 0000000..0bbd870
Binary files /dev/null and b/logos/ORF1.png differ
diff --git a/logos/ORF2.png b/logos/ORF2.png
new file mode 100755
index 0000000..3426caf
Binary files /dev/null and b/logos/ORF2.png differ
diff --git a/logos/ORF3.png b/logos/ORF3.png
new file mode 100755
index 0000000..3ec1688
Binary files /dev/null and b/logos/ORF3.png differ
diff --git a/logos/ORFSP.png b/logos/ORFSP.png
new file mode 100755
index 0000000..186509f
Binary files /dev/null and b/logos/ORFSP.png differ
diff --git a/logos/PASS.png b/logos/PASS.png
new file mode 100755
index 0000000..33bcc05
Binary files /dev/null and b/logos/PASS.png differ
diff --git a/logos/PBOY.png b/logos/PBOY.png
new file mode 100755
index 0000000..05dc5e8
Binary files /dev/null and b/logos/PBOY.png differ
diff --git a/logos/PHOEN.png b/logos/PHOEN.png
new file mode 100755
index 0000000..af619d3
Binary files /dev/null and b/logos/PHOEN.png differ
diff --git a/logos/PLANE.png b/logos/PLANE.png
new file mode 100755
index 0000000..9d96e76
Binary files /dev/null and b/logos/PLANE.png differ
diff --git a/logos/PRO7.png b/logos/PRO7.png
new file mode 100755
index 0000000..44ce381
Binary files /dev/null and b/logos/PRO7.png differ
diff --git a/logos/PRO7F.png b/logos/PRO7F.png
new file mode 100755
index 0000000..6cf3125
Binary files /dev/null and b/logos/PRO7F.png differ
diff --git a/logos/PRO7M.png b/logos/PRO7M.png
new file mode 100755
index 0000000..3fee44b
Binary files /dev/null and b/logos/PRO7M.png differ
diff --git a/logos/PULS4.png b/logos/PULS4.png
new file mode 100755
index 0000000..fedcadf
Binary files /dev/null and b/logos/PULS4.png differ
diff --git a/logos/PULS8.png b/logos/PULS8.png
new file mode 100755
index 0000000..10995fc
Binary files /dev/null and b/logos/PULS8.png differ
diff --git a/logos/QVC.png b/logos/QVC.png
new file mode 100755
index 0000000..95cee8f
Binary files /dev/null and b/logos/QVC.png differ
diff --git a/logos/QVCBS.png b/logos/QVCBS.png
new file mode 100755
index 0000000..f27af48
Binary files /dev/null and b/logos/QVCBS.png differ
diff --git a/logos/QVCP.png b/logos/QVCP.png
new file mode 100755
index 0000000..58ab77f
Binary files /dev/null and b/logos/QVCP.png differ
diff --git a/logos/RB-TV.png b/logos/RB-TV.png
new file mode 100755
index 0000000..10563e1
Binary files /dev/null and b/logos/RB-TV.png differ
diff --git a/logos/RBB-B.png b/logos/RBB-B.png
new file mode 100755
index 0000000..a2c6749
Binary files /dev/null and b/logos/RBB-B.png differ
diff --git a/logos/RBB-BB.png b/logos/RBB-BB.png
new file mode 100755
index 0000000..141444d
Binary files /dev/null and b/logos/RBB-BB.png differ
diff --git a/logos/RBB.png b/logos/RBB.png
new file mode 100755
index 0000000..796312f
Binary files /dev/null and b/logos/RBB.png differ
diff --git a/logos/RBTV.png b/logos/RBTV.png
new file mode 100755
index 0000000..d55b343
Binary files /dev/null and b/logos/RBTV.png differ
diff --git a/logos/RCK.png b/logos/RCK.png
new file mode 100755
index 0000000..9599a2b
Binary files /dev/null and b/logos/RCK.png differ
diff --git a/logos/REGBS.png b/logos/REGBS.png
new file mode 100755
index 0000000..98c32ec
Binary files /dev/null and b/logos/REGBS.png differ
diff --git a/logos/REGIO.png b/logos/REGIO.png
new file mode 100755
index 0000000..d92adbc
Binary files /dev/null and b/logos/REGIO.png differ
diff --git a/logos/RIC.png b/logos/RIC.png
new file mode 100755
index 0000000..6dc963b
Binary files /dev/null and b/logos/RIC.png differ
diff --git a/logos/RMTV.png b/logos/RMTV.png
new file mode 100755
index 0000000..672c92a
Binary files /dev/null and b/logos/RMTV.png differ
diff --git a/logos/RNF.png b/logos/RNF.png
new file mode 100755
index 0000000..300a7f3
Binary files /dev/null and b/logos/RNF.png differ
diff --git a/logos/ROM.png b/logos/ROM.png
new file mode 100755
index 0000000..c98ad92
Binary files /dev/null and b/logos/ROM.png differ
diff --git a/logos/RTL-C.png b/logos/RTL-C.png
new file mode 100755
index 0000000..926fb2c
Binary files /dev/null and b/logos/RTL-C.png differ
diff --git a/logos/RTL-L.png b/logos/RTL-L.png
new file mode 100755
index 0000000..a4d8f8f
Binary files /dev/null and b/logos/RTL-L.png differ
diff --git a/logos/RTL-N.png b/logos/RTL-N.png
new file mode 100755
index 0000000..2b8ebc1
Binary files /dev/null and b/logos/RTL-N.png differ
diff --git a/logos/RTL.png b/logos/RTL.png
new file mode 100755
index 0000000..93b68f9
Binary files /dev/null and b/logos/RTL.png differ
diff --git a/logos/RTL2.png b/logos/RTL2.png
new file mode 100755
index 0000000..00f2e7e
Binary files /dev/null and b/logos/RTL2.png differ
diff --git a/logos/RTLPL.png b/logos/RTLPL.png
new file mode 100755
index 0000000..859fdde
Binary files /dev/null and b/logos/RTLPL.png differ
diff --git a/logos/S1PLU.png b/logos/S1PLU.png
new file mode 100755
index 0000000..48c23d4
Binary files /dev/null and b/logos/S1PLU.png differ
diff --git a/logos/SACH.png b/logos/SACH.png
new file mode 100755
index 0000000..92cab92
Binary files /dev/null and b/logos/SACH.png differ
diff --git a/logos/SAT1.png b/logos/SAT1.png
new file mode 100755
index 0000000..911fb01
Binary files /dev/null and b/logos/SAT1.png differ
diff --git a/logos/SAT1E.png b/logos/SAT1E.png
new file mode 100755
index 0000000..3de1e1a
Binary files /dev/null and b/logos/SAT1E.png differ
diff --git a/logos/SAT1G.png b/logos/SAT1G.png
new file mode 100755
index 0000000..64dc5c5
Binary files /dev/null and b/logos/SAT1G.png differ
diff --git a/logos/SCIFI.png b/logos/SCIFI.png
new file mode 100755
index 0000000..87a4162
Binary files /dev/null and b/logos/SCIFI.png differ
diff --git a/logos/SERVU.png b/logos/SERVU.png
new file mode 100755
index 0000000..9337c52
Binary files /dev/null and b/logos/SERVU.png differ
diff --git a/logos/SERVUSA.png b/logos/SERVUSA.png
new file mode 100755
index 0000000..e7f875f
--- /dev/null
+++ b/logos/SERVUSA.png
@@ -0,0 +1,2 @@
+
+AccessDeniedAccess Denied2AD6SA2Y8GZD7N5FYrHbYtEc7tKYovPqAqbZuKrCDzSlj0Cjan9aPbMIExv16Re5lcEE1dGyUJD6NiVCDrufjEW4+pc=
\ No newline at end of file
diff --git a/logos/SF1.png b/logos/SF1.png
new file mode 100755
index 0000000..65c2f4e
Binary files /dev/null and b/logos/SF1.png differ
diff --git a/logos/SF2.png b/logos/SF2.png
new file mode 100755
index 0000000..2d20959
Binary files /dev/null and b/logos/SF2.png differ
diff --git a/logos/SHD2.png b/logos/SHD2.png
new file mode 100755
index 0000000..6cd3f58
Binary files /dev/null and b/logos/SHD2.png differ
diff --git a/logos/SHOT.png b/logos/SHOT.png
new file mode 100755
index 0000000..1890503
Binary files /dev/null and b/logos/SHOT.png differ
diff --git a/logos/SILVE.png b/logos/SILVE.png
new file mode 100755
index 0000000..d9ed099
Binary files /dev/null and b/logos/SILVE.png differ
diff --git a/logos/SIXX.png b/logos/SIXX.png
new file mode 100755
index 0000000..b98ce4d
Binary files /dev/null and b/logos/SIXX.png differ
diff --git a/logos/SKLAR.png b/logos/SKLAR.png
new file mode 100755
index 0000000..bd276d3
Binary files /dev/null and b/logos/SKLAR.png differ
diff --git a/logos/SKY-A.png b/logos/SKY-A.png
new file mode 100755
index 0000000..4c0c04a
Binary files /dev/null and b/logos/SKY-A.png differ
diff --git a/logos/SKY-C.png b/logos/SKY-C.png
new file mode 100755
index 0000000..f71f316
Binary files /dev/null and b/logos/SKY-C.png differ
diff --git a/logos/SKY-CO.png b/logos/SKY-CO.png
new file mode 100755
index 0000000..7270ab7
Binary files /dev/null and b/logos/SKY-CO.png differ
diff --git a/logos/SKY-CR.png b/logos/SKY-CR.png
new file mode 100755
index 0000000..1479e91
Binary files /dev/null and b/logos/SKY-CR.png differ
diff --git a/logos/SKY-D.png b/logos/SKY-D.png
new file mode 100755
index 0000000..de4d991
Binary files /dev/null and b/logos/SKY-D.png differ
diff --git a/logos/SKY-E.png b/logos/SKY-E.png
new file mode 100755
index 0000000..9f2b8f5
Binary files /dev/null and b/logos/SKY-E.png differ
diff --git a/logos/SKY-F.png b/logos/SKY-F.png
new file mode 100755
index 0000000..fc75dc8
Binary files /dev/null and b/logos/SKY-F.png differ
diff --git a/logos/SKY-H.png b/logos/SKY-H.png
new file mode 100755
index 0000000..ac706da
Binary files /dev/null and b/logos/SKY-H.png differ
diff --git a/logos/SKY-K.png b/logos/SKY-K.png
new file mode 100755
index 0000000..98b7c00
Binary files /dev/null and b/logos/SKY-K.png differ
diff --git a/logos/SKY-N.png b/logos/SKY-N.png
new file mode 100755
index 0000000..84eca8b
Binary files /dev/null and b/logos/SKY-N.png differ
diff --git a/logos/SKY-NA.png b/logos/SKY-NA.png
new file mode 100755
index 0000000..afe620a
Binary files /dev/null and b/logos/SKY-NA.png differ
diff --git a/logos/SKY-S.png b/logos/SKY-S.png
new file mode 100755
index 0000000..ddfd779
Binary files /dev/null and b/logos/SKY-S.png differ
diff --git a/logos/SKY1.png b/logos/SKY1.png
new file mode 100755
index 0000000..d180745
Binary files /dev/null and b/logos/SKY1.png differ
diff --git a/logos/SKYAT.png b/logos/SKYAT.png
new file mode 100755
index 0000000..e94eb08
Binary files /dev/null and b/logos/SKYAT.png differ
diff --git a/logos/SKYCS.png b/logos/SKYCS.png
new file mode 100755
index 0000000..22313b5
Binary files /dev/null and b/logos/SKYCS.png differ
diff --git a/logos/SKYF1.png b/logos/SKYF1.png
new file mode 100755
index 0000000..a0cd453
Binary files /dev/null and b/logos/SKYF1.png differ
diff --git a/logos/SKYRP.png b/logos/SKYRP.png
new file mode 100755
index 0000000..239e75c
--- /dev/null
+++ b/logos/SKYRP.png
@@ -0,0 +1,2 @@
+
+AccessDeniedAccess Denied5Q9BCX5H8P1SRGATw1fjaHF5dMDNnCafHSwzBJtpb34QamfB5jWaE3r1WZIqwXUKtxGhLxkeDidsxrEJsLRxG+OKFjU=
\ No newline at end of file
diff --git a/logos/SKYSG.png b/logos/SKYSG.png
new file mode 100755
index 0000000..804226d
--- /dev/null
+++ b/logos/SKYSG.png
@@ -0,0 +1,2 @@
+
+AccessDeniedAccess DeniedXPZEQC0Z34WQQGTG2VJ9t2a9I1pF/+hFtVHSgo6yg7VIXRrBWPnoCvTnppzQ7CpjWHiHsp7gMUMk1/4bPhxzHqJpKWA=
\ No newline at end of file
diff --git a/logos/SKYSH.png b/logos/SKYSH.png
new file mode 100755
index 0000000..129a645
--- /dev/null
+++ b/logos/SKYSH.png
@@ -0,0 +1,2 @@
+
+AccessDeniedAccess DeniedXPZ8646BK33PWJPAZsqlcQ3a2E2l7ECmT1X5orIZl9mEOG7OO2xE7pdGkIMGBeTHL1QTuRJN1c0l3vpW6sMNpaRUfVc=
\ No newline at end of file
diff --git a/logos/SKYSM.png b/logos/SKYSM.png
new file mode 100755
index 0000000..4233880
--- /dev/null
+++ b/logos/SKYSM.png
@@ -0,0 +1,2 @@
+
+AccessDeniedAccess DeniedXPZ0DYAKV39GWQVMeRaialFxGREqG3NV+DuW5TguPM0wZuby3DRrWfhJIz77VXDWhqUpJ4EZGRwwB2hiQJU4TV/4sgQ=
\ No newline at end of file
diff --git a/logos/SKYSPL.png b/logos/SKYSPL.png
new file mode 100755
index 0000000..aa04b21
--- /dev/null
+++ b/logos/SKYSPL.png
@@ -0,0 +1,2 @@
+
+AccessDeniedAccess Denied2ADBN44SGEPHQTFHIASXRgi5QNOVx7q8LD5+4gRptIqhIsZiRPfXhuDnv1vT5O3wjclzgdMX0lZuFhuAFtAZUZQng8A=
\ No newline at end of file
diff --git a/logos/SKYST.png b/logos/SKYST.png
new file mode 100755
index 0000000..c5a9522
--- /dev/null
+++ b/logos/SKYST.png
@@ -0,0 +1,2 @@
+
+AccessDeniedAccess DeniedXPZ1XZ8V3B8VSHCXK/rfEB2BNXyVJmDGmu9Udkd8E6gJ7hx7NU9iKQ7vf6qeMKyNrv8HCIcm9ZQ0f7a5G0UfiQQ0qtg=
\ No newline at end of file
diff --git a/logos/SKYSTE.png b/logos/SKYSTE.png
new file mode 100755
index 0000000..b7c2cb1
--- /dev/null
+++ b/logos/SKYSTE.png
@@ -0,0 +1,2 @@
+
+AccessDeniedAccess Denied5Q91Q6H6MX30PKZA40c6onhFAM4K0GWoRPP9O8L8NKI/InApv3pzvWCTRvCT2PwHJqqNVurHSS7dcVoQMifOEvju92w=
\ No newline at end of file
diff --git a/logos/SKYTH.png b/logos/SKYTH.png
new file mode 100755
index 0000000..ce7e53b
Binary files /dev/null and b/logos/SKYTH.png differ
diff --git a/logos/SNHD.png b/logos/SNHD.png
new file mode 100755
index 0000000..f395497
Binary files /dev/null and b/logos/SNHD.png differ
diff --git a/logos/SONY.png b/logos/SONY.png
new file mode 100755
index 0000000..2dc829e
Binary files /dev/null and b/logos/SONY.png differ
diff --git a/logos/SP-GE.png b/logos/SP-GE.png
new file mode 100755
index 0000000..51dc8ce
Binary files /dev/null and b/logos/SP-GE.png differ
diff --git a/logos/SP1US.png b/logos/SP1US.png
new file mode 100755
index 0000000..4603f34
Binary files /dev/null and b/logos/SP1US.png differ
diff --git a/logos/SPO-A.png b/logos/SPO-A.png
new file mode 100755
index 0000000..7367ee3
Binary files /dev/null and b/logos/SPO-A.png differ
diff --git a/logos/SPO-D.png b/logos/SPO-D.png
new file mode 100755
index 0000000..09d13e3
Binary files /dev/null and b/logos/SPO-D.png differ
diff --git a/logos/SPORT.png b/logos/SPORT.png
new file mode 100755
index 0000000..eef4c05
Binary files /dev/null and b/logos/SPORT.png differ
diff --git a/logos/SPTVW.png b/logos/SPTVW.png
new file mode 100755
index 0000000..e55a962
Binary files /dev/null and b/logos/SPTVW.png differ
diff --git a/logos/SPUHD.png b/logos/SPUHD.png
new file mode 100755
index 0000000..32a344e
Binary files /dev/null and b/logos/SPUHD.png differ
diff --git a/logos/SR.png b/logos/SR.png
new file mode 100755
index 0000000..b7a1848
Binary files /dev/null and b/logos/SR.png differ
diff --git a/logos/STTV.png b/logos/STTV.png
new file mode 100755
index 0000000..c2705b8
Binary files /dev/null and b/logos/STTV.png differ
diff --git a/logos/SUPER.png b/logos/SUPER.png
new file mode 100755
index 0000000..aa9d85f
Binary files /dev/null and b/logos/SUPER.png differ
diff --git a/logos/SWR.png b/logos/SWR.png
new file mode 100755
index 0000000..d5afec3
Binary files /dev/null and b/logos/SWR.png differ
diff --git a/logos/SWRBW.png b/logos/SWRBW.png
new file mode 100755
index 0000000..55b8465
Binary files /dev/null and b/logos/SWRBW.png differ
diff --git a/logos/SWRRP.png b/logos/SWRRP.png
new file mode 100755
index 0000000..ce098a5
Binary files /dev/null and b/logos/SWRRP.png differ
diff --git a/logos/TAG24.png b/logos/TAG24.png
new file mode 100755
index 0000000..3f0429a
Binary files /dev/null and b/logos/TAG24.png differ
diff --git a/logos/TELE5.png b/logos/TELE5.png
new file mode 100755
index 0000000..8693586
Binary files /dev/null and b/logos/TELE5.png differ
diff --git a/logos/TLC.png b/logos/TLC.png
new file mode 100755
index 0000000..ede7b68
Binary files /dev/null and b/logos/TLC.png differ
diff --git a/logos/TMAX.png b/logos/TMAX.png
new file mode 100755
index 0000000..a213fcf
Binary files /dev/null and b/logos/TMAX.png differ
diff --git a/logos/TNT-C.png b/logos/TNT-C.png
new file mode 100755
index 0000000..79fd648
Binary files /dev/null and b/logos/TNT-C.png differ
diff --git a/logos/TNT-F.png b/logos/TNT-F.png
new file mode 100755
index 0000000..e1b0e90
Binary files /dev/null and b/logos/TNT-F.png differ
diff --git a/logos/TNT-S.png b/logos/TNT-S.png
new file mode 100755
index 0000000..c2324f3
Binary files /dev/null and b/logos/TNT-S.png differ
diff --git a/logos/TOGGO.png b/logos/TOGGO.png
new file mode 100755
index 0000000..31a199e
Binary files /dev/null and b/logos/TOGGO.png differ
diff --git a/logos/TRACE.png b/logos/TRACE.png
new file mode 100755
index 0000000..83d3cc3
Binary files /dev/null and b/logos/TRACE.png differ
diff --git a/logos/TRAVELXP.png b/logos/TRAVELXP.png
new file mode 100755
index 0000000..8d30fe4
Binary files /dev/null and b/logos/TRAVELXP.png differ
diff --git a/logos/TRCH.png b/logos/TRCH.png
new file mode 100755
index 0000000..8255df7
Binary files /dev/null and b/logos/TRCH.png differ
diff --git a/logos/TV2.png b/logos/TV2.png
new file mode 100755
index 0000000..4b473bb
Binary files /dev/null and b/logos/TV2.png differ
diff --git a/logos/TV5.png b/logos/TV5.png
new file mode 100755
index 0000000..606c82e
Binary files /dev/null and b/logos/TV5.png differ
diff --git a/logos/TVB.png b/logos/TVB.png
new file mode 100755
index 0000000..0dbff08
Binary files /dev/null and b/logos/TVB.png differ
diff --git a/logos/TVM.png b/logos/TVM.png
new file mode 100755
index 0000000..d42d0ae
Binary files /dev/null and b/logos/TVM.png differ
diff --git a/logos/UHD1.png b/logos/UHD1.png
new file mode 100755
index 0000000..d5277b9
Binary files /dev/null and b/logos/UHD1.png differ
diff --git a/logos/UNIVE.png b/logos/UNIVE.png
new file mode 100755
index 0000000..c8737a4
Binary files /dev/null and b/logos/UNIVE.png differ
diff --git a/logos/VH1.png b/logos/VH1.png
new file mode 100755
index 0000000..5a8d79a
Binary files /dev/null and b/logos/VH1.png differ
diff --git a/logos/VIVA.png b/logos/VIVA.png
new file mode 100755
index 0000000..0cdd587
Binary files /dev/null and b/logos/VIVA.png differ
diff --git a/logos/VOX.png b/logos/VOX.png
new file mode 100755
index 0000000..532458b
Binary files /dev/null and b/logos/VOX.png differ
diff --git a/logos/VOXUP.png b/logos/VOXUP.png
new file mode 100755
index 0000000..ccae75c
Binary files /dev/null and b/logos/VOXUP.png differ
diff --git a/logos/WDR-AC.png b/logos/WDR-AC.png
new file mode 100755
index 0000000..16e6485
Binary files /dev/null and b/logos/WDR-AC.png differ
diff --git a/logos/WDR-BI.png b/logos/WDR-BI.png
new file mode 100755
index 0000000..adf9045
Binary files /dev/null and b/logos/WDR-BI.png differ
diff --git a/logos/WDR-BN.png b/logos/WDR-BN.png
new file mode 100755
index 0000000..ff259e6
Binary files /dev/null and b/logos/WDR-BN.png differ
diff --git a/logos/WDR-D.png b/logos/WDR-D.png
new file mode 100755
index 0000000..0c5476d
Binary files /dev/null and b/logos/WDR-D.png differ
diff --git a/logos/WDR-DO.png b/logos/WDR-DO.png
new file mode 100755
index 0000000..0c4f236
Binary files /dev/null and b/logos/WDR-DO.png differ
diff --git a/logos/WDR-DU.png b/logos/WDR-DU.png
new file mode 100755
index 0000000..d535217
Binary files /dev/null and b/logos/WDR-DU.png differ
diff --git a/logos/WDR-E.png b/logos/WDR-E.png
new file mode 100755
index 0000000..d18d665
Binary files /dev/null and b/logos/WDR-E.png differ
diff --git a/logos/WDR-K.png b/logos/WDR-K.png
new file mode 100755
index 0000000..d1496a5
Binary files /dev/null and b/logos/WDR-K.png differ
diff --git a/logos/WDR-MS.png b/logos/WDR-MS.png
new file mode 100755
index 0000000..27abb08
Binary files /dev/null and b/logos/WDR-MS.png differ
diff --git a/logos/WDR-SI.png b/logos/WDR-SI.png
new file mode 100755
index 0000000..4fa858b
Binary files /dev/null and b/logos/WDR-SI.png differ
diff --git a/logos/WDR-W.png b/logos/WDR-W.png
new file mode 100755
index 0000000..b3f580d
Binary files /dev/null and b/logos/WDR-W.png differ
diff --git a/logos/WDR.png b/logos/WDR.png
new file mode 100755
index 0000000..87e267f
Binary files /dev/null and b/logos/WDR.png differ
diff --git a/logos/WDWTV.png b/logos/WDWTV.png
new file mode 100755
index 0000000..38204b4
Binary files /dev/null and b/logos/WDWTV.png differ
diff --git a/logos/WELT.png b/logos/WELT.png
new file mode 100755
index 0000000..91e0b3b
Binary files /dev/null and b/logos/WELT.png differ
diff --git a/logos/ZDF.png b/logos/ZDF.png
new file mode 100755
index 0000000..fe56aa9
Binary files /dev/null and b/logos/ZDF.png differ
diff --git a/logos/ZEE-1.png b/logos/ZEE-1.png
new file mode 100755
index 0000000..2246019
Binary files /dev/null and b/logos/ZEE-1.png differ
diff --git a/logos/ZINFO.png b/logos/ZINFO.png
new file mode 100755
index 0000000..c356a62
Binary files /dev/null and b/logos/ZINFO.png differ
diff --git a/po/Makefile.am b/po/Makefile.am
new file mode 100644
index 0000000..9c7baa2
--- /dev/null
+++ b/po/Makefile.am
@@ -0,0 +1,61 @@
+#
+# to use this for the localisation of other plugins,
+# just change the DOMAIN to the name of the Plugin.
+# It is assumed, that the domain ist the same as
+# the directory name of the plugin.
+#
+
+DOMAIN = TVMagazineCockpit
+installdir = $(libdir)/enigma2/python/Plugins/Extensions/$(DOMAIN)
+#GETTEXT=./pygettext.py
+GETTEXT=xgettext
+
+#MSGFMT = ./msgfmt.py
+MSGFMT = msgfmt
+
+LANGS := de
+LANGPO := $(foreach LANG, $(LANGS),$(LANG).po)
+LANGMO := $(foreach LANG, $(LANGS),$(LANG).mo)
+
+default: $(DOMAIN).pot $(LANGPO) merge $(LANGMO)
+ for lang in $(LANGS); do \
+ mkdir -p $$lang/LC_MESSAGES; \
+ cp $$lang.mo $$lang/LC_MESSAGES/$(DOMAIN).mo; \
+ cp $$lang.po $$lang/LC_MESSAGES/$$lang.po; \
+ done
+
+merge:
+ for lang in $(LANGS); do \
+ msgmerge --no-location -s -N -U $$lang.po $(DOMAIN).pot; \
+ done
+
+
+# the TRANSLATORS: allows putting translation comments before the to-be-translated line.
+$(DOMAIN).pot:
+ $(GETTEXT) -L python --add-comments="TRANSLATORS:" -d $(DOMAIN) -s -o $(DOMAIN).pot ../*.py
+
+ ../xml2po.py ../ >> $(DOMAIN).pot
+
+ msguniq -o $(DOMAIN)uniq.pot $(DOMAIN).pot
+
+
+.PHONY: $(DOMAIN).pot
+
+
+%.mo: %.po
+ $(MSGFMT) -o $@ $<
+
+%.po:
+ msginit -l $@ -o $@ -i $(DOMAIN).pot --no-translator
+
+CLEANFILES = $(foreach LANG, $(LANGS),$(LANG).mo)
+
+clean-local:
+ $(RM) -r $(LANGS)
+
+install-data-am: default
+ for lang in $(LANGS); do \
+ mkdir -p $(DESTDIR)$(installdir)/locale/$$lang/LC_MESSAGES; \
+ cp $$lang.mo $(DESTDIR)$(installdir)/locale/$$lang/LC_MESSAGES/$(DOMAIN).mo; \
+ cp $$lang.po $(DESTDIR)$(installdir)/locale/$$lang/LC_MESSAGES/$$lang.po; \
+ done
diff --git a/po/TVMagazineCockpit.pot b/po/TVMagazineCockpit.pot
new file mode 100644
index 0000000..2750521
--- /dev/null
+++ b/po/TVMagazineCockpit.pot
@@ -0,0 +1,240 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: \n"
+"POT-Creation-Date: 2024-07-09 18:46+0200\n"
+"PO-Revision-Date: 2024-07-09 18:48+0200\n"
+"Last-Translator: dream-alpha\n"
+"Language-Team: \n"
+"Language: de_DE\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Generator: Poedit 3.4.4\n"
+"X-Poedit-Basepath: ../src\n"
+"X-Poedit-SearchPath-0: .\n"
+
+msgid "Exit"
+msgstr ""
+
+msgid "TV Bouquets"
+msgstr ""
+
+msgid "Bouquets"
+msgstr ""
+
+msgid "Service Reference"
+msgstr ""
+
+msgid "Favorites"
+msgstr ""
+
+msgid "not found"
+msgstr ""
+
+msgid "Channel Management"
+msgstr ""
+
+msgid "Press OK for channel list"
+msgstr ""
+
+msgid "Save"
+msgstr ""
+
+msgid "name difference"
+msgstr ""
+
+msgid "Bouquet"
+msgstr ""
+
+msgid "Press OK to enable/disable move function or Menu for more options"
+msgstr ""
+
+msgid "Select"
+msgstr ""
+
+msgid "Delete channel"
+msgstr ""
+
+msgid "Delete all channels"
+msgstr ""
+
+msgid "Zap"
+msgstr ""
+
+msgid "Add channel"
+msgstr ""
+
+msgid "Add all channels"
+msgstr ""
+
+msgid "Channels (TV)"
+msgstr ""
+
+msgid "Move mode enabled"
+msgstr ""
+
+msgid "TV Bouquet Channels"
+msgstr ""
+
+msgid "Press OK to add channel, or Menu for more options"
+msgstr ""
+
+msgid "Default"
+msgstr ""
+
+msgid "Sky"
+msgstr ""
+
+msgid "All"
+msgstr ""
+
+msgid "COCKPIT"
+msgstr ""
+
+msgid "Default bouquet"
+msgstr ""
+
+msgid "Select the default bouquet."
+msgstr ""
+
+msgid "Picon directory"
+msgstr ""
+
+msgid "Select the directory the picons are stored in."
+msgstr ""
+
+msgid "Use picons"
+msgstr ""
+
+msgid "Should channel picons be used instead of channel logos?"
+msgstr ""
+
+msgid "DEBUG"
+msgstr ""
+
+msgid "Log level"
+msgstr ""
+
+msgid "Select the debug log level."
+msgstr ""
+
+msgid "default"
+msgstr ""
+
+msgid "favorites"
+msgstr ""
+
+msgid "sky"
+msgstr ""
+
+msgid "all"
+msgstr ""
+
+msgid "Error during download"
+msgstr ""
+
+msgid "Event Details"
+msgstr ""
+
+msgid "min"
+msgstr ""
+
+msgid "Add Timer"
+msgstr ""
+
+msgid "Menu"
+msgstr ""
+
+msgid "Input"
+msgstr ""
+
+msgid "Bouquet Selection"
+msgstr ""
+
+msgid "Bouquet Setup"
+msgstr ""
+
+msgid "Settings"
+msgstr ""
+
+msgid "About"
+msgstr ""
+
+msgid "More"
+msgstr ""
+
+msgid "20:15"
+msgstr ""
+
+msgid "22:00"
+msgstr ""
+
+msgid "Now"
+msgstr ""
+
+msgid "column view"
+msgstr ""
+
+msgid "Loading..."
+msgstr ""
+
+msgid "Page"
+msgstr ""
+
+msgid "Services"
+msgstr ""
+
+msgid "Browse TV Magazine"
+msgstr ""
+
+msgid "TVMagazineCockpit"
+msgstr ""
+
+msgid "TVMagazine Event Infos"
+msgstr ""
+
+msgid "TVMagazineCockpit Event Infos"
+msgstr ""
+
+msgid "Plugin"
+msgstr ""
+
+msgid "Version"
+msgstr ""
+
+msgid "Copyright"
+msgstr ""
+
+msgid "License"
+msgstr ""
+
+msgid "Cancel"
+msgstr ""
+
+msgid "Defaults"
+msgstr ""
+
+msgid "Setup"
+msgstr ""
+
+msgid "Really close without saving settings?"
+msgstr ""
+
+msgid "Loading default settings will overwrite all settings, really load them?"
+msgstr ""
+
+msgid "Some changes require a GUI restart"
+msgstr ""
+
+msgid "Restart GUI now?"
+msgstr ""
+
+msgid "Bookmarks"
+msgstr ""
+
+msgid "Select directory"
+msgstr ""
+
+msgid "Path does not exist"
+msgstr ""
diff --git a/po/de.po b/po/de.po
new file mode 100644
index 0000000..c9e9ccf
--- /dev/null
+++ b/po/de.po
@@ -0,0 +1,247 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: \n"
+"POT-Creation-Date: 2024-07-09 18:46+0200\n"
+"PO-Revision-Date: 2024-07-09 18:48+0200\n"
+"Last-Translator: dream-alpha\n"
+"Language-Team: \n"
+"Language: de_DE\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Generator: Poedit 3.4.4\n"
+"X-Poedit-Basepath: ../src\n"
+"X-Poedit-SearchPath-0: .\n"
+
+msgid "Exit"
+msgstr "Beenden"
+
+msgid "TV Bouquets"
+msgstr "TV Bouquets"
+
+msgid "Bouquets"
+msgstr "Bouquets"
+
+msgid "Service Reference"
+msgstr "Kanal Referenz"
+
+msgid "Favorites"
+msgstr "Favoriten"
+
+msgid "not found"
+msgstr "nicht gefunden"
+
+msgid "Channel Management"
+msgstr "Kanalverwaltung"
+
+msgid "Press OK for channel list"
+msgstr "Drücke OK zur Anzeige der Kanalliste"
+
+msgid "Save"
+msgstr "Speichern"
+
+msgid "name difference"
+msgstr "Namensunterschied"
+
+msgid "Bouquet"
+msgstr "Bouquet"
+
+msgid "Press OK to enable/disable move function or Menu for more options"
+msgstr ""
+"Drücke OK zum Aktivieren/Deaktivieren der Verschiebefunktion oder Menü für "
+"weitere Funkionen"
+
+msgid "Select"
+msgstr "Auswahl"
+
+msgid "Delete channel"
+msgstr "Kanal löschen"
+
+msgid "Delete all channels"
+msgstr "Alle Kanäle löschen"
+
+msgid "Zap"
+msgstr "Umschalten"
+
+msgid "Add channel"
+msgstr "Kanal hinzufügen"
+
+msgid "Add all channels"
+msgstr "Alle Kanäle hinzufügen"
+
+msgid "Channels (TV)"
+msgstr "Kanäle (TV)"
+
+msgid "Move mode enabled"
+msgstr "Verschiebemodus"
+
+msgid "TV Bouquet Channels"
+msgstr "TV Bouquet Kanäle"
+
+msgid "Press OK to add channel, or Menu for more options"
+msgstr ""
+"Drücke OK um den Kanal zum Bouquet hinzuzufügen oder Menü für weitere "
+"Funktionen"
+
+msgid "Default"
+msgstr "Standard"
+
+msgid "Sky"
+msgstr "SKY"
+
+msgid "All"
+msgstr "Alle"
+
+msgid "COCKPIT"
+msgstr "COCKPIT"
+
+msgid "Default bouquet"
+msgstr "Standard Bouquet"
+
+msgid "Select the default bouquet."
+msgstr "Auswahl des Standard Bouquets"
+
+msgid "Picon directory"
+msgstr "Picon Verzeichnis"
+
+msgid "Select the directory the picons are stored in."
+msgstr "Auswahl des Picon Verzeichnisses"
+
+msgid "Use picons"
+msgstr "Verwende Picons"
+
+msgid "Should channel picons be used instead of channel logos?"
+msgstr "Sollen Picons statt Logos verwendet werden?"
+
+msgid "DEBUG"
+msgstr "DEBUG"
+
+msgid "Log level"
+msgstr "Logstufe"
+
+msgid "Select the debug log level."
+msgstr "Auswahl der Logstufe"
+
+msgid "default"
+msgstr "Standard"
+
+msgid "favorites"
+msgstr "Favoriten"
+
+msgid "sky"
+msgstr "SKY"
+
+msgid "all"
+msgstr "Alle"
+
+msgid "Error during download"
+msgstr "Fehler beim Download"
+
+msgid "Event Details"
+msgstr "Sendungsdetails"
+
+msgid "min"
+msgstr "Min"
+
+msgid "Add Timer"
+msgstr "Timer hinzufügen"
+
+msgid "Menu"
+msgstr "Menü"
+
+msgid "Input"
+msgstr "Eingabe"
+
+msgid "Bouquet Selection"
+msgstr "Bouquetauswahl"
+
+msgid "Bouquet Setup"
+msgstr "Bouquetverwaltung"
+
+msgid "Settings"
+msgstr "Einstellungen"
+
+msgid "About"
+msgstr "Über"
+
+msgid "More"
+msgstr "Mehr"
+
+msgid "20:15"
+msgstr "20:15"
+
+msgid "22:00"
+msgstr "22:00"
+
+msgid "Now"
+msgstr "Jetzt"
+
+msgid "column view"
+msgstr "Spaltenansicht"
+
+msgid "Loading..."
+msgstr "Lade..."
+
+msgid "Page"
+msgstr "Seite"
+
+msgid "Services"
+msgstr "Kanäle"
+
+msgid "Browse TV Magazine"
+msgstr "TV Magazin duchblättern"
+
+msgid "TVMagazineCockpit"
+msgstr "TVMagazinCockpit"
+
+msgid "TVMagazine Event Infos"
+msgstr "TV Magazine Sendungsinfos"
+
+msgid "TVMagazineCockpit Event Infos"
+msgstr "TV Magazin Sendungsinfos"
+
+msgid "Plugin"
+msgstr "Plugin"
+
+msgid "Version"
+msgstr "Version"
+
+msgid "Copyright"
+msgstr "Copyright"
+
+msgid "License"
+msgstr "Lizenz"
+
+msgid "Cancel"
+msgstr "Abbruch"
+
+msgid "Defaults"
+msgstr "Standard"
+
+msgid "Setup"
+msgstr "Einstellungen"
+
+msgid "Really close without saving settings?"
+msgstr "Fortfahren ohne Speichern der Einstellungen?"
+
+msgid "Loading default settings will overwrite all settings, really load them?"
+msgstr ""
+"Das Laden der Standardeinstellungen überschreibt alle aktuellen "
+"Einstellungen.\n"
+"Sollen die Standardeinstellungen wirklich geladen werden?"
+
+msgid "Some changes require a GUI restart"
+msgstr "Einige Änderungen erfordern einen Neustart der GUI"
+
+msgid "Restart GUI now?"
+msgstr "Soll die GUI jetzt neu gestartet werden?"
+
+msgid "Bookmarks"
+msgstr "Lesezeichen"
+
+msgid "Select directory"
+msgstr "Verzeichnis-Auswahl"
+
+msgid "Path does not exist"
+msgstr "Verzeichnis existiert nicht"
diff --git a/setup.cfg b/setup.cfg
new file mode 100644
index 0000000..968fd5c
--- /dev/null
+++ b/setup.cfg
@@ -0,0 +1,9 @@
+[flake8]
+ignore = W191, W503, E117, E203, E242, E501
+
+[pycodestyle]
+count = False
+ignore = W191, W503, E117, E203, E242
+
+max-line-length = 320
+statistics = True
diff --git a/src/About.py b/src/About.py
new file mode 100644
index 0000000..32a751d
--- /dev/null
+++ b/src/About.py
@@ -0,0 +1,35 @@
+#!/usr/bin/python
+# coding=utf-8
+#
+# Copyright (C) 2018-2024 by dream-alpha
+#
+# In case of reuse of this source code please do not remove this copyright.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# For more information on the GNU General Public License see:
+# .
+
+
+from Screens.MessageBox import MessageBox
+from .Version import PLUGIN, VERSION, COPYRIGHT, LICENSE
+from .__init__ import _
+
+
+def about(session):
+ session.open(
+ MessageBox,
+ _("Plugin") + ": " + PLUGIN + "\n\n"
+ + _("Version") + ": " + VERSION + "\n\n"
+ + _("Copyright") + ": " + COPYRIGHT + "\n\n"
+ + _("License") + ": " + LICENSE,
+ MessageBox.TYPE_INFO
+ )
diff --git a/src/ChannelManagement.py b/src/ChannelManagement.py
new file mode 100755
index 0000000..12fd847
--- /dev/null
+++ b/src/ChannelManagement.py
@@ -0,0 +1,299 @@
+# !/usr/bin/python
+# coding=utf-8
+#
+# Copyright (C) 2018-2024 by dream-alpha
+#
+# In case of reuse of this source code please do not remove this copyright.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# For more information on the GNU General Public License see:
+# .
+
+
+import re
+from APIs.ServiceData import getTVBouquets, getServiceList
+from Screens.Screen import Screen
+from Screens.ChoiceBox import ChoiceBox
+# from Screens.MessageBox import MessageBox
+from Screens.ChannelSelection import service_types_tv
+from Screens.SimpleSummary import SimpleSummary
+from Components.ActionMap import ActionMap
+from Components.Label import Label
+from Components.Sources.StaticText import StaticText
+from ServiceReference import ServiceReference
+from Tools.Directories import resolveFilename, SCOPE_CONFIG
+from .__init__ import _
+from .MyList import MyList
+from .Debug import logger
+from .ChannelUtils import write_channel_list, getChannel
+from .Constants import TVS
+from .ZapUtils import Zap_Service
+
+
+class ChannelManagement(Screen):
+ def __init__(self, session, bouquet, channel_list, channel_dict):
+ logger.info("...")
+ self.bouquet = bouquet
+ self.channel_list = channel_list
+ self.channel_list_org = channel_list[:]
+ logger.debug("channel_list: %s", self.channel_list)
+ self.channel_dict = channel_dict
+ Screen.__init__(self, session)
+ self.skinName = "ChannelManagement"
+ self["actions"] = ActionMap(
+ ["TVC_Actions"],
+ {
+ "ok": self.key_ok,
+ "cancel": self.key_red,
+ "red": self.key_red,
+ "green": self.key_green,
+ "yellow": self.key_yellow,
+ "blue": self.key_blue,
+ # "info": self.showInfo,
+ "menu": self.showMenu,
+ # "menulong": self.showMenuLong
+ }
+ )
+ self["actionsmove"] = ActionMap(
+ ["TVC_Actions"],
+ {
+ "up": self.keyUp,
+ "down": self.keyDown,
+ "left": self.noop,
+ "right": self.noop
+ }
+ )
+ self["actionsmove"].setEnabled(False)
+
+ self["key_red"] = StaticText(_("Exit"))
+ self["key_green"] = StaticText()
+ self["key_yellow"] = StaticText(_("TV Bouquets"))
+ self["key_blue"] = StaticText(_("Bouquets"))
+
+ self["list"] = MyList()
+ self["list"].style = "default"
+ self.mytitlestr = ("mytitle1", "mytitle2", "mytitle3", "mytitle4", "mytitle5")
+ self["mytitle1"] = Label("TV Spielfilm Name")
+ self["mytitle2"] = Label("TV Spielfilm ID")
+ self["mytitle3"] = Label("Enigma Name")
+ self["mytitle4"] = Label(_("Service Reference"))
+ self["mytitle5"] = Label(_("Favorites"))
+ for myx in self.mytitlestr:
+ self[myx].hide()
+ self["message"] = Label()
+ self.listtype = ""
+ self.bouquet_list = []
+ self.key_blue()
+
+ def createBouquetList(self, channel_list, channel_dict):
+ result = []
+ for channel_name in channel_list:
+ channel_id = channel_dict[channel_name]["id"]
+ value = channel_dict[channel_name]
+ if value:
+ enameval = ""
+ ename = ServiceReference(value["service"]).getServiceName()
+ if not ename:
+ enameval = _("not found")
+ elif value["ename"] != ename:
+ enameval = ename
+ result.append([value["tname"], channel_id, value["ename"], value["service"], enameval, channel_name])
+ else:
+ result.append(["n/a", channel_id, "n/a", "n/a", ""])
+ return result
+
+ def noop(self):
+ logger.info("...")
+
+ def keyUp(self):
+ logger.info("...")
+ if self.listtype in "blue":
+ currindex = self["list"].getIndex()
+ self["list"].moveSelection("moveUp")
+ self["list"].list.insert(self["list"].getIndex(), self["list"].list.pop(currindex))
+
+ def keyDown(self):
+ logger.info("...")
+ if self.listtype in "blue":
+ currindex = self["list"].getIndex()
+ self["list"].moveSelection("moveDown")
+ self["list"].list.insert(self["list"].getIndex(), self["list"].list.pop(currindex))
+
+ def key_red(self):
+ logger.info("...")
+ self.close(self.channel_list_org)
+
+ def key_green(self):
+ logger.info("...")
+ if self.listtype == "blue":
+ channel_list = []
+ bouquet_channel_list = self["list"].getList()
+ for list_element in bouquet_channel_list:
+ channel_list.append(list_element[5])
+ write_channel_list(self.bouquet, channel_list)
+ logger.debug("channel_list: %s", channel_list)
+ self.close(channel_list)
+
+ def key_yellow(self):
+
+ def channels_file_name(bouquet):
+ return resolveFilename(SCOPE_CONFIG, "tvspielfilm_%s_channels.json" % bouquet)
+
+ logger.info("...")
+ self.listtype = "yellow"
+ self.setTitle(self["key_yellow"].text)
+ self["key_green"].text = ""
+ self["actionsmove"].setEnabled(False)
+ tvbouquets = getTVBouquets()
+ mylist = []
+ allname = self.cleanname("Alle Sender (Enigma)")
+ filenameall = channels_file_name(allname)
+ mylist.append(["Alle Sender (Enigma)", "", service_types_tv, allname, filenameall, "eall"])
+ for bouquet in tvbouquets:
+ name = self.cleanname(bouquet[1])
+ filename = channels_file_name(name)
+
+ mylist.append([bouquet[1], "", bouquet[0], name, filename, "bouq"])
+ for myx in self.mytitlestr:
+ self[myx].hide()
+ self["list"].style = "default"
+ self["list"].setList(mylist)
+ title = "%s %s - %s: %s" % (TVS, _("Channel Management"), _("TV Bouquets"), self["list"].count())
+ self.setTitle(title)
+ self["message"].setText(_("Press OK for channel list"))
+
+ def key_blue(self):
+ logger.info("...")
+ self["actionsmove"].setEnabled(False)
+ self.listtype = "blue"
+ self.setTitle(self["key_blue"].text)
+ self["key_green"].text = _("Save")
+ for myx in self.mytitlestr:
+ self[myx].show()
+ self["mytitle5"].text = _("name difference")
+ self["list"].style = "channel_bouquet"
+ self.bouquet_list = self.createBouquetList(self.channel_list, self.channel_dict)
+ self["list"].updateList(self.bouquet_list)
+
+ title = "%s %s - %s: %s" % (TVS, _("Channel Management"), _("Bouquet"), self.bouquet)
+ self.setTitle(title)
+ self["message"].setText(_("Press OK to enable/disable move function or Menu for more options"))
+
+ def showMenu(self):
+ logger.info("...")
+ self["actionsmove"].setEnabled(False)
+ selection = 0
+ options = []
+ mytitle = _("Select")
+ curr = self["list"].getCurrent()
+ if self.listtype == "blue":
+ if curr:
+ options.append((_("Delete channel"), "delcurr"))
+ if self.bouquet_list:
+ options.append((_("Delete all channels"), "delall"))
+ options.append((_("Zap"), "zap"))
+ mytitle = _("Bouquet")
+ elif self.listtype == "yellow2":
+ if curr:
+ options.append((_("Add channel"), "addcurr"))
+ options.append((_("Add all channels"), "addall"))
+ mytitle = _("Channels (TV)")
+ if options:
+ self.session.openWithCallback(
+ self.menuCallback,
+ ChoiceBox,
+ title=mytitle,
+ list=options,
+ selection=selection
+ )
+
+ def menuCallback(self, answer):
+ logger.info("...")
+ answer = answer and answer[1]
+ curr = self["list"].getCurrent()
+ if curr:
+ if answer == "delcurr":
+ self.channel_list.remove(curr[5])
+ self["list"].deleteEntry()
+ self.key_blue()
+ elif answer == "delall":
+ self.channel_list = []
+ self.key_blue()
+ elif answer == "addcurr":
+ if self.addTVChannel(curr):
+ self.key_blue()
+ elif answer == "addall":
+ self.channel_list = []
+ for row in self["list"].getList():
+ self.addTVChannel(row)
+ logger.debug("addall: channel_list: %s", self.channel_list)
+ self.key_blue()
+ elif answer == "zap":
+ Zap_Service(curr[3])
+
+ def addTVChannel(self, curr):
+ name = curr[0]
+ service = curr[1]
+ channel_name = getChannel(service, self.channel_dict)
+ if channel_name:
+ self.channel_list.append(channel_name)
+ else:
+ logger.error("service not found: %s: %s", name, service)
+ return True
+
+ def key_ok(self):
+ logger.info("...")
+ curr = self["list"].getCurrent()
+ if self.listtype == "yellow":
+ if curr:
+ self.showBouquetChannels(curr)
+ elif self.listtype == "yellow2":
+ self.addTVChannel(curr)
+ elif self.listtype == "blue":
+ if curr:
+ if self["actionsmove"].enabled is False:
+ self["actionsmove"].setEnabled(True)
+ title = "%s %s - %s: %s - %s" % (TVS, _("Channel Management"), _("Bouquet"), self.bouquet, _("Move mode enabled"))
+ else:
+ self["actionsmove"].setEnabled(False)
+ title = "%s %s - %s: %s" % (TVS, _("Channel Management"), _("Bouquet"), self.bouquet)
+ self.setTitle(title)
+
+ def showBouquetChannels(self, curr):
+ logger.info("...")
+ if curr:
+ servicetypes = curr[2] + " ORDER BY name"
+ service_list = getServiceList(servicetypes)
+ logger.debug("service_list: %s", service_list)
+ if service_list:
+ mylist = []
+ for service, ename in service_list:
+ if "::" not in service:
+ mylist.append((ename, service, ""))
+ self.listtype = "yellow2"
+ self["actionsmove"].setEnabled(False)
+ for myx in self.mytitlestr:
+ self[myx].hide()
+ self["list"].style = "default"
+ self["list"].setList(mylist)
+ title = "%s %s - %s: %s" % (TVS, _("Channel Management"), _("TV Bouquet Channels"), self["list"].count())
+ self.setTitle(title)
+ self["message"].setText(_("Press OK to add channel, or Menu for more options"))
+
+ def cleanname(self, msg):
+ logger.info("...")
+ p = re.compile("[^a-zA-Z0-9]")
+ return p.sub("_", msg).replace(" ", "")
+
+ def createSummary(self):
+ logger.info("...")
+ return SimpleSummary
diff --git a/src/ChannelUtils.py b/src/ChannelUtils.py
new file mode 100755
index 0000000..0a4d444
--- /dev/null
+++ b/src/ChannelUtils.py
@@ -0,0 +1,98 @@
+# !/usr/bin/python
+# coding=utf-8
+#
+# Copyright (C) 2018-2024 by dream-alpha
+#
+# In case of reuse of this source code please do not remove this copyright.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# For more information on the GNU General Public License see:
+# .
+
+
+import os
+import json
+from six import text_type
+from Tools.Directories import resolveFilename, SCOPE_CONFIG, pathExists
+from .ConfigInit import plugindir
+from .Debug import logger
+
+
+def convert_unicode_to_str(input_data):
+ if isinstance(input_data, dict):
+ return {convert_unicode_to_str(key): convert_unicode_to_str(value) for key, value in input_data.iteritems()}
+ if isinstance(input_data, list):
+ return [convert_unicode_to_str(element) for element in input_data]
+ if isinstance(input_data, text_type):
+ return input_data.encode("utf-8")
+ return input_data
+
+
+def read_channel_list(bouquet="default"):
+ logger.info("bouquet: %s", bouquet)
+ filename = ""
+ channel_list = []
+ channel_list_filename = "tvspielfilm_channel_list_%s.json" % bouquet
+ path = os.path.join(resolveFilename(SCOPE_CONFIG), channel_list_filename)
+ if pathExists(path):
+ filename = path
+ else:
+ path = os.path.join(plugindir, channel_list_filename)
+ if pathExists(path):
+ filename = path
+ logger.debug("filename: %s", filename)
+ if filename:
+ with open(filename) as data_file:
+ channel_list = convert_unicode_to_str(json.load(data_file))
+ logger.debug("channel_list: %s", channel_list)
+ return channel_list
+
+
+def write_channel_list(bouquet, channel_list):
+ logger.info("bouquet: %s", bouquet)
+ channel_list_filename = "tvspielfilm_channel_list_%s.json" % bouquet
+ path = os.path.join(resolveFilename(SCOPE_CONFIG), channel_list_filename)
+ with open(path, "w") as afile:
+ json.dump(channel_list, afile, indent=2)
+
+
+def read_channel_dict():
+ logger.info("...")
+ filename = ""
+ channel_dict = {}
+ channel_dict_filename = "tvspielfilm_channel_dict_default.json"
+ path = os.path.join(resolveFilename(SCOPE_CONFIG), channel_dict_filename)
+ if pathExists(path):
+ filename = path
+ else:
+ path = os.path.join(plugindir, channel_dict_filename)
+ if pathExists(path):
+ filename = path
+ logger.debug("filename: %s", filename)
+ if filename:
+ with open(filename) as data_file:
+ channel_dict = convert_unicode_to_str(json.load(data_file))
+ logger.debug("channel_dict: %s", channel_dict)
+ return channel_dict
+
+
+def getChannel(service, channel_dict):
+ logger.info("service: %s", service)
+ for channel_name, channel in channel_dict.iteritems():
+ # logger.debug("channel_name: %s, channel: %s", channel_name, channel)
+ if channel["service"] == service:
+ logger.debug("found: %s", channel_name)
+ break
+ else:
+ channel_name = ""
+ logger.debug("channel_name: %s", channel_name)
+ return channel_name
diff --git a/src/ConfigInit.py b/src/ConfigInit.py
new file mode 100755
index 0000000..5606a4a
--- /dev/null
+++ b/src/ConfigInit.py
@@ -0,0 +1,45 @@
+# !/usr/bin/python
+# coding=utf-8
+#
+# Copyright (C) 2018-2024 by dream-alpha
+#
+# In case of reuse of this source code please do not remove this copyright.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# For more information on the GNU General Public License see:
+# .
+
+from Components.config import config, ConfigSelection, ConfigYesNo, ConfigSubsection, ConfigNothing, NoSave
+from Tools.Directories import resolveFilename, SCOPE_PLUGINS
+from .Debug import logger, log_levels, initLogging
+from .__init__ import _
+
+
+plugindir = resolveFilename(SCOPE_PLUGINS, "Extensions/TVMagazineCockpit/")
+bouquet_choices = [
+ ("default", _("Default")),
+ ("favorites", _("Favorites")),
+ ("sky", _("Sky")),
+ ("all", _("All")),
+]
+
+
+class ConfigInit():
+
+ def __init__(self):
+ logger.info("...")
+ config.plugins.tvmagazinecockpit = ConfigSubsection()
+ config.plugins.tvmagazinecockpit.fake_entry = NoSave(ConfigNothing())
+ config.plugins.tvmagazinecockpit.debug_log_level = ConfigSelection(default="DEBUG", choices=list(log_levels.keys()))
+ config.plugins.tvmagazinecockpit.use_picons = ConfigYesNo(default=True)
+ config.plugins.tvmagazinecockpit.bouquet = ConfigSelection(default="default", choices=bouquet_choices)
+ initLogging()
diff --git a/src/ConfigScreen.py b/src/ConfigScreen.py
new file mode 100644
index 0000000..6946613
--- /dev/null
+++ b/src/ConfigScreen.py
@@ -0,0 +1,295 @@
+#!/usr/bin/python
+# coding=utf-8
+#
+# Copyright (C) 2018-2024 by dream-alpha
+#
+# In case of reuse of this source code please do not remove this copyright.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# For more information on the GNU General Public License see:
+# .
+
+
+import os
+from Components.ConfigList import ConfigListScreen
+from Components.config import config, configfile, getConfigListEntry, ConfigText, ConfigPassword
+from Components.Button import Button
+from Components.Sources.StaticText import StaticText
+from Components.ActionMap import ActionMap
+from Screens.Screen import Screen
+from Screens.LocationBox import LocationBox
+from Screens.MessageBox import MessageBox
+from Screens.VirtualKeyBoard import VirtualKeyBoard
+from Screens.Standby import TryQuitMainloop
+from enigma import eTimer, ePoint
+from .__init__ import _
+from .Version import PLUGIN
+from .Debug import logger, log_levels, setLogLevel
+from .SkinUtils import getSkinName
+from .ConfigScreenInit import ConfigScreenInit
+
+
+class ConfigScreen(ConfigScreenInit, ConfigListScreen, Screen):
+
+ def __init__(self, session, config_plugins_plugin):
+ self.config_plugins_plugin = config_plugins_plugin
+ Screen.__init__(self, session)
+ self.skinName = getSkinName("ConfigScreen")
+ ConfigScreenInit.__init__(self, session)
+
+ self["actions"] = ActionMap(
+ ["ColorActions", "SetupActions"],
+ {
+ "cancel": self.keyCancel,
+ "red": self.keyCancel,
+ "save": self.keySaveNew,
+ "yellow": self.loadDefaultSettings,
+ "next_section": self.bouquetPlus,
+ "previous_section": self.bouquetMinus,
+ },
+ -2 # higher priority
+ )
+
+ self["VirtualKB"] = ActionMap(
+ ["VirtualKeyboardActions"],
+ {
+ "showVirtualKeyboard": self.keyText,
+ },
+ -2 # higher priority
+ )
+
+ self["VirtualKB"].setEnabled(False)
+
+ self["key_red"] = Button(_("Cancel"))
+ self["key_green"] = Button(_("Save"))
+ self["key_yellow"] = Button(_("Defaults"))
+ self["key_blue"] = Button()
+ self["help"] = StaticText()
+
+ self.list = []
+ ConfigListScreen.__init__(self, self.list, session=self.session, on_change=self.changedEntry)
+ self.needs_restart = False
+
+ self.reload_timer = eTimer()
+ self.reload_timer_conn = self.reload_timer.timeout.connect(self.createConfig)
+
+ self["config"].selectionChanged = self.selectionChanged
+ self["config"].onSelectionChanged.append(self.updateHelp)
+ # self["config"].onSelectionChanged.append(self.handleInputHelpers)
+
+ self.setTitle(PLUGIN + " " + _("Setup"))
+ self.createConfig()
+
+ def selectionChanged(self):
+ current = self["config"].getCurrent()
+ if current and len(current) > 1:
+ if self["config"].current != current:
+ if self["config"].current:
+ self["config"].current[1].onDeselect(self.session)
+ if current:
+ current[1].onSelect(self.session)
+ self["config"].current = current
+ for x in self["config"].onSelectionChanged:
+ if x:
+ x()
+
+ def handleInputHelpers(self):
+ self["VirtualKB"].setEnabled(False)
+ if self["config"].getCurrent():
+ if isinstance(self['config'].getCurrent()[1], (ConfigPassword, ConfigText)):
+ self["VirtualKB"].setEnabled(True)
+ if hasattr(self, "HelpWindow"):
+ if self["config"].getCurrent()[1].help_window.instance:
+ helpwindowpos = self["HelpWindow"].getPosition()
+ self["config"].getCurrent()[1].help_window.instance.move(ePoint(helpwindowpos[0], helpwindowpos[1]))
+
+ def keyText(self):
+ self.session.openWithCallback(self.VirtualKeyBoardCallback, VirtualKeyBoard, title=self["config"].getCurrent()[0], text=self["config"].getCurrent()[1].getValue())
+
+ def VirtualKeyBoardCallback(self, callback=None):
+ if callback:
+ self["config"].getCurrent()[1].setValue(callback)
+ self["config"].invalidate(self["config"].getCurrent())
+
+ def cancelConfirm(self, answer):
+ if answer:
+ for x in self["config"].list:
+ if len(x) > 1:
+ x[1].cancel()
+ self.close()
+
+ def keyCancel(self):
+ if self["config"].isChanged():
+ self.session.openWithCallback(self.cancelConfirm, MessageBox, _("Really close without saving settings?"))
+ else:
+ self.close()
+
+ def bouquetPlus(self):
+ self["config"].jumpToPreviousSection()
+
+ def bouquetMinus(self):
+ self["config"].jumpToNextSection()
+
+ def createConfig(self):
+ logger.debug("len(self.config_list): %s", len(self.config_list))
+ self.list = []
+ for i, conf in enumerate(self.config_list):
+ # 0 entry text
+ # 1 variable
+ # 2 validation
+ # 3 pressed ok
+ # 4 setup level
+ # 5 parent entries
+ # 6 help text
+ # config item must be valid for current usage setup level
+ if config.usage.setup_level.index >= conf[4]:
+ # parent entries must be true
+ for parent in conf[5]:
+ if parent < 0:
+ if not self.config_list[i + parent][1].value:
+ break
+ elif parent > 0:
+ if self.config_list[i - parent][1].value:
+ break
+ else:
+ # loop fell through without a break
+ if conf[0] == self.section:
+ if len(self.list) > 1:
+ self.list.append(getConfigListEntry("", self.config_plugins_plugin.fake_entry, None, None, 0, [], ""))
+ if conf[1] == "":
+ self.list.append(getConfigListEntry("",))
+ else:
+ self.list.append(getConfigListEntry(conf[1],))
+ else:
+ self.list.append(getConfigListEntry(conf[0], conf[1], conf[2], conf[3], conf[4], conf[5], conf[6]))
+ self["config"].setList(self.list)
+
+ def loadDefaultSettings(self):
+ self.session.openWithCallback(
+ self.loadDefaultSettingsCallback,
+ MessageBox,
+ _("Loading default settings will overwrite all settings, really load them?"),
+ MessageBox.TYPE_YESNO
+ )
+
+ def loadDefaultSettingsCallback(self, answer):
+ if answer:
+ for conf in self.config_list:
+ if conf[0] != self.section:
+ conf[1].value = conf[1].default
+ self.createConfig()
+
+ def changedEntry(self, _addNotifier=None):
+ if self.reload_timer.isActive():
+ self.reload_timer.stop()
+ self.reload_timer.start(50, True)
+
+ def updateHelp(self):
+ cur = self["config"].getCurrent()
+ self["help"].text = (cur[6] if cur else '')
+
+ def dirSelected(self, adir):
+ if adir:
+ adir = os.path.normpath(adir)
+ if self["config"].getCurrent()[2]:
+ if self["config"].getCurrent()[2](adir):
+ self["config"].getCurrent()[1].value = adir
+
+ def keyOK(self):
+ logger.debug("...")
+ current = self["config"].getCurrent()
+ if current and current[3]:
+ current[3](current[1])
+
+ def reloadConfig(self):
+ logger.debug("...")
+ ConfigScreenInit.__init__(self, self.session)
+ self.changedEntry()
+
+ def keySaveNew(self):
+ logger.debug("...")
+ save_value = True
+ for i, conf in enumerate(self.config_list):
+ # logger.debug("i: %s, conf[0]: %s", i, conf[0])
+ if conf[0] != self.section:
+ if conf[1].isChanged():
+ # logger.debug("i: %s, conf[0]: %s isChanged", i, conf[0])
+ if conf[2]:
+ # execute value changed function
+ # logger.debug("execute value changed function")
+ if not conf[2](conf[1]):
+ logger.error("value function error: %s", conf[0])
+ save_value = False
+ # Check parent entries
+ for parent in conf[5]:
+ # logger.debug("parent: %s, conf[5]: %s", str(parent), str(conf[5]))
+ if self.config_list[i + parent][2]:
+ # execute parent value changed function
+ # logger.debug("execute parent value changed function")
+ if not self.config_list[i + parent][2](self.config_list[i + parent][1]):
+ logger.error("parent value function error: %s", self.config_list[i + parent][2])
+ if save_value:
+ logger.debug("saving: %s", conf[0])
+ conf[1].save()
+ configfile.save()
+ if not save_value:
+ self.createConfig()
+ else:
+ if self.needs_restart:
+ self.restartGUI()
+ else:
+ self.close(True)
+
+ def restartGUI(self):
+ self.session.openWithCallback(self.restartGUIConfirmed, MessageBox, _("Some changes require a GUI restart") + "\n" + _("Restart GUI now?"), MessageBox.TYPE_YESNO)
+
+ def restartGUIConfirmed(self, answer):
+ if answer:
+ self.session.open(TryQuitMainloop, 3)
+ else:
+ self.close(True)
+
+ def setLogLevel(self, element):
+ logger.debug("element: %s", element.value)
+ setLogLevel(log_levels[element.value])
+ return True
+
+ def needsRestart(self, _element=None):
+ logger.info("...")
+ self.needs_restart = True
+ return True
+
+ def openLocationBox(self, element):
+ if element:
+ path = os.path.normpath(element.value)
+ self.session.openWithCallback(
+ self.dirSelected,
+ LocationBox,
+ windowTitle=_("Bookmarks"),
+ text=_("Select directory"),
+ currDir=path + "/",
+ bookmarks=self.config_plugins_plugin.bookmarks,
+ autoAdd=False,
+ editDir=True,
+ inhibitDirs=["/bin", "/boot", "/dev", "/etc", "/lib", "/proc", "/sbin", "/sys", "/var"],
+ minFree=None
+ )
+
+ def validatePath(self, element):
+ if isinstance(element, str):
+ adir = os.path.normpath(element)
+ else:
+ adir = os.path.normpath(element.value)
+ valid = os.path.exists(adir)
+ if not valid:
+ self.session.open(MessageBox, _("Path does not exist") + ": " + adir, MessageBox.TYPE_ERROR)
+ return valid
diff --git a/src/ConfigScreenInit.py b/src/ConfigScreenInit.py
new file mode 100644
index 0000000..4729c7a
--- /dev/null
+++ b/src/ConfigScreenInit.py
@@ -0,0 +1,69 @@
+#!/usr/bin/python
+# coding=utf-8
+#
+# Copyright (C) 2018-2024 by dream-alpha
+#
+# In case of reuse of this source code please do not remove this copyright.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# For more information on the GNU General Public License see:
+# .
+
+
+from Components.config import config
+from .Debug import logger
+from .__init__ import _
+
+
+class ConfigScreenInit():
+ def __init__(self, session):
+ self.session = session
+ self.section = 400 * "¯"
+
+ # config list entry
+ # , config element
+ # , , function called on save
+ # , , , function called if user has pressed OK
+ # , , , , usage setup level from E2
+ # , , , , 0: simple+
+ # , , , , 1: intermediate+
+ # , , , , 2: expert+
+ # , , , , , depends on relative parent entries
+ # , , , , , parent config value < 0 = true
+ # , , , , , parent config value > 0 = false
+ # , , , , , , context sensitive help text
+ # , , , , , ,
+ # 0 , 1 , 2 , 3 , 4 , 5 , 6
+ self.config_list = [
+ (self.section , _("COCKPIT") , None , None , 0 , [] , ""),
+ (_("Default bouquet") , config.plugins.tvmagazinecockpit.bouquet , None , None , 0 , [] , _("Select the default bouquet.")),
+ (_("Picon directory") , config.usage.configselection_piconspath , self.validatePath , None , 0 , [] , _("Select the directory the picons are stored in.")),
+ (_("Use picons") , config.plugins.tvmagazinecockpit.use_picons , None , None , 0 , [] , _("Should channel picons be used instead of channel logos?")),
+ (self.section , _("DEBUG") , None , None , 2 , [] , ""),
+ (_("Log level") , config.plugins.piconcockpit.debug_log_level , self.setLogLevel , None , 2 , [] , _("Select the debug log level.")),
+ ]
+
+ @staticmethod
+ def save(_conf):
+ logger.debug("...")
+
+ def openLocationBox(self, element):
+ logger.debug("element: %s", element.value)
+ return True
+
+ def setLogLevel(self, element):
+ logger.debug("element: %s", element.value)
+ return True
+
+ def validatePath(self, element):
+ logger.debug("element: %s", element.value)
+ return True
diff --git a/src/Constants.py b/src/Constants.py
new file mode 100644
index 0000000..4fd4cf1
--- /dev/null
+++ b/src/Constants.py
@@ -0,0 +1,71 @@
+# !/usr/bin/python
+# coding=utf-8
+#
+# Copyright (C) 2018-2024 by dream-alpha
+#
+# In case of reuse of this source code please do not remove this copyright.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# For more information on the GNU General Public License see:
+# .
+
+
+from __init__ import _
+
+TMP_DIR = "tmp/TVC"
+TVS = "TV Spielfilm"
+BOUQUETS = {"default": _("default"), "favorites": _("favorites"), "sky": _("sky"), "all": _("all")}
+
+EVENT_IDX_TIME_START = 0
+EVENT_IDX_VIDEOS = 1
+EVENT_IDX_IS_NEW = 2
+EVENT_IDX_TEXT = 3
+EVENT_IDX_GENRE = 4
+EVENT_IDX_YEAR = 5
+EVENT_IDX_IMAGES = 6
+EVENT_IDX_CURRENT_TOPICS = 7
+EVENT_IDX_ID = 8
+EVENT_IDX_TITLE = 9
+EVENT_IDX_EPISODE_TITLE = 10
+EVENT_IDX_SUBLINE = 11
+EVENT_IDX_TIME_END = 12
+EVENT_IDX_REPEAT = 13
+EVENT_IDX_BROADCASTER_ID = 14
+EVENT_IDX_BROADCASTER_NAME = 15
+EVENT_IDX_IS_TIP_OF_THE_DAY = 16
+EVENT_IDX_IS_TOP_TIP = 17
+EVENT_IDX_ANCHOR_MAN = 18
+EVENT_IDX_THUMB_ID_NUMERIC = 19
+EVENT_LENGTH = 20
+
+EVENT_KEYS = [
+ "timestart",
+ "videos",
+ "isNew",
+ "text",
+ "genre",
+ "year",
+ "images",
+ "currentTopics",
+ "id",
+ "title",
+ "episodeTitle",
+ "subline",
+ "timeend",
+ "repeatHint",
+ "broadcasterId",
+ "broadcasterName",
+ "isTipOfTheDay",
+ "isTopTip",
+ "anchorMan",
+ "thumbIdNumeric"
+]
diff --git a/src/Debug.py b/src/Debug.py
new file mode 100644
index 0000000..fbcfb9e
--- /dev/null
+++ b/src/Debug.py
@@ -0,0 +1,53 @@
+#!/usr/bin/python
+# coding=utf-8
+#
+# Copyright (C) 2018-2024 by dream-alpha
+#
+# In case of reuse of this source code please do not remove this copyright.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# For more information on the GNU General Public License see:
+# .
+
+
+import sys
+import logging
+from Components.config import config, ConfigSubsection, ConfigDirectory, ConfigSelection # noqa: F401, pylint: disable=W0611
+from .Version import ID, PLUGIN
+
+
+logger = None
+streamer = None
+format_string = (ID + ": " + "%(levelname)s: %(filename)s: %(funcName)s: %(message)s")
+log_levels = {"ERROR": logging.ERROR, "INFO": logging.INFO, "DEBUG": logging.DEBUG}
+plugin = PLUGIN.lower()
+exec("config.plugins." + plugin + " = ConfigSubsection()") # noqa: F401, pylint: disable=W0122
+exec("config.plugins." + plugin + ".debug_log_level = ConfigSelection(default='INFO', choices=log_levels.keys())") # noqa: F401, pylint: disable=W0122
+
+
+def initLogging():
+ global logger
+ global streamer
+ if not logger:
+ logger = logging.getLogger(ID)
+ formatter = logging.Formatter(format_string)
+ streamer = logging.StreamHandler(sys.stdout)
+ streamer.setFormatter(formatter)
+ logger.addHandler(streamer)
+ logger.propagate = False
+ setLogLevel(log_levels[eval("config.plugins." + plugin + ".debug_log_level").value])
+
+
+def setLogLevel(level):
+ logger.setLevel(level)
+ streamer.setLevel(level)
+ logger.info("level: %s", level)
diff --git a/src/Downloader.py b/src/Downloader.py
new file mode 100755
index 0000000..8c5be49
--- /dev/null
+++ b/src/Downloader.py
@@ -0,0 +1,407 @@
+# !/usr/bin/python
+# coding=utf-8
+#
+# Copyright (C) 2018-2024 by dream-alpha
+#
+# In case of reuse of this source code please do not remove this copyright.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# For more information on the GNU General Public License see:
+# .
+
+# pylint: disable=W1113, W0212, W0221, W0222
+
+
+import json
+from cookielib import CookieJar
+from twisted.internet import reactor
+from twisted.web.http_headers import Headers
+from twisted.internet.task import deferLater
+from twisted.web.client import Agent, RedirectAgent, _GzipProtocol, CookieAgent, BrowserLikePolicyForHTTPS, HTTPConnectionPool, _requireSSL, PartialDownloadError
+from twisted.internet.protocol import Protocol
+from twisted.internet.defer import Deferred, DeferredSemaphore, succeed
+from twisted.web.iweb import IBodyProducer
+from twisted.internet.ssl import ClientContextFactory as ssl_ClientContextFactory, CertificateOptions, AcceptableCiphers
+from twisted.internet._sslverify import ClientTLSOptions, verifyHostname, VerificationError
+from twisted.web._newclient import ResponseDone, ResponseFailed, PotentialDataLoss
+from twisted.python.failure import Failure
+from twisted.internet.error import CertificateError
+from twisted.web import http
+from zope.interface import implementer
+from OpenSSL import SSL as _SSL
+from API import session as mysession
+from .__init__ import _
+from .Debug import logger
+
+
+_headers = Headers({"User-Agent": ["Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36"]})
+_headers.addRawHeader("content-type", "text/html; charset=UTF-8")
+_headers.addRawHeader("Accept-Language", "de, de-DE;q=0.9, en;q=0.8, en-GB;q=0.7, en-US;q=0.6")
+_headers.addRawHeader("Accept-Charset", "utf-8, iso-8859-1;q=0.5")
+_headers.addRawHeader("Accept", "text/html, application/xhtml+xml, application/xml;q=0.9, image/webp, */*;q=0.8")
+_headers.addRawHeader("Cache-Control", "public, max-age=86400, max-stale=86400")
+_headers.addRawHeader("Sec-CH-UA", 'Google Chrome";v="107", "Chromium";v="107", "Not=A?Brand";v="24')
+_headers.addRawHeader("SEC-CH-UA-FULL-VERSION", "107.0.5304.88")
+_headers.addRawHeader("Sec-CH-UA-Mobile", "?0")
+_headers.addRawHeader("Sec-CH-UA-Platform", "Windows")
+_headers.addRawHeader("Sec-CH-UA-Platform-Version", "10.0.0")
+_headers.addRawHeader("Sec-CH-UA-Model", "")
+_headers.addRawHeader("SEC-CH-UA-ARCH", "x86")
+_headers.addRawHeader("Sec-CH-UA-Bitness", "64")
+_headers.addRawHeader("DNT", "1")
+_headers.addRawHeader("Connection", "keep-alive")
+headers_gzip = _headers.copy()
+headers_gzip.addRawHeader("Accept-Encoding", "gzip, deflate")
+headersplain = _headers.copy()
+headersplain.setRawHeaders("content-type", ["text/plain; charset=UTF-8"])
+headers_ts = Headers({"User-Agent": ["GStreamer souphttpsrc libsoup/2.52.2"]})
+headers_ts.setRawHeaders("content-type", ["application/x-mpegURL"])
+headers_dash = _headers.copy()
+headers_dash.setRawHeaders("content-type", ["application/dash+xml"])
+_headers_jpeg = _headers.copy()
+_headers_jpeg.setRawHeaders("content-type", ["image/jpeg"])
+_headers_svg = _headers.copy()
+_headers_svg.setRawHeaders("content-type", ["image/svg+xml"])
+_headers_json = _headers.copy()
+_headers_json.setRawHeaders("content-type", ["application/json; charset=utf-8"])
+
+
+_downloads = dict()
+_downloads["state"] = True
+
+
+def MyCallLater(ltime, iscallable, *args, **kwargs):
+ logger.info("...")
+ return reactor.callLater(ltime, iscallable, *args, **kwargs)
+
+
+class CallLater:
+ def __init__(self, result, iscallable, *args, **kwargs):
+ logger.info("...")
+ reactor.callLater(0, iscallable, result, *args, **kwargs)
+
+ def __del__(self):
+ logger.info("...")
+
+
+class MyDeferredSemaphore:
+ def __init__(self, tokens=1):
+ logger.info("...")
+ self.ds = DeferredSemaphore(tokens=tokens)
+ self._deferreds = []
+ self.work = dict()
+ _downloads["state"] = True
+
+ def run(self, *args, **kwargs):
+ logger.info("...")
+ return self.ds.run(*args, **kwargs)
+
+ def rundeferLater(self, ltime=0.0, *args, **kwargs):
+ logger.info("...")
+ return deferLater(reactor, ltime, self.ds.run, *args, **kwargs)
+
+ def start(self, *args, **kwargs):
+ logger.info("...")
+ return self.rundeferLater(0.0, *args, **kwargs)
+
+ def deferCanceler(self, _cancel=True):
+ logger.info("...")
+ for items in self.ds.waiting:
+ items.cancel()
+
+ def settokens(self, tokens=10):
+ logger.info("...")
+ self.ds.tokens = tokens
+ self.ds.limit = tokens
+
+ def finished(self):
+ logger.info("...")
+ return self.ds.tokens >= self.ds.limit
+
+ def __del__(self):
+ logger.info("...")
+ self.deferCanceler()
+ self.work.clear()
+
+
+class _MyClientTLSOptions(ClientTLSOptions):
+ def _identityVerifyingInfoCallback(self, connection, where, _ret):
+ logger.info("...")
+ if where & _SSL.SSL_CB_HANDSHAKE_START:
+ connection.set_tlsext_host_name(self._hostnameBytes)
+ elif where & _SSL.SSL_CB_HANDSHAKE_DONE:
+ try:
+ verifyHostname(connection, self._hostnameASCII)
+ except (CertificateError, VerificationError) as e:
+ logger.debug("Remote certificate is not valid for hostname %s; %s", self._hostnameASCII, e)
+ except ValueError as e:
+ logger.debug("Ignoring error while verifying certificate from host %s (exception: %s)", self._hostnameASCII, repr(e))
+
+
+try:
+ MyClientTLSOptions = ClientTLSOptions
+except Exception:
+ MyClientTLSOptions = _MyClientTLSOptions
+
+
+class ClientContextFactory(ssl_ClientContextFactory):
+ def __init__(self):
+ logger.info("...")
+ self.method = _SSL.SSLv23_METHOD
+
+ def getContext(self, hostname=None, _port=None):
+ logger.info("...")
+ ctx = self._contextFactory(self.method)
+ ctx.set_options(_SSL.OP_SINGLE_DH_USE | _SSL.OP_NO_SSLv2 | _SSL.OP_NO_SSLv3 | _SSL.OP_ALL)
+ ctx.set_session_cache_mode(_SSL.SESS_CACHE_BOTH)
+ if hostname:
+ MyClientTLSOptions(hostname, ctx)
+ return ctx
+
+
+defaultCiphers = AcceptableCiphers.fromOpenSSLCipherString(
+ "TLS13-AES-256-GCM-SHA384:TLS13-CHACHA20-POLY1305-SHA256:"
+ "TLS13-AES-128-GCM-SHA256:"
+ "ECDH+AESGCM:ECDH+CHACHA20:DH+AESGCM:DH+CHACHA20:ECDH+AES256:DH+AES256:"
+ "ECDH+AES128:DH+AES:RSA+AESGCM:RSA+AES:"
+ "!aNULL:!MD5:!DSS")
+
+
+class ClientContextFactory__(BrowserLikePolicyForHTTPS):
+
+ def _getCertificateOptions(self, _hostname, _port):
+ logger.info("...")
+ return CertificateOptions(verify=False, method=_SSL.SSLv23_METHOD, fixBrokenPeers=True, acceptableCiphers=defaultCiphers, )
+
+ @_requireSSL
+ def getContext(self, hostname=None, port=None):
+ logger.info("...")
+ return self._getCertificateOptions(hostname, port).getContext()
+
+ @_requireSSL
+ def creatorForNetloc(self, hostname, port):
+ logger.info("...")
+ return MyClientTLSOptions(hostname.decode("ascii"), self.getContext(hostname, port))
+
+
+class MyRedirectAgent(RedirectAgent):
+ _redirectResponses = [http.MOVED_PERMANENTLY, http.FOUND]
+ _seeOtherResponses = [http.SEE_OTHER]
+
+
+class mydownloadWithProgress:
+ def __init__(self, url, fileOrName, headers=None, *args, **kwargs):
+ logger.info("...")
+ self.factory = getPagenew(url=url, fileOrName=fileOrName, headers=headers, *args, **kwargs)
+
+ def start(self):
+ logger.info("...")
+ return self.factory.deferred
+
+ def stop(self):
+ logger.info("...")
+ self.factory.deferred.cancel()
+
+ def addProgress(self, progress_callback):
+ logger.info("...")
+ self.factory.progress_callback = progress_callback
+
+
+def MydownloadPage(url, file=None, method="GET", headers=_headers, postdata=None, contextFactory=ClientContextFactory(), *args, **kwargs):
+ logger.info("...")
+ return getPagenew(url, file, method, headers, postdata, contextFactory, *args, **kwargs).deferred
+
+
+def MygetPage(url, fileOrName=None, method="GET", headers=_headers, postdata=None, contextFactory=ClientContextFactory(), *args, **kwargs):
+ logger.info("...")
+ return getPagenew(url, fileOrName, method, headers, postdata, contextFactory, *args, **kwargs).deferred
+
+
+@implementer(IBodyProducer)
+class StringProducer(object):
+ def __init__(self, body):
+ logger.info("...")
+ self.body = body
+ self.length = len(body)
+
+ def startProducing(self, consumer):
+ logger.info("...")
+ consumer.write(self.body)
+ return succeed(None)
+
+ def pauseProducing(self):
+ logger.info("...")
+
+ def stopProducing(self):
+ logger.info("...")
+
+
+class ReadBodyProtocol(Protocol):
+ def __init__(self, status, message, deferred):
+ logger.info("...")
+ self.deferred = deferred
+ self.status = status
+ self.message = message
+ self.dataBuffer = []
+
+ def dataReceived(self, data):
+ logger.info("...")
+ self.dataBuffer.append(data)
+
+ def connectionLost(self, reason):
+ logger.info("...")
+ if reason.check(ResponseDone):
+ self.deferred.callback(b"".join(self.dataBuffer))
+ elif reason.check(PotentialDataLoss):
+ self.deferred.errback(PartialDownloadError(self.status, self.message, b"".join(self.dataBuffer)))
+ else:
+ self.deferred.errback(reason)
+
+
+class ReadBodyURI(Protocol):
+ def __init__(self, deferred, response):
+ logger.info("...")
+ self.deferred = deferred
+ self._response = response
+ self.dataBuffer = []
+
+ def dataReceived(self, data):
+ logger.info("...")
+ self.dataBuffer.append(data)
+
+ def connectionLost(self, reason):
+ logger.info("...")
+ if reason.check(ResponseDone):
+ self.deferred.callback((b"".join(self.dataBuffer), self._response.request.absoluteURI))
+ elif reason.check(PotentialDataLoss):
+ self.deferred.errback(PartialDownloadError(self._response.code, self._response.phrase, b"".join(self.dataBuffer)))
+ else:
+ self.deferred.errback(reason)
+
+
+class ReadBody(Protocol):
+ def __init__(self, finished, response, fileOrName, progress_callback):
+ logger.info("...")
+ self.finished = finished
+ self._response = response
+ self.currentbytes = 0.0
+ self.progress_callback = progress_callback
+ self.datafile = None
+ if isinstance(fileOrName, str):
+ self.datafile = open(fileOrName, "wb")
+ else:
+ self.datafile = fileOrName
+
+ def dataReceived(self, data):
+ logger.info("...")
+ try:
+ if self.finished.called:
+ return
+ if self.datafile:
+ self.datafile.write(data)
+ self.currentbytes += len(data)
+ if self._response.length and self.progress_callback:
+ self.progress_callback(self.currentbytes, self._response.length)
+ except IOError:
+ self.finished.errback(Failure())
+
+ def connectionLost(self, reason):
+ logger.info("...")
+ if self.datafile:
+ try:
+ self.datafile.close()
+ except Exception:
+ self.finished.errback(Failure())
+
+ if reason.check(ResponseDone):
+ self.finished.callback(None)
+ elif reason.check(PotentialDataLoss):
+ self.finished.errback(Failure())
+ else:
+ self.finished.errback(reason)
+
+
+class getPagenew(object):
+ progress_callback = None
+
+ def __init__(self, url, fileOrName=None, method="GET", headers=None, postdata=None, contextFactory=ClientContextFactory(), location=None, timeout=10.0, cookies=None, *args, **kwargs):
+ logger.info("...")
+ body = None
+ if postdata:
+ body = StringProducer(postdata)
+ pool = HTTPConnectionPool(reactor, persistent=True)
+ pool.maxPersistentPerHost = 10
+ pool.cachedConnectionTimeout = 600
+ pool.retryAutomatically = True
+ pool._factory.noisy = False
+
+ agent = MyRedirectAgent(Agent(reactor, contextFactory=contextFactory, connectTimeout=timeout, bindAddress=None, pool=pool))
+ cookieJar = None
+ if cookies:
+ cookieJar = CookieJar()
+ agent = CookieAgent(agent, cookieJar)
+
+ self.deferred = agent.request(method=method, uri=url, headers=headers, bodyProducer=body)
+ self.deferred.addCallback(self.calresponse, fileOrName, location, cookieJar, *args, **kwargs)
+
+ def calresponse(self, response, fileOrName, location, cookieJar, *args, **kwargs):
+ def _cancel(_):
+ logger.info("...")
+ try:
+ response._transport._producer.abortConnection()
+ except Exception:
+ pass
+
+ logger.info("...")
+ finished = Deferred(canceller=_cancel)
+ if "CallbackResponse" in kwargs:
+ kwargs["CallbackResponse"](self, response, fileOrName, location, cookieJar, *args, **kwargs)
+ if response.code not in (200, 301, 302, 303):
+ raise ResponseFailed("{0} {1}".format(response.code, response.phrase), response)
+ gzipdecoder = "gzip" in response.headers.getRawHeaders("Content-Encoding", "none")
+
+ if not location and gzipdecoder:
+ response.deliverBody(_GzipProtocol(ReadBodyProtocol(response.code, response.phrase, finished), response))
+ elif fileOrName:
+ response.deliverBody(ReadBody(finished, response, fileOrName, self.progress_callback))
+ elif location:
+ if gzipdecoder:
+ response.deliverBody(_GzipProtocol(ReadBodyURI(finished, response), response))
+ else:
+ response.deliverBody(ReadBodyURI(finished, response))
+ else:
+ response.deliverBody(ReadBodyProtocol(response.code, response.phrase, finished))
+ return finished
+
+ def calerr(self, _err):
+ logger.info("...")
+
+
+def writerawheaders(response, *_args, **_kwargs):
+ logger.info("...")
+ with open("/tmp/rawheaders.json", "w") as fp:
+ json.dump(list(response.headers.getAllRawHeaders()), fp, encoding="utf-8", indent=2, sort_keys=True)
+
+
+def http_failed(failure_instance=None, *_args, **kwargs):
+ logger.info("...")
+ error_message = str(failure_instance.getErrorMessage())
+ if not error_message:
+ error_message = str(failure_instance)
+ text = _(kwargs.get("title", "Error")) + "\n"
+ text += _("Error during download") + "\n\n" + error_message + "\n"
+ logger.error("error_message: %s", error_message)
+ try:
+ if mysession:
+ mysession.toastManager.showToast(text, int(kwargs.get("duration", 20)))
+ except Exception as e:
+ logger.error("exception: %s", e)
diff --git a/src/EventDetails.py b/src/EventDetails.py
new file mode 100755
index 0000000..eff2415
--- /dev/null
+++ b/src/EventDetails.py
@@ -0,0 +1,153 @@
+# !/usr/bin/python
+# coding=utf-8
+#
+# Copyright (C) 2018-2024 by dream-alpha
+#
+# In case of reuse of this source code please do not remove this copyright.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# For more information on the GNU General Public License see:
+# .
+
+
+import os
+from time import strftime, localtime
+from Screens.Screen import Screen
+from Components.ActionMap import ActionMap
+from Components.Label import Label
+from Components.Pixmap import Pixmap
+from Components.ScrollLabel import ScrollLabel
+from Components.AVSwitch import AVSwitch
+from Tools.Directories import pathExists
+from Tools.LoadPixmap import LoadPixmap
+from Downloader import headers_gzip, MydownloadPage, MyDeferredSemaphore, http_failed
+from enigma import eServiceReference, ePicLoad
+from StreamPlayer import StreamPlayer
+from .Debug import logger
+from .Constants import TMP_DIR, TVS, EVENT_IDX_SUBLINE, EVENT_IDX_EPISODE_TITLE, EVENT_IDX_YEAR, EVENT_IDX_VIDEOS, EVENT_IDX_IMAGES, EVENT_IDX_TITLE, EVENT_IDX_TIME_START, EVENT_IDX_TIME_END, EVENT_IDX_TEXT
+from .PictureUtils import getPicon, getVideo, getEventPicUrl
+from .__init__ import _
+
+
+class EventDetails(Screen):
+ def __init__(self, session, channel, list_event):
+ logger.info("...")
+ self.list_event = list_event
+ self.channel = channel
+ Screen.__init__(self, session)
+ self.skinName = "EventDetails"
+ self["description"] = ScrollLabel()
+ self["actions"] = ActionMap(
+ ["TVC_Actions"],
+ {
+ "ok": self.key_ok,
+ "cancel": self.close,
+ "up": self["description"].pageUp,
+ "left": self["description"].pageUp,
+ "down": self["description"].pageDown,
+ "right": self["description"].pageDown
+ }
+ )
+ self["programpix"] = Pixmap()
+ self["videopix"] = Pixmap()
+ self["channelpix"] = Pixmap()
+ self["daumenpix"] = Pixmap()
+
+ self["title"] = Label()
+ self["episodetitle"] = Label()
+ self["timeduration"] = Label()
+
+ self.picload = ePicLoad()
+ self.picload_conn = self.picload.PictureData.connect(self.__finish_decode)
+ self.deferreds = []
+ self.download = MyDeferredSemaphore(tokens=12)
+
+ self.onClose.append(self.__onClose__)
+ self.onLayoutFinish.append(self.createsetup)
+
+ def createsetup(self):
+ logger.info("...")
+ logger.debug("list_event: %s", self.list_event)
+ self.setTitle("%s - %s" % (TVS, _("Event Details")))
+ year = self.list_event[EVENT_IDX_YEAR]
+ # genre = self.list_event[EVENT_IDX_GENRE]
+ title = self.list_event[EVENT_IDX_TITLE]
+ if year:
+ title += " (%s)" % year
+ self["title"].setText(title)
+ episodetitle = self.list_event[EVENT_IDX_EPISODE_TITLE]
+ subline = self.list_event[EVENT_IDX_SUBLINE]
+ self["episodetitle"].setText(episodetitle if episodetitle else subline)
+ start = strftime("%H:%M", localtime(int(self.list_event[EVENT_IDX_TIME_START])))
+ duration = (int(self.list_event[EVENT_IDX_TIME_END]) - int(self.list_event[EVENT_IDX_TIME_START])) / 60
+ self["timeduration"].setText("%s, %s %s" % (start, duration, _("min")))
+ self["channelpix"].setPixmap(getPicon(self.channel["id"], self.channel["service"]))
+ self["description"].setText(self.list_event[EVENT_IDX_TEXT])
+
+ url = getEventPicUrl(self.list_event[EVENT_IDX_IMAGES])
+ if url:
+ afile = os.path.join(TMP_DIR, "programpix%s" % url[-4:])
+ self.download.run(MydownloadPage, url, afile, headers=headers_gzip).addCallback(self.result_back_pic, self["programpix"], afile).addErrback(http_failed)
+
+ self.video_title, url, self.video_url = getVideo(self.list_event[EVENT_IDX_VIDEOS])
+ if url:
+ afile = os.path.join(TMP_DIR, "videopix%s" % url[-4:])
+ self.download.run(MydownloadPage, url, afile, headers=headers_gzip).addCallback(self.result_back_pic2, self["videopix"], afile).addErrback(http_failed)
+
+ def result_back_pic(self, result, pixmap, afile):
+ logger.info("result: %s", result)
+ logger.info("afile: %s", afile)
+ pixmap.instance.setPixmap(LoadPixmap(afile))
+
+ def result_back_pic2(self, result, pixmap, afile):
+ logger.info("result: %s", result)
+ logger.info("afile: %s", afile)
+ self.loadscalePixmap(pixmap, afile)
+
+ def loadscalePixmap(self, pixmap, afile=""):
+ logger.info("afile: %s, pixmap: %s", afile, pixmap)
+ if pathExists(afile):
+ # pixmap.instance.setPixmap(gPixmapPtr())
+ scale = AVSwitch().getFramebufferScale()
+ size = pixmap.instance.size()
+ self.picload.setPara(
+ (size.width(), size.height(), scale[0], scale[1], False, 1, "#00000000")
+ )
+ self.picload.startDecode(afile)
+
+ def __finish_decode(self, _picInfo):
+ logger.info("...")
+ ptr = self.picload.getData()
+ if ptr is not None:
+ self["videopix"].instance.setPixmap(ptr)
+
+ def deferCanceler(self):
+ logger.info("...")
+ for items in self.deferreds:
+ if items.paused >= 0:
+ items.pause()
+ if not items.called:
+ items.cancel()
+ self.deferreds.remove(items)
+
+ def key_ok(self):
+ logger.info("...")
+ if self.video_url and self.video_url.endswith(("mp4")):
+ sref = eServiceReference(eServiceReference.idGST, 0, self.video_url)
+ sref.setName(self.video_title)
+ self.session.open(StreamPlayer, sref)
+
+ def __onClose__(self):
+ logger.info("...")
+ del self.picload_conn
+ del self.picload
+ self.deferCanceler()
diff --git a/src/EventList.py b/src/EventList.py
new file mode 100644
index 0000000..4813efe
--- /dev/null
+++ b/src/EventList.py
@@ -0,0 +1,95 @@
+# !/usr/bin/python
+# coding=utf-8
+#
+# Copyright (C) 2018-2024 by dream-alpha
+#
+# In case of reuse of this source code please do not remove this copyright.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# For more information on the GNU General Public License see:
+# .
+
+
+from Components.HTMLComponent import HTMLComponent
+from Components.TemplatedMultiContentComponent import TemplatedMultiContentComponent
+from enigma import eListbox
+from .SkinUtils import getSkinPath
+from .FileUtils import readFile
+from .Debug import logger
+
+
+class EventList(HTMLComponent, TemplatedMultiContentComponent, object):
+
+ COMPONENT_ID = ""
+ default_template = ""
+
+ def __init__(self, alist=None, component_id="", default_template_name=""):
+ logger.info("...")
+ self.skinAttributes = []
+ EventList.default_template = readFile(getSkinPath(default_template_name))
+ EventList.COMPONENT_ID = component_id
+ TemplatedMultiContentComponent.__init__(self)
+ self.list = alist if alist else []
+
+ def getCurrent(self):
+ logger.info("...")
+ return self.l.getCurrentSelection()
+
+ GUI_WIDGET = eListbox
+
+ def postWidgetCreate(self, instance):
+ logger.info("...")
+ instance.setContent(self.l)
+
+ def preWidgetRemove(self, instance):
+ logger.info("...")
+ instance.setContent(None)
+
+ def moveToIndex(self, index):
+ logger.info("...")
+ self.instance.moveSelectionTo(index)
+
+ def getCurrentIndex(self):
+ logger.info("...")
+ return self.instance.getCurrentIndex()
+
+ def moveUp(self):
+ logger.info("...")
+ if self.instance is not None:
+ self.instance.moveSelection(self.instance.moveUp)
+
+ def moveDown(self):
+ logger.info("...")
+ if self.instance is not None:
+ self.instance.moveSelection(self.instance.moveDown)
+
+ def moveLeft(self):
+ logger.info("...")
+ if self.instance is not None:
+ self.instance.moveSelection(self.instance.moveLeft)
+
+ def moveRight(self):
+ logger.info("...")
+ if self.instance is not None:
+ self.instance.moveSelection(self.instance.moveRight)
+
+ def invalidate(self):
+ logger.info("...")
+ self.l.invalidate()
+
+ def entryRemoved(self, index):
+ logger.info("...")
+ self.l.entryRemoved(index)
+
+ def setSelectionEnable(self, selectionEnabled=True):
+ logger.info("...")
+ self.instance.setSelectionEnable(selectionEnabled)
diff --git a/src/FileUtils.py b/src/FileUtils.py
new file mode 100644
index 0000000..71cdf07
--- /dev/null
+++ b/src/FileUtils.py
@@ -0,0 +1,88 @@
+#!/usr/bin/python
+# coding=utf-8
+#
+# Copyright (C) 2018-2024 by dream-alpha
+#
+# In case of reuse of this source code please do not remove this copyright.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# For more information on the GNU General Public License see:
+# .
+
+
+import os
+from pipes import quote
+import glob
+from .Debug import logger
+
+
+def stripCutNumber(path):
+ filename, ext = os.path.splitext(path)
+ if len(filename) > 3:
+ if filename[-4] == "_" and filename[-3:].isdigit():
+ filename = filename[:-4]
+ path = filename + ext
+ return path
+
+
+def readFile(path):
+ data = ""
+ try:
+ with open(path, "r") as f:
+ data = f.read()
+ except Exception as e:
+ logger.info("path: %s, exception: %s", path, e)
+ return data
+
+
+def writeFile(path, data):
+ try:
+ with open(path, "w") as f:
+ f.write(data)
+ except Exception as e:
+ logger.error("path: %s, exception: %s", path, e)
+
+
+def deleteFile(path):
+ os.popen("rm %s" % quote(path)).read()
+
+
+def deleteFiles(path, clear=False):
+ for afile in glob.glob(path):
+ if clear:
+ writeFile(afile, "")
+ deleteFile(afile)
+
+
+def touchFile(path):
+ os.popen("touch %s" % quote(path)).read()
+
+
+def copyFile(src_path, dest_path):
+ os.popen("cp %s %s" % (quote(src_path), quote(dest_path))).read()
+
+
+def renameFile(src_path, dest_path):
+ os.popen("mv %s %s" % (quote(src_path), quote(dest_path))).read()
+
+
+def createDirectory(path):
+ os.popen("mkdir -p %s" % quote(path)).read()
+
+
+def createSymlink(src, dst):
+ logger.info("link: src: %s > %s", src, dst)
+ os.symlink(src, dst)
+
+
+def deleteDirectory(path):
+ os.popen("rm -rf %s" % quote(path)).read()
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..65b79ed
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,4 @@
+installdir = $(libdir)/enigma2/python/Plugins/Extensions/TVMagazineCockpit
+SUBDIRS = skin
+install_PYTHON = *.py
+install_DATA = *.png *.xml
diff --git a/src/Menu.py b/src/Menu.py
new file mode 100755
index 0000000..bb0b645
--- /dev/null
+++ b/src/Menu.py
@@ -0,0 +1,102 @@
+# !/usr/bin/python
+# coding=utf-8
+#
+# Copyright (C) 2018-2024 by dream-alpha
+#
+# In case of reuse of this source code please do not remove this copyright.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# For more information on the GNU General Public License see:
+# .
+
+
+from Components.config import config
+from Components.UsageConfig import preferredTimerPath
+from RecordTimer import RecordTimerEntry
+from Screens.TimerEdit import TimerSanityConflict
+from Screens.TimerEntry import TimerEntry
+from Screens.ChoiceBox import ChoiceBox
+from enigma import eServiceReference
+from ServiceReference import ServiceReference
+from .__init__ import _
+from .Debug import logger
+from .Version import PLUGIN
+from .ZapUtils import Zap_Service
+from .Constants import EVENT_IDX_TIME_START, EVENT_IDX_TIME_END, EVENT_IDX_TITLE, EVENT_IDX_GENRE
+from .PluginUtils import getPlugin, WHERE_MEDIATHEK_SEARCH, WHERE_TMDB_MOVIELIST
+from .ServiceUtils import getService
+
+
+class Menu():
+ def __init__(self):
+ logger.info("...")
+ self.mediathek_plugin = getPlugin(WHERE_MEDIATHEK_SEARCH)
+ self.tmdb_plugin = getPlugin(WHERE_TMDB_MOVIELIST)
+
+ def openMenu(self, service, event):
+ logger.info("service: %s", service)
+ logger.info("event: %s", event)
+ self.service = service
+ self.event = event
+ alist = [
+ ("%s" % _("Zap"), "zap"),
+ ("%s" % _("Add Timer"), "timer"),
+ ]
+ if self.mediathek_plugin:
+ alist.append(("%s" % self.mediathek_plugin.description, "mediathek_search"))
+ if self.tmdb_plugin:
+ alist.append(("%s" % self.tmdb_plugin.description, "tmdb_search"))
+
+ self.session.openWithCallback(
+ self.openMenuCallback,
+ ChoiceBox,
+ title=PLUGIN,
+ list=alist,
+ windowTitle=_("Menu"),
+ allow_cancel=True,
+ titlebartext=_("Input")
+ )
+
+ def openMenuCallback(self, answer=None):
+ logger.info("...")
+ if answer:
+ action = answer[1]
+ if action == "zap":
+ Zap_Service(self.service)
+ self.close()
+ elif action == "timer":
+ serviceref = ServiceReference(eServiceReference(self.service))
+ begin = int(self.event[EVENT_IDX_TIME_START]) - config.recording.margin_before.value * 60
+ end = int(self.event[EVENT_IDX_TIME_END]) + config.recording.margin_after.value * 60
+ eventdata = (begin, end, self.event[EVENT_IDX_TITLE], self.event[EVENT_IDX_GENRE], None)
+ newEntry = RecordTimerEntry(serviceref, checkOldTimers=True, dirname=preferredTimerPath(), *eventdata)
+ self.session.openWithCallback(self.finishedAdd, TimerEntry, newEntry)
+ elif action == "mediathek_search":
+ self.mediathek_plugin(self.session, self.event[EVENT_IDX_TITLE])
+ elif action == "tmdb_search":
+ service = getService("", self.event[EVENT_IDX_TITLE])
+ self.tmdb_plugin(self.session, service)
+
+ def finishedAdd(self, answer):
+ logger.info("...")
+ if answer[0]:
+ entry = answer[1]
+ simulTimerList = self.session.nav.RecordTimer.record(entry)
+ if simulTimerList is not None:
+ for x in simulTimerList:
+ if x.setAutoincreaseEnd(entry):
+ self.session.nav.RecordTimer.timeChanged(x)
+ simulTimerList = self.session.nav.RecordTimer.record(entry)
+ if simulTimerList is not None:
+ self.session.openWithCallback(self.finishedAdd, TimerSanityConflict, simulTimerList)
+ else:
+ logger.debug("Timeredit aborted")
diff --git a/src/More.py b/src/More.py
new file mode 100755
index 0000000..564ecf0
--- /dev/null
+++ b/src/More.py
@@ -0,0 +1,105 @@
+# !/usr/bin/python
+# coding=utf-8
+#
+# Copyright (C) 2018-2024 by dream-alpha
+#
+# In case of reuse of this source code please do not remove this copyright.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# For more information on the GNU General Public License see:
+# .
+
+
+from Screens.ChoiceBox import ChoiceBox
+from Components.config import config
+from .__init__ import _
+from .Debug import logger
+from .ConfigScreen import ConfigScreen
+from .ChannelManagement import ChannelManagement
+from .ConfigInit import bouquet_choices
+from .About import about
+from .Version import PLUGIN
+
+
+class More():
+ def __init__(self):
+ logger.info("...")
+
+ def openMore(self, bouquet, channel_list, channel_dict):
+ logger.info("...")
+ self.bouquet = bouquet
+ self.channel_list = channel_list
+ self.channel_dict = channel_dict
+ alist = [
+ ("%s" % _("Bouquet Selection"), "bouquetselection"),
+ ("%s" % _("Bouquet Setup"), "channel"),
+ ("%s" % _("Settings"), "settings"),
+ ("%s" % _("About"), "about"),
+ ]
+
+ self.session.openWithCallback(
+ self.openMoreCallback,
+ ChoiceBox,
+ title=PLUGIN,
+ list=alist,
+ windowTitle=_("More"),
+ allow_cancel=True,
+ titlebartext=_("Input")
+ )
+
+ def openMoreCallback(self, answer=None):
+ logger.info("...")
+ if answer:
+ screen = answer[1]
+ if screen == "channel":
+ self.session.openWithCallback(
+ self.openChannelManagementCallback,
+ ChannelManagement,
+ self.bouquet,
+ self.channel_list,
+ self.channel_dict,
+ )
+ elif screen == "settings":
+ self.session.openWithCallback(
+ self.openConfigScreenCallback,
+ ConfigScreen,
+ config.plugins.tvmagazinecockpit
+ )
+ elif screen == "bouquetselection":
+ alist = [(value[1], value[0]) for value in bouquet_choices]
+ self.session.openWithCallback(
+ self.openBouquetSelectionCallback,
+ ChoiceBox,
+ title="Bouquet Selection",
+ list=alist,
+ windowTitle=_("Bouquet Selection"),
+ allow_cancel=True,
+ titlebartext=_("Input")
+ )
+ elif screen == "about":
+ about(self.session)
+
+ def openConfigScreenCallback(self, _result=None):
+ logger.info("...")
+ self.reload()
+
+ def openChannelManagementCallback(self, channel_list):
+ logger.info("...")
+ self.channel_list = channel_list
+ self.reload()
+
+ def openBouquetSelectionCallback(self, bouquet):
+ logger.info("bouquet: %s", bouquet)
+ if bouquet:
+ config.plugins.tvmagazinecockpit.bouquet.value = bouquet[1]
+ config.plugins.tvmagazinecockpit.bouquet.save()
+ self.close("programcolumns")
diff --git a/src/MyList.py b/src/MyList.py
new file mode 100644
index 0000000..0b02bca
--- /dev/null
+++ b/src/MyList.py
@@ -0,0 +1,64 @@
+# !/usr/bin/python
+# coding=utf-8
+#
+# Copyright (C) 2018-2024 by dream-alpha
+#
+# In case of reuse of this source code please do not remove this copyright.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# For more information on the GNU General Public License see:
+# .
+
+
+from Components.Sources.List import List
+from .Debug import logger
+
+
+class MyList(List):
+ def __init__(self, alist=None, enableWrapAround=False, item_height=25, fonts=None, buildfunc=None):
+ logger.info("...")
+ if alist is None:
+ alist = []
+ if fonts is None:
+ fonts = []
+ List.__init__(self, list=alist, enableWrapAround=enableWrapAround, item_height=item_height, fonts=fonts, buildfunc=buildfunc)
+
+ def extendList(self, alist):
+ logger.info("...")
+ self.list.extend(alist)
+ self.changed((self.CHANGED_ALL, ))
+
+ def sort(self, key=0):
+ logger.info("...")
+ self.list.sort(key=key)
+ self.changed((self.CHANGED_ALL, ))
+
+ def deleteEntry(self):
+ logger.info("...")
+ index = self.master.getIndex()
+ del self.list[index]
+ self.setList(self.list)
+ self.master.setIndex(index)
+ self.entry_changed(index)
+
+ def clearList(self):
+ logger.info("...")
+ if self.list:
+ del self.list[:]
+ self.changed((self.CHANGED_CLEAR, ))
+
+ def modifyEntryVal(self, index, data, indexval):
+ self.list[index][indexval] = data
+ self.entry_changed(index)
+
+ def getList(self):
+ return self.list[:]
diff --git a/src/PictureUtils.py b/src/PictureUtils.py
new file mode 100644
index 0000000..e7f82c2
--- /dev/null
+++ b/src/PictureUtils.py
@@ -0,0 +1,60 @@
+# !/usr/bin/python
+# coding=utf-8
+#
+# Copyright (C) 2018-2024 by dream-alpha
+#
+# In case of reuse of this source code please do not remove this copyright.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# For more information on the GNU General Public License see:
+# .
+
+
+from Components.config import config
+from Tools.LoadPixmap import LoadPixmap
+from .ConfigInit import plugindir
+from .Debug import logger
+
+
+def getPicon(channel_id, service=""):
+ logger.info("channel_id: %s, service: %s", channel_id, service)
+ pixmap_ptr = None
+ if service and config.plugins.tvmagazinecockpit.use_picons.value:
+ picons_dir = config.usage.configselection_piconspath.value
+ pixmap_ptr = LoadPixmap("%s/%s.png" % (picons_dir, service[:-1].replace(":", "_")))
+ if not pixmap_ptr:
+ pixmap_ptr = LoadPixmap("%slogos/%s.png" % (plugindir, channel_id))
+ return pixmap_ptr
+
+
+def getVideo(videos):
+ logger.debug("videos: %s", videos)
+ title = video_url = still_image_url = ""
+ if len(videos) > 0:
+ video_list = videos[0].get("video", "")
+ video = video_list[0]
+ logger.debug("video: %s", video)
+ title = videos[0].get("title", "")
+ still_image_url = videos[0].get("stillImage", "")
+ video_url = video.get("url", "")
+ logger.debug("title: %s, still_image_url: %s, video_url: %s", title, still_image_url, video_url)
+ return title, still_image_url, video_url
+
+
+def getEventPicUrl(images):
+ logger.debug("images: %s", images)
+ url = ""
+ if len(images) > 0:
+ image = images[0]
+ url = image.get("size4", "")
+ logger.debug("programpix url: %s", url)
+ return url
diff --git a/src/PluginUtils.py b/src/PluginUtils.py
new file mode 100644
index 0000000..0cbc972
--- /dev/null
+++ b/src/PluginUtils.py
@@ -0,0 +1,37 @@
+#!/usr/bin/python
+# coding=utf-8
+#
+# Copyright (C) 2018-2024 by dream-alpha
+#
+# In case of reuse of this source code please do not remove this copyright.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# For more information on the GNU General Public License see:
+# .
+
+
+from Components.PluginComponent import plugins
+
+
+WHERE_SEARCH = -99
+WHERE_TMDB_SEARCH = -98
+WHERE_TMDB_MOVIELIST = -97
+WHERE_MEDIATHEK_SEARCH = -96
+WHERE_TVMAGAZINE_SEARCH = -95
+
+
+def getPlugin(where):
+ plugin = None
+ plugins_list = plugins.getPlugins(where=where)
+ if len(plugins_list) > 0:
+ plugin = plugins_list[0]
+ return plugin
diff --git a/src/ProgramColumns.py b/src/ProgramColumns.py
new file mode 100755
index 0000000..07ee860
--- /dev/null
+++ b/src/ProgramColumns.py
@@ -0,0 +1,407 @@
+# !/usr/bin/python
+# coding=utf-8
+#
+# Copyright (C) 2018-2024 by dream-alpha
+#
+# In case of reuse of this source code please do not remove this copyright.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# For more information on the GNU General Public License see:
+# .
+
+
+import os
+import time
+from datetime import datetime
+from time import strftime, localtime
+from math import ceil
+from enigma import gPixmapPtr
+from Screens.Screen import Screen
+from Components.ActionMap import ActionMap
+from Components.Label import Label
+from Components.Pixmap import Pixmap
+from Components.Sources.StaticText import StaticText
+from Components.config import config
+from Tools.LoadPixmap import LoadPixmap
+from .Downloader import headers_gzip, MydownloadPage, http_failed, MyDeferredSemaphore
+from .EventDetails import EventDetails
+from .More import More
+from .Menu import Menu
+from .__init__ import _
+from .EventList import EventList
+from .Debug import logger
+from .TVSpielfilmData import TVSpielfilmData
+from .Constants import TMP_DIR, TVS, BOUQUETS, EVENT_IDX_YEAR, EVENT_IDX_IMAGES, EVENT_IDX_TITLE, EVENT_IDX_EPISODE_TITLE, EVENT_IDX_SUBLINE, EVENT_IDX_TIME_START, EVENT_IDX_BROADCASTER_NAME
+from .PictureUtils import getEventPicUrl, getPicon
+from .FileUtils import deleteDirectory
+from .ChannelUtils import read_channel_list
+
+
+class ProgramColumns(Screen, More, Menu):
+ def __init__(self, session, channel_dict):
+ logger.info("...")
+ self.bouquet = config.plugins.tvmagazinecockpit.bouquet.value
+ self.channel_list = read_channel_list(self.bouquet)
+ self.channel_dict = channel_dict
+ Screen.__init__(self, session)
+ self.skinName = "ProgramColumns"
+ More.__init__(self)
+ Menu.__init__(self)
+ self["actions"] = ActionMap(
+ ["TVC_Actions", "NumberActions"],
+ {
+ "0": self.reload,
+ "ok": self.key_ok,
+ "cancel": self.close,
+ "info": self.key_ok,
+ "up": self.moveUp,
+ "down": self.moveDown,
+ "left": self.left,
+ "right": self.right,
+ "next": self.key_next,
+ "back": self.key_back,
+ "red": self.key_red,
+ "green": self.key_green,
+ "yellow": self.key_yellow,
+ "blue": self.key_blue,
+ "menu": self.showMenu,
+ "channelup": self.channelup,
+ "channeldown": self.channeldown,
+ }
+ )
+
+ self.tvs_data_mgr = TVSpielfilmData(self.showChannel)
+ self.events = {}
+ self.cols = 6
+ self.list_columns = [[]] * self.cols
+ self.list_prime = [[]] * self.cols
+ self.list_indices = [-1] * self.cols
+ self.listindex = 0
+ self.page_index = 0
+ self.pages = 0
+
+ self["searchdate"] = Label()
+
+ for i in range(self.cols):
+ self["list%s" % i] = EventList(None, "ProgramColumns", "screenpart_program_template.tpl")
+ self["channel%s" % i] = Label()
+ self["channelpix%s" % i] = Pixmap()
+ self["programpix%s" % i] = Pixmap()
+ self["time%s" % i] = Label()
+ self["description%s" % i] = Label()
+
+ self.first = True
+ self.mytimecount = 1
+ mytime = int(time.time()) - 24 * 60 * 60
+ self.timelist = []
+ for _day in range(0, 15):
+ self.timelist.append([strftime("< %A, %d. %b %Y >", localtime(mytime)), strftime("%Y-%m-%d", localtime(mytime))])
+ mytime = mytime + 24 * 60 * 60
+
+ self["key_red"] = StaticText(_("More") + " ...")
+ self["key_green"] = StaticText(_("20:15"))
+ self["key_yellow"] = StaticText(_("22:00"))
+ self["key_blue"] = StaticText(_("Now"))
+
+ self.download = MyDeferredSemaphore(tokens=100)
+ self.onClose.append(self.__onClose__)
+ self.onLayoutFinish.append(self.reload)
+
+ def downloadChannel(self, channel, i):
+ logger.info("channel: %s", channel)
+ if self.channel_list:
+ self.tvs_data_mgr.downloadEvents(channel, self.day, i)
+ else:
+ self.showPage()
+
+ def showPage(self):
+ logger.info("...")
+ # logger.info("self.events: %s", self.events)
+ title = "%s %s - %s: %s" % (TVS, _("column view"), BOUQUETS[self.bouquet], _("Loading..."))
+ self.setTitle(title)
+ self.clearValues()
+ start = self.page_index * 6
+ stop = min(start + 6, len(self.channel_list))
+ self.page_list = self.channel_list[start:stop]
+ logger.debug("page_list: %s", self.page_list)
+
+ for i, channel_name in enumerate(self.page_list):
+ channel = self.channel_dict.get(channel_name, None)
+ if channel:
+ channel_id = channel["id"]
+ self["channel%s" % i].setText(channel_id)
+ # self["description%s" % i].setText(_("no event info avilable"))
+ if self.day in self.events and channel_id in self.events[self.day]:
+ logger.debug("data already available")
+ self.showChannel(self.events, channel, i)
+ else:
+ logger.debug("need to download data")
+ self.downloadChannel(channel, i)
+ if len(self.page_list) == 0:
+ title = "%s %s - %s: %s: %s/%s, %s: %s" % (TVS, _("column view"), BOUQUETS[self.bouquet], _("Page"), self.page_index + 1, self.pages, _("Services"), len(self.channel_list))
+ self.setTitle(title)
+
+ def showChannel(self, events, channel, i):
+
+ def createListEntry(event):
+ entry = []
+ start_time = strftime("%H:%M", localtime(int(event[EVENT_IDX_TIME_START])))
+ entry.append(start_time)
+ entry.append(event[EVENT_IDX_TITLE])
+ sub_title = event[EVENT_IDX_EPISODE_TITLE]
+ if not sub_title:
+ sub_title = event[EVENT_IDX_SUBLINE]
+ entry.append(sub_title)
+ entry.append(str(event[EVENT_IDX_YEAR]))
+ entry.append(int(event[EVENT_IDX_TIME_START]))
+ return entry
+
+ logger.info("i: %s", i)
+ channel_id = channel["id"]
+ self.events = events
+ tmp_list = []
+ prime_time = self.getPointInTime("20:15")
+ prime_diff = prime_time
+ self.list_prime[i] = None
+ now_time = self.point_in_time
+ now_diff = now_time
+ now_index = 0
+ for event_index, event in enumerate(events[self.day][channel_id]):
+ tmp = createListEntry(event)
+ event_time = int(event[EVENT_IDX_TIME_START])
+ event_diff = abs(prime_time - event_time)
+ # logger.debug("event_time: %s, event_diff: %s, prime_diff: %s", event_time, event_diff, prime_diff)
+ if event_diff < prime_diff:
+ prime_diff = event_diff
+ self.list_prime[i] = event
+ # logger.debug("new prime diff: %s", prime_diff)
+
+ event_diff = abs(now_time - event_time)
+ # logger.debug("event_time: %s, event_diff: %s, now_diff: %s", event_time, event_diff, now_diff)
+ if event_diff < now_diff:
+ now_diff = event_diff
+ now_index = event_index
+ # logger.debug("new now diff: %s, index: %s", now_diff, now_index)
+ tmp_list.append(tmp)
+
+ if self.list_prime[i]:
+ self.showPrimeEvent(self.list_prime[i], i, channel)
+
+ self.list_columns[i] = tmp_list
+ self.list_indices[i] = now_index
+
+ sub_list = self.list_columns[i][self.list_indices[i] - 1:self.list_indices[i] + 4]
+ j = len(sub_list)
+ while j < 5:
+ sub_list.append(["", "", "", "", 0])
+ j += 1
+
+ self["list%s" % i].l.setList(sub_list)
+ self["list%s" % i].moveToIndex(1)
+ if i == 0 and self.first:
+ self.first = False
+ self["list0"].setSelectionEnable(True)
+ title = "%s %s - %s: %s: %s/%s, %s: %s" % (TVS, _("column view"), BOUQUETS[self.bouquet], _("Page"), self.page_index + 1, self.pages, _("Services"), len(self.channel_list))
+ self.setTitle(title)
+
+ def showPrimeEvent(self, prime_event, i, channel):
+ logger.info("...")
+ channel_id = channel["id"]
+ self["channel%s" % i].setText(prime_event[EVENT_IDX_BROADCASTER_NAME])
+ self["time%s" % i].setText(strftime("%H:%M", localtime(int(prime_event[EVENT_IDX_TIME_START]))))
+ self["description%s" % i].setText(prime_event[EVENT_IDX_TITLE])
+ self["channelpix%s" % i].instance.setPixmap(gPixmapPtr())
+ self["channelpix%s" % i].instance.setPixmap(getPicon(channel_id, channel["service"]))
+ url = getEventPicUrl(prime_event[EVENT_IDX_IMAGES])
+ if url:
+ afile = os.path.join(TMP_DIR, "programpix-%s-%s%s" % (self.day, channel_id, url[-4:]))
+ if os.path.exists(afile):
+ self.result_back_pic(None, i, afile)
+ else:
+ self.download.run(MydownloadPage, url, afile, headers=headers_gzip).addCallback(self.result_back_pic, i, afile).addErrback(http_failed)
+
+ def result_back_pic(self, result, i, event_pic_file):
+ logger.info("result: %s", result)
+ logger.info("i: %s, event_pic_file: %s", i, event_pic_file)
+ self["programpix%s" % i].instance.setPixmap(LoadPixmap(event_pic_file))
+
+ def clearValues(self):
+ logger.info("...")
+ for i in range(self.cols):
+ self["channel%s" % i].setText("")
+ self["time%s" % i].setText("")
+ self["description%s" % i].setText("")
+ self["channelpix%s" % i].instance.setPixmap(gPixmapPtr())
+ self["list%s" % i].l.setList([])
+ self["programpix%s" % i].instance.setPixmap(gPixmapPtr())
+
+ def left(self):
+ logger.info("...")
+ self["list%s" % self.listindex].setSelectionEnable(False)
+ self.listindex -= 1
+ if self.listindex < 0:
+ self.listindex = self.cols - 1
+ self.page_index -= 1
+ if self.page_index < 0:
+ self.page_index = self.pages - 1
+ max_listindex = len(self.channel_list) % self.cols - 1
+ if max_listindex >= 0:
+ self.listindex = max_listindex
+ self.showPage()
+ self["list%s" % self.listindex].setSelectionEnable(True)
+
+ def right(self):
+ logger.info("...")
+ self["list%s" % self.listindex].setSelectionEnable(False)
+ max_listindex = len(self.channel_list) % self.cols - 1
+ self.listindex += 1
+ if (
+ self.listindex > self.cols - 1
+ or (self.page_index == self.pages - 1 and self.listindex > max_listindex)
+ ):
+ self.listindex = 0
+ self.page_index += 1
+ if self.page_index > self.pages - 1:
+ self.page_index = 0
+ self.showPage()
+ self["list%s" % self.listindex].setSelectionEnable(True)
+
+ def moveUp(self):
+ logger.info("listindex: %s", self.listindex)
+ if self.list_indices[self.listindex] > 1:
+ self.list_indices[self.listindex] -= 1
+ index = self.list_indices[self.listindex]
+ column = self.list_columns[self.listindex]
+ self.point_in_time = column[index][4]
+ sub_list = column[index - 1:index + 4]
+ self["list%s" % self.listindex].setList(sub_list)
+ self.showPage()
+
+ def moveDown(self):
+ logger.info("listindex: %s", self.listindex)
+ logger.debug("index: %s, len(list): %s", self.list_indices[self.listindex], len(self.list_columns[self.listindex]))
+ if self.list_indices[self.listindex] < len(self.list_columns[self.listindex]) - 1:
+ self.list_indices[self.listindex] += 1
+ index = self.list_indices[self.listindex]
+ column = self.list_columns[self.listindex]
+ self.point_in_time = column[index][4]
+ sub_list = column[index - 1:index + 4]
+ self["list%s" % self.listindex].setList(sub_list)
+ self.showPage()
+
+ def channelup(self):
+ logger.info("...")
+ self["list%s" % self.listindex].setSelectionEnable(False)
+ self.page_index += 1
+ if self.page_index >= self.pages:
+ self.page_index = 0
+ self.listindex = 0
+ self["list%s" % self.listindex].setSelectionEnable(True)
+ self.showPage()
+
+ def channeldown(self):
+ logger.info("...")
+ self["list%s" % self.listindex].setSelectionEnable(False)
+ self.page_index -= 1
+ if self.page_index < 0:
+ self.page_index = self.pages - 1
+ self.listindex = self.cols - 1 if len(self.channel_list) % self.cols == 0 else len(self.channel_list) % self.cols - 1
+ else:
+ self.listindex = self.cols - 1
+ self["list%s" % self.listindex].setSelectionEnable(True)
+ self.showPage()
+
+ def showMore(self):
+ logger.info("...")
+ if self.download.finished():
+ self.openMore(self.bouquet, self.channel_list, self.channel_dict)
+
+ def showMenu(self):
+ if self.download.finished():
+ channel_name = self.page_list[self.listindex]
+ channel = self.channel_dict[channel_name]
+ event = self.events[self.day][channel["id"]][self.list_indices[self.listindex]]
+ self.openMenu(channel["service"], event)
+
+ def key_next(self):
+ logger.info("...")
+ self.mytimecount += 1
+ self.reload()
+
+ def key_back(self):
+ logger.info("...")
+ self.mytimecount -= 1
+ self.reload()
+
+ def key_ok(self):
+ logger.info("...")
+ current_selection = self["list%s" % self.listindex].l.getCurrentSelection()
+ if current_selection:
+ logger.debug("current_selection: %s", current_selection)
+ channel_name = self.page_list[self.listindex]
+ channel_id = self.channel_dict[channel_name]["id"]
+ self.session.open(
+ EventDetails,
+ self.channel_dict[channel_name],
+ self.events[self.day][channel_id][self.list_indices[self.listindex]],
+ )
+
+ def getPointInTime(self, hm):
+ logger.info("hm: %s", hm)
+ logger.info("mytimecount: %s", self.mytimecount)
+ ymd = self.timelist[self.mytimecount][1].split("-")
+ hm = hm.split(":")
+ point_in_time = int(datetime(int(ymd[0]), int(ymd[1]), int(ymd[2]), int(hm[0]), int(hm[1]), 0).strftime("%s"))
+ logger.debug("point_in_time: %s", point_in_time)
+ return point_in_time
+
+ def key_red(self):
+ logger.info("...")
+ self.showMore()
+
+ def key_green(self):
+ logger.info("...")
+ self.point_in_time = self.getPointInTime("20:15")
+ self.showPage()
+
+ def key_yellow(self):
+ logger.info("...")
+ self.point_in_time = self.getPointInTime("22:00")
+ self.showPage()
+
+ def key_blue(self):
+ logger.info("...")
+ self.point_in_time = self.getPointInTime(time.strftime("%H:%M"))
+ self.showPage()
+
+ def reload(self):
+ logger.info("self.channel_list: %s", self.channel_list)
+ self["list%s" % self.listindex].setSelectionEnable(False)
+ self.pages = int(ceil(float(len(self.channel_list)) / self.cols))
+ self.listindex = 0
+ self.page_index = 0
+ self.mytimecount = max(min(len(self.timelist) - 1, self.mytimecount), 0)
+ self["searchdate"].text = self.timelist[self.mytimecount][0]
+ self.day = self.timelist[self.mytimecount][1]
+ self.list_columns = [[]] * self.cols
+ self.list_prime = [[]] * self.cols
+ self.list_indices = [-1] * self.cols
+ self.point_in_time = self.getPointInTime("20:15")
+ self["list%s" % self.listindex].setSelectionEnable(True)
+ self.showPage()
+
+ def __onClose__(self):
+ logger.info("...")
+ self.download.deferCanceler()
+ del self.download.ds.waiting[:]
+ self.download.work.clear()
+ deleteDirectory(TMP_DIR)
diff --git a/src/Search.py b/src/Search.py
new file mode 100755
index 0000000..1ec6478
--- /dev/null
+++ b/src/Search.py
@@ -0,0 +1,31 @@
+# !/usr/bin/python
+# coding=utf-8
+#
+# Copyright (C) 2018-2024 by dream-alpha
+#
+# In case of reuse of this source code please do not remove this copyright.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# For more information on the GNU General Public License see:
+# .
+
+
+from Screens.Screen import Screen
+from .Debug import logger
+
+
+class Search(Screen):
+ def __init__(self, session, query):
+ logger.info("query: %s", query)
+ Screen.__init__(self, session)
+
+ # let"s do it...
diff --git a/src/ServiceUtils.py b/src/ServiceUtils.py
new file mode 100644
index 0000000..33e056b
--- /dev/null
+++ b/src/ServiceUtils.py
@@ -0,0 +1,64 @@
+#!/usr/bin/python
+# coding=utf-8
+#
+# Copyright (C) 2018-2024 by dream-alpha
+#
+# In case of reuse of this source code please do not remove this copyright.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# For more information on the GNU General Public License see:
+# .
+
+
+import os
+from enigma import eServiceReference
+
+
+SID_DVB = eServiceReference.idDVB # eServiceFactoryDVB::id enum{id = 0x0001};
+SID_DVD = eServiceReference.idDVD # eServiceFactoryDVD::id enum{id = 0x1111};
+SID_M2TS = eServiceReference.idM2TS # eServiceFactoryM2TS::id enum{id = 0x0003};
+SID_GST = eServiceReference.idGST # eServiceFactoryGST::id enum{id = 0x1001};
+
+
+EXT_TS = [".ts", ".trp"]
+EXT_M2TS = [".m2ts"]
+EXT_DVD = [".ifo", ".iso", ".img"]
+EXT_VIDEO = [".avi", ".divx", ".f4v", ".flv", ".m4v", ".mkv", ".mov", ".mp4", ".mpeg", ".mpg", ".mts", ".vob", ".wmv", ".asf", ".stream", ".webm"]
+EXT_BLU = [".bdmv"]
+
+EXT_PICTURE = [".jpg", ".jpeg", ".png"]
+EXT_MUSIC = [".mp3", ".wma"]
+EXT_PLAYLIST = [".m3u"]
+
+ALL_VIDEO = EXT_TS + EXT_M2TS + EXT_DVD + EXT_VIDEO + EXT_BLU
+ALL_MEDIA = ALL_VIDEO + EXT_PICTURE + EXT_MUSIC + EXT_PLAYLIST
+
+
+DEFAULT_VIDEO_PID = 0x44
+DEFAULT_AUDIO_PID = 0x45
+
+
+def getService(path, name=""):
+ service = None
+ ext = os.path.splitext(path)[1].lower()
+ if ext in EXT_TS:
+ service = eServiceReference(SID_DVB, 0, path)
+ elif ext in EXT_DVD:
+ service = eServiceReference(SID_DVD, 0, path)
+ elif ext in EXT_M2TS:
+ service = eServiceReference(SID_M2TS, 0, path)
+ else:
+ service = eServiceReference(SID_GST, 0, path)
+ service.setData(0, DEFAULT_VIDEO_PID)
+ service.setData(1, DEFAULT_AUDIO_PID)
+ service.setName(name)
+ return service
diff --git a/src/SkinUtils.py b/src/SkinUtils.py
new file mode 100644
index 0000000..1228983
--- /dev/null
+++ b/src/SkinUtils.py
@@ -0,0 +1,96 @@
+#!/usr/bin/python
+# coding=utf-8
+#
+# Copyright (C) 2018-2024 by dream-alpha
+#
+# In case of reuse of this source code please do not remove this copyright.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# For more information on the GNU General Public License see:
+# .
+
+
+import os
+from enigma import getDesktop
+from Components.config import config
+from Tools.Directories import resolveFilename, SCOPE_PLUGINS
+from skin import loadSkin, loadSingleSkinData, dom_skins
+from .Debug import logger
+from .Version import ID, PLUGIN
+
+
+def getSkinName(skin_name):
+ return ID + skin_name
+
+
+def getScalingFactor():
+ return {"HD": 2.0 / 3.0, "FHD": 1, "WQHD": 4.0 / 3.0}[getResolution()]
+
+
+def getResolution():
+ height = getDesktop(0).size().height()
+ resolution = "SD"
+ if height > 576:
+ resolution = "HD"
+ if height > 720:
+ resolution = "FHD"
+ if height > 1080:
+ resolution = "WQHD"
+ return resolution
+
+
+def getSkinPath(file_name):
+ logger.debug(">>> file_name: %s", file_name)
+ base_skin_dir = "/usr/share/enigma2"
+ sub_skin_dir = os.path.dirname(config.skin.primary_skin.value)
+ resolution = getResolution()
+ logger.debug("resolution: %s, sub_skin_dir: %s", resolution, sub_skin_dir)
+ if not sub_skin_dir:
+ sub_skin_dir = "Default-HD"
+ elif resolution == "FHD":
+ if sub_skin_dir in ["Shadow-FHD", "Zombi-Shadow-FHD"]:
+ sub_skin_dir = "Shadow-FHD"
+ else:
+ sub_skin_dir = "Default-FHD"
+ elif resolution == "WQHD":
+ if sub_skin_dir in ["Shadow-WQHD", "Default-WQHD"]:
+ sub_skin_dir = "Default-WQHD"
+ else:
+ sub_skin_dir = "Other-WQHD"
+ else:
+ sub_skin_dir = "Default-HD"
+
+ dirs = [
+ os.path.join(resolveFilename(SCOPE_PLUGINS), "Extensions", PLUGIN, "skin", sub_skin_dir),
+ os.path.join(resolveFilename(SCOPE_PLUGINS), "SystemPlugins", PLUGIN, "skin", sub_skin_dir),
+ os.path.join(resolveFilename(SCOPE_PLUGINS), "Extensions", PLUGIN, "skin"),
+ os.path.join(resolveFilename(SCOPE_PLUGINS), "SystemPlugins", PLUGIN, "skin"),
+ os.path.join(base_skin_dir, sub_skin_dir),
+ base_skin_dir
+ ]
+ logger.debug("dirs: %s", dirs)
+
+ for adir in dirs:
+ skin_path = os.path.join(adir, file_name)
+ logger.debug("checking: skin_path: %s", skin_path)
+ if os.path.exists(skin_path):
+ break
+ skin_path = ""
+ logger.debug("skin_path: %s", skin_path)
+ return skin_path
+
+
+def loadPluginSkin(skin_file):
+ logger.info("skin_path: %s", getSkinPath(skin_file))
+ loadSkin(getSkinPath(skin_file), "")
+ path, dom_skin = dom_skins[-1:][0]
+ loadSingleSkinData(getDesktop(0), dom_skin, path)
diff --git a/src/StreamPlayer.py b/src/StreamPlayer.py
new file mode 100644
index 0000000..fa78954
--- /dev/null
+++ b/src/StreamPlayer.py
@@ -0,0 +1,64 @@
+# !/usr/bin/python
+# coding=utf-8
+#
+# Copyright (C) 2018-2024 by dream-alpha
+#
+# In case of reuse of this source code please do not remove this copyright.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# For more information on the GNU General Public License see:
+# .
+
+
+from Screens.InfoBar import MoviePlayer
+from Components.ActionMap import ActionMap
+from .Debug import logger
+
+
+class StreamPlayer(MoviePlayer):
+ def __init__(self, session, service):
+ logger.info("...")
+ MoviePlayer.__init__(self, session, service)
+ self.skinName = "MoviePlayer"
+ if "CueSheetActions" in self:
+ del self["CueSheetActions"]
+ if "MenuActions" in self:
+ del self["MenuActions"]
+ if "MovieListActions" in self:
+ del self["MovieListActions"]
+ if "TeletextActions" in self:
+ del self["TeletextActions"]
+ if "InstantExtensionsActions" in self:
+ del self["InstantExtensionsActions"]
+ if "helpActions" in self:
+ del self["helpActions"]
+ if "EPGActions" in self:
+ del self["EPGActions"]
+
+ self["ShowHideActions"] = ActionMap(
+ ["InfobarShowHideActions"],
+ {
+ "toggleShow": self.toggleShow,
+ "hide": self.leavePlayer,
+ },
+ 1
+ )
+
+ def seekFwd(self):
+ logger.info("...")
+
+ def seekBack(self):
+ logger.info("...")
+
+ def handleLeave(self, _how):
+ logger.info("...")
+ self.close()
diff --git a/src/TVMagazineCockpit.png b/src/TVMagazineCockpit.png
new file mode 100755
index 0000000..d981361
Binary files /dev/null and b/src/TVMagazineCockpit.png differ
diff --git a/src/TVMagazineCockpit.py b/src/TVMagazineCockpit.py
new file mode 100644
index 0000000..d58bf7e
--- /dev/null
+++ b/src/TVMagazineCockpit.py
@@ -0,0 +1,46 @@
+# !/usr/bin/python
+# coding=utf-8
+#
+# Copyright (C) 2018-2024 by dream-alpha
+#
+# In case of reuse of this source code please do not remove this copyright.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# For more information on the GNU General Public License see:
+# .
+
+
+from .Debug import logger
+from .ProgramColumns import ProgramColumns
+from .ChannelUtils import read_channel_dict
+from .Constants import TMP_DIR
+from .FileUtils import createDirectory
+
+
+class TVMagazineCockpit():
+ def __init__(self, session, **_kwargs):
+ logger.info("...")
+ self.session = session
+ self.last_screen = None
+ createDirectory(TMP_DIR)
+ self.channel_dict = read_channel_dict()
+ self.showScreenCallback("programcolumns")
+
+ def showScreen(self, screen, *args):
+ logger.info("screen: %s", screen)
+ self.session.openWithCallback(self.showScreenCallback, screen, *args)
+
+ def showScreenCallback(self, *args):
+ return_screen = args[0] if len(args) > 0 else ""
+ logger.info("return_screen: %s", return_screen)
+ if return_screen == "programcolumns":
+ self.showScreen(ProgramColumns, self.channel_dict)
diff --git a/src/TVSpielfilmData.py b/src/TVSpielfilmData.py
new file mode 100644
index 0000000..d414006
--- /dev/null
+++ b/src/TVSpielfilmData.py
@@ -0,0 +1,72 @@
+# !/usr/bin/python
+# coding=utf-8
+#
+# Copyright (C) 2018-2024 by dream-alpha
+#
+# In case of reuse of this source code please do not remove this copyright.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# For more information on the GNU General Public License see:
+# .
+
+
+import json
+from .Downloader import headers_gzip, MygetPage, MyDeferredSemaphore
+from .Constants import EVENT_KEYS, EVENT_IDX_VIDEOS, EVENT_IDX_IMAGES, EVENT_LENGTH
+from .Debug import logger
+from .ChannelUtils import convert_unicode_to_str
+
+
+class TVSpielfilmData():
+ def __init__(self, callback):
+ self.callback = callback
+ self.events = {}
+ self.download = MyDeferredSemaphore(tokens=32)
+
+ def parseJsonEvents(self, json_events):
+ logger.info("...")
+ list_events = []
+ for json_event in json_events:
+ list_event = [""] * EVENT_LENGTH
+ for index, key in enumerate(EVENT_KEYS):
+ # logger.debug("json_event: %s", json_event)
+ # logger.debug("index: %s, key: %s", index, key)
+ if index in [EVENT_IDX_VIDEOS, EVENT_IDX_IMAGES]:
+ # logger.debug("json_event: %s", json_event)
+ list_event[index] = json_event.get(key, [])
+ else:
+ list_event[index] = json_event.get(key, "")
+ list_events.append(list_event)
+ return list_events
+
+ def downloadEvents(self, channel, day, i):
+ logger.info("channel: %s, day: %s", channel, day)
+ channel_id = channel["id"]
+ del self.download.ds.waiting[:]
+ url = "https://live.tvspielfilm.de/static/broadcast/list/%s/%s" % (channel_id, day)
+ logger.debug("url: %s", url)
+ self.download.run(MygetPage, url, headers=headers_gzip).addCallback(self.result_back, channel, i, day).addErrback(self.download_failed, channel, i, day)
+
+ def result_back(self, result, channel, i, day):
+ logger.info("channel: %s", channel)
+ channel_id = channel["id"]
+ if result:
+ if day not in self.events:
+ self.events[day] = {}
+ events = convert_unicode_to_str(json.loads(result))
+ self.events[day][channel_id] = self.parseJsonEvents(events)
+ self.callback(self.events, channel, i)
+
+ def download_failed(self, failure, channel, i, day):
+ logger.error("channel: %s, failure: %s", channel, failure)
+ self.events[day] = {}
+ self.callback(self.events, channel, i)
diff --git a/src/Version.py b/src/Version.py
new file mode 100644
index 0000000..145df79
--- /dev/null
+++ b/src/Version.py
@@ -0,0 +1,26 @@
+# !/usr/bin/python
+# coding=utf-8
+#
+# Copyright (C) 2018-2024 by dream-alpha
+#
+# In case of reuse of this source code please do not remove this copyright.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# For more information on the GNU General Public License see:
+# .
+
+
+PLUGIN = "TVMagazineCockpit"
+ID = "TVC"
+VERSION = "1.7.8"
+COPYRIGHT = "2018-2024 by dream-alpha"
+LICENSE = "This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version."
diff --git a/src/ZapUtils.py b/src/ZapUtils.py
new file mode 100644
index 0000000..d80dfbc
--- /dev/null
+++ b/src/ZapUtils.py
@@ -0,0 +1,53 @@
+# !/usr/bin/python
+# coding=utf-8
+#
+# Copyright (C) 2018-2024 by dream-alpha
+#
+# In case of reuse of this source code please do not remove this copyright.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# For more information on the GNU General Public License see:
+# .
+
+
+from Screens.InfoBar import InfoBar
+from Screens.ChannelSelection import service_types_tv
+from enigma import eServiceCenter, eServiceReference
+from .Debug import logger
+
+
+def Zap_Service(strservice):
+ logger.info("strservice: %s", strservice)
+ if strservice:
+ service = eServiceReference(str(strservice))
+ if service:
+ allservice = eServiceReference("%s ORDER BY name" % (service_types_tv))
+ serviceHandler = eServiceCenter.getInstance()
+ bouquet_root = InfoBar.instance.servicelist.bouquet_root
+ bouquet = bouquet_root
+ bouquetlist = serviceHandler.list(bouquet_root)
+ if bouquetlist is not None:
+ while True:
+ bouquet = bouquetlist.getNext()
+ if not bouquet.valid():
+ bouquet = allservice
+ break
+ currlist = serviceHandler.list(bouquet)
+ if (currlist is not None) and (strservice in currlist.getContent("S", True)):
+ break
+ if InfoBar.instance.servicelist.getRoot() != bouquet: # already in correct bouquet?
+ InfoBar.instance.servicelist.clearPath()
+ if bouquet_root != bouquet:
+ InfoBar.instance.servicelist.enterPath(bouquet_root)
+ InfoBar.instance.servicelist.enterPath(bouquet)
+ InfoBar.instance.servicelist.setCurrentSelection(service) # select the service in servicelist
+ InfoBar.instance.servicelist.zap()
diff --git a/src/__init__.py b/src/__init__.py
new file mode 100644
index 0000000..edcc6e0
--- /dev/null
+++ b/src/__init__.py
@@ -0,0 +1,47 @@
+#!/usr/bin/python
+# coding=utf-8
+#
+# Copyright (C) 2018-2024 by dream-alpha
+#
+# In case of reuse of this source code please do not remove this copyright.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# For more information on the GNU General Public License see:
+# .
+
+
+import os
+import gettext
+from Components.Language import language
+from Tools.Directories import resolveFilename, SCOPE_PLUGINS
+from .Version import PLUGIN
+from .Debug import initLogging
+
+
+def initLocale():
+ lang = language.getLanguage()[:2]
+ os.environ["LANGUAGE"] = lang
+ locale = resolveFilename(SCOPE_PLUGINS, "Extensions/" + PLUGIN + "/locale")
+ if not os.path.exists(locale):
+ locale = resolveFilename(SCOPE_PLUGINS, "SystemPlugins/" + PLUGIN + "/locale")
+ if os.path.exists(locale):
+ gettext.bindtextdomain(PLUGIN, locale)
+
+
+def _(txt):
+ translation = gettext.dgettext(PLUGIN, txt)
+ return translation
+
+
+initLogging()
+initLocale()
+language.addCallback(initLocale)
diff --git a/src/keymap.xml b/src/keymap.xml
new file mode 100644
index 0000000..d79ffe0
--- /dev/null
+++ b/src/keymap.xml
@@ -0,0 +1,21 @@
+
+
+
diff --git a/src/locale/de/LC_MESSAGES/TVMagazineCockpit.mo b/src/locale/de/LC_MESSAGES/TVMagazineCockpit.mo
new file mode 100644
index 0000000..200d375
Binary files /dev/null and b/src/locale/de/LC_MESSAGES/TVMagazineCockpit.mo differ
diff --git a/src/plugin.png b/src/plugin.png
new file mode 100644
index 0000000..1553d8e
Binary files /dev/null and b/src/plugin.png differ
diff --git a/src/plugin.py b/src/plugin.py
new file mode 100644
index 0000000..8d13573
--- /dev/null
+++ b/src/plugin.py
@@ -0,0 +1,99 @@
+# !/usr/bin/python
+# coding=utf-8
+#
+# Copyright (C) 2018-2024 by dream-alpha
+#
+# In case of reuse of this source code please do not remove this copyright.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# For more information on the GNU General Public License see:
+# .
+
+
+from Plugins.Plugin import PluginDescriptor
+from .ConfigInit import ConfigInit
+from .SkinUtils import loadPluginSkin
+from .Debug import logger
+from .Version import VERSION
+from . import _
+from .TVMagazineCockpit import TVMagazineCockpit
+# from .PluginUtils import WHERE_TVMAGAZINE_SEARCH
+# from .Search import Search
+
+
+# def search(session, query, **__kwargs):
+# Search(session, query)
+
+
+# def searchEvent(session, event="", service="", **_kwargs):
+# logger.info("...")
+# if not service:
+# service = session.nav.getCurrentService()
+# info = service.info()
+# if not event:
+# event = info.getEvent(0) # 0 = now, 1 = next
+# event_name = event and event.getEventName() or info.getName() or ""
+# logger.info("event_name: %s", event_name)
+# Search(session, event_name)
+
+
+def main(session, **kwargs):
+ logger.info("...")
+ TVMagazineCockpit(session, **kwargs)
+
+
+def autoStart(reason, **kwargs):
+ if reason == 0: # startup
+ if "session" in kwargs:
+ logger.info("+++ Version: %s starts...", VERSION)
+ loadPluginSkin("skin.xml")
+ elif reason == 1: # shutdown
+ logger.info("--- shutdown")
+ else:
+ logger.info("reason not handled: %s", reason)
+
+
+def Plugins(**__kwargs):
+ logger.info("...")
+ ConfigInit()
+ return [
+ PluginDescriptor(
+ where=[
+ PluginDescriptor.WHERE_AUTOSTART,
+ PluginDescriptor.WHERE_SESSIONSTART
+ ],
+ fnc=autoStart
+ ),
+ PluginDescriptor(
+ name="TVMagazineCockpit",
+ where=PluginDescriptor.WHERE_PLUGINMENU,
+ icon="TVMagazineCockpit.png",
+ description=_("Browse TV Magazine"),
+ fnc=main
+ ),
+ # PluginDescriptor(
+ # name=_("TVMagazineCockpit"),
+ # description=_("TVMagazine Event Infos"),
+ # where=[
+ # PluginDescriptor.WHERE_EPG_SELECTION_SINGLE_BLUE,
+ # PluginDescriptor.WHERE_EVENTINFO,
+ # PluginDescriptor.WHERE_EVENTVIEW,
+ # ],
+ # fnc=searchEvent
+ # ),
+ # PluginDescriptor(
+ # name=_("TVMagazineCockpit"),
+ # description=_("TVMagazineCockpit Event Infos"),
+ # where=WHERE_TVMAGAZINE_SEARCH,
+ # fnc=search
+ # ),
+ ]
diff --git a/src/skin/Default-FHD/Makefile.am b/src/skin/Default-FHD/Makefile.am
new file mode 100644
index 0000000..164b525
--- /dev/null
+++ b/src/skin/Default-FHD/Makefile.am
@@ -0,0 +1,2 @@
+installdir = $(libdir)/enigma2/python/Plugins/Extensions/TVMagazineCockpit/skin/Default-FHD
+install_DATA = skin.xml screenpart_program_template.tpl
diff --git a/src/skin/Default-FHD/colors.xmlinc b/src/skin/Default-FHD/colors.xmlinc
new file mode 100644
index 0000000..239e7c9
--- /dev/null
+++ b/src/skin/Default-FHD/colors.xmlinc
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/skin/Default-FHD/screenpart_program_template.tpl b/src/skin/Default-FHD/screenpart_program_template.tpl
new file mode 100644
index 0000000..cdea211
--- /dev/null
+++ b/src/skin/Default-FHD/screenpart_program_template.tpl
@@ -0,0 +1 @@
+{"template":[MultiContentEntryText(pos=(5,7),size=(55,23),font=1,flags=RT_HALIGN_LEFT,text=0,backcolor=None),MultiContentEntryText(pos=(65,5),size=(245,75),font=0,flags=RT_HALIGN_LEFT|RT_WRAP,text=1,backcolor=None),MultiContentEntryText(pos=(65,87),size=(245,23),font=1,flags=RT_HALIGN_LEFT|RT_WRAP,text=2,color=0xa0a0a0,color_sel=0xa0a0a0,backcolor=None),MultiContentEntryText(pos=(65,115),size=(245,23),font=1,flags=RT_HALIGN_LEFT|RT_WRAP,text=3,color=0xa0a0a0,color_sel=0xa0a0a0,backcolor=None),MultiContentEntryText(pos=(0,0),size=(320,140),font=1,flags=RT_VALIGN_CENTER,text="",border_width=1,border_color=0x595959),],"itemHeight":140,"selectionEnabled":False,"fonts":[gFont("Regular",23),gFont("Regular",20),gFont("Regular",17)]}
\ No newline at end of file
diff --git a/src/skin/Default-FHD/skin.xml b/src/skin/Default-FHD/skin.xml
new file mode 100644
index 0000000..b67f350
--- /dev/null
+++ b/src/skin/Default-FHD/skin.xml
@@ -0,0 +1,104 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Format:%A, %d. %B - %H:%M
+
+
+ {"templates": {"default":(40,[ MultiContentEntryText(pos=(5,0),size=(1000,40),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=0), MultiContentEntryText(pos=(500,0),size=(500,40),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=1,color=0xa0a0a0), ]), "channel_bouquet":(40,[ MultiContentEntryText(pos=(5,0),size=(350,40),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=0, backcolor=None), MultiContentEntryText(pos=(360,0),size=(350,40),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=1, backcolor=None), MultiContentEntryText(pos=(720,0),size=(350,40),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=2, backcolor=None), MultiContentEntryText(pos=(1080,0),size=(350,40),font=1,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=3, backcolor=None), MultiContentEntryText(pos=(1440,0),size=(350,40),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=4, backcolor=None), MultiContentEntryText(pos=(355,0),size=(1,40),font=0,flags=RT_VALIGN_CENTER,text="", backcolor=0xa0a0a0), MultiContentEntryText(pos=(715,0),size=(1,40),font=0,flags=RT_VALIGN_CENTER,text="", backcolor=0xa0a0a0), MultiContentEntryText(pos=(1075,0),size=(1,40),font=0,flags=RT_VALIGN_CENTER,text="", backcolor=0xa0a0a0), MultiContentEntryText(pos=(1435,0),size=(1,40),font=0,flags=RT_VALIGN_CENTER,text="", backcolor=0xa0a0a0), ]) }, "fonts": [gFont("Regular",25),gFont("Regular",20)], itemHeight":40 }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Date
+
+
+ Default
+
+
+
+
+
+
+
diff --git a/src/skin/Default-HD/Makefile.am b/src/skin/Default-HD/Makefile.am
new file mode 100644
index 0000000..f366176
--- /dev/null
+++ b/src/skin/Default-HD/Makefile.am
@@ -0,0 +1,2 @@
+installdir = $(libdir)/enigma2/python/Plugins/Extensions/TVMagazineCockpit/skin/Default-HD
+install_DATA = skin.xml screenpart_program_template.tpl
diff --git a/src/skin/Default-HD/colors.xmlinc b/src/skin/Default-HD/colors.xmlinc
new file mode 100644
index 0000000..239e7c9
--- /dev/null
+++ b/src/skin/Default-HD/colors.xmlinc
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/skin/Default-HD/screenpart_program_template.tpl b/src/skin/Default-HD/screenpart_program_template.tpl
new file mode 100644
index 0000000..043e9e7
--- /dev/null
+++ b/src/skin/Default-HD/screenpart_program_template.tpl
@@ -0,0 +1 @@
+{"template":[MultiContentEntryText(pos=(3,5),size=(37,15),font=1,flags=RT_HALIGN_LEFT,text=0,backcolor=None),MultiContentEntryText(pos=(43,3),size=(163,50),font=0,flags=RT_HALIGN_LEFT|RT_WRAP,text=1,backcolor=None),MultiContentEntryText(pos=(43,58),size=(163,15),font=1,flags=RT_HALIGN_LEFT|RT_WRAP,text=2,color=0xa0a0a0,color_sel=0xa0a0a0,backcolor=None),MultiContentEntryText(pos=(43,77),size=(163,15),font=1,flags=RT_HALIGN_LEFT|RT_WRAP,text=3,color=0xa0a0a0,color_sel=0xa0a0a0,backcolor=None),MultiContentEntryText(pos=(0,0),size=(213,93),font=1,flags=RT_VALIGN_CENTER,text="",border_width=1,border_color=0x595959),],"itemHeight":93,"selectionEnabled":False,"fonts":[gFont("Regular",15),gFont("Regular",13),gFont("Regular",11)]}
\ No newline at end of file
diff --git a/src/skin/Default-HD/skin.xml b/src/skin/Default-HD/skin.xml
new file mode 100644
index 0000000..b86a01b
--- /dev/null
+++ b/src/skin/Default-HD/skin.xml
@@ -0,0 +1,104 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Format:%A, %d. %B - %H:%M
+
+
+ {"templates":{"default":(27,[MultiContentEntryText(pos=(3,0),size=(667,27),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=0),MultiContentEntryText(pos=(333,0),size=(333,27),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=1,color=0xa0a0a0),]),"channel_bouquet":(27,[MultiContentEntryText(pos=(3,0),size=(233,27),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=0,backcolor=None),MultiContentEntryText(pos=(240,0),size=(233,27),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=1,backcolor=None),MultiContentEntryText(pos=(480,0),size=(233,27),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=2,backcolor=None),MultiContentEntryText(pos=(720,0),size=(233,27),font=1,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=3,backcolor=None),MultiContentEntryText(pos=(960,0),size=(233,27),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=4,backcolor=None),MultiContentEntryText(pos=(237,0),size=(1,27),font=0,flags=RT_VALIGN_CENTER,text="",backcolor=0xa0a0a0),MultiContentEntryText(pos=(477,0),size=(1,27),font=0,flags=RT_VALIGN_CENTER,text="",backcolor=0xa0a0a0),MultiContentEntryText(pos=(717,0),size=(1,27),font=0,flags=RT_VALIGN_CENTER,text="",backcolor=0xa0a0a0),MultiContentEntryText(pos=(957,0),size=(1,27),font=0,flags=RT_VALIGN_CENTER,text="",backcolor=0xa0a0a0),])},"fonts":[gFont("Regular",17),gFont("Regular",13)],itemHeight":40}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Date
+
+
+ Default
+
+
+
+
+
+
+
diff --git a/src/skin/Default-WQHD/Makefile.am b/src/skin/Default-WQHD/Makefile.am
new file mode 100644
index 0000000..ce9a5fa
--- /dev/null
+++ b/src/skin/Default-WQHD/Makefile.am
@@ -0,0 +1,2 @@
+installdir = $(libdir)/enigma2/python/Plugins/Extensions/TVMagazineCockpit/skin/Default-WQHD
+install_DATA = skin.xml screenpart_program_template.tpl
diff --git a/src/skin/Default-WQHD/colors.xmlinc b/src/skin/Default-WQHD/colors.xmlinc
new file mode 100644
index 0000000..23b5d66
--- /dev/null
+++ b/src/skin/Default-WQHD/colors.xmlinc
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/skin/Default-WQHD/screen_ChannelManagement.xmlinc b/src/skin/Default-WQHD/screen_ChannelManagement.xmlinc
new file mode 100755
index 0000000..777d680
--- /dev/null
+++ b/src/skin/Default-WQHD/screen_ChannelManagement.xmlinc
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+ {"templates":{"default":(53,[MultiContentEntryText(pos=(7,0),size=(1333,53),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=0),MultiContentEntryText(pos=(667,0),size=(667,53),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=1,color=0xa0a0a0),]),"channel_bouquet":(53,[MultiContentEntryText(pos=(7,0),size=(467,53),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=0,backcolor=None),MultiContentEntryText(pos=(480,0),size=(467,53),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=1,backcolor=None),MultiContentEntryText(pos=(960,0),size=(467,53),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=2,backcolor=None),MultiContentEntryText(pos=(1440,0),size=(467,53),font=1,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=3,backcolor=None),MultiContentEntryText(pos=(1920,0),size=(467,53),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=4,backcolor=None),MultiContentEntryText(pos=(473,0),size=(1,53),font=0,flags=RT_VALIGN_CENTER,text="",backcolor=0xa0a0a0),MultiContentEntryText(pos=(953,0),size=(1,53),font=0,flags=RT_VALIGN_CENTER,text="",backcolor=0xa0a0a0),MultiContentEntryText(pos=(1433,0),size=(1,53),font=0,flags=RT_VALIGN_CENTER,text="",backcolor=0xa0a0a0),MultiContentEntryText(pos=(1913,0),size=(1,53),font=0,flags=RT_VALIGN_CENTER,text="",backcolor=0xa0a0a0),])},"fonts":[gFont("Regular",33),gFont("Regular",27)],"itemHeight":53}
+
+
+
+
+
diff --git a/src/skin/Default-WQHD/screen_ConfigScreen.xmlinc b/src/skin/Default-WQHD/screen_ConfigScreen.xmlinc
new file mode 100644
index 0000000..1cbc524
--- /dev/null
+++ b/src/skin/Default-WQHD/screen_ConfigScreen.xmlinc
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/src/skin/Default-WQHD/screen_EventDetails.xmlinc b/src/skin/Default-WQHD/screen_EventDetails.xmlinc
new file mode 100755
index 0000000..e877711
--- /dev/null
+++ b/src/skin/Default-WQHD/screen_EventDetails.xmlinc
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/src/skin/Default-WQHD/screen_ProgramColumns.xmlinc b/src/skin/Default-WQHD/screen_ProgramColumns.xmlinc
new file mode 100644
index 0000000..a4327b6
--- /dev/null
+++ b/src/skin/Default-WQHD/screen_ProgramColumns.xmlinc
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/src/skin/Default-WQHD/screenpart_ProgramColumnsPrime.xmlinc b/src/skin/Default-WQHD/screenpart_ProgramColumnsPrime.xmlinc
new file mode 100644
index 0000000..05acd9c
--- /dev/null
+++ b/src/skin/Default-WQHD/screenpart_ProgramColumnsPrime.xmlinc
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/skin/Default-WQHD/screenpart_program_template.tpl b/src/skin/Default-WQHD/screenpart_program_template.tpl
new file mode 100644
index 0000000..e42ce7e
--- /dev/null
+++ b/src/skin/Default-WQHD/screenpart_program_template.tpl
@@ -0,0 +1 @@
+{"template":[MultiContentEntryText(pos=(7,9),size=(73,31),font=1,flags=RT_HALIGN_LEFT,text=0,backcolor=None),MultiContentEntryText(pos=(87,7),size=(327,100),font=0,flags=RT_HALIGN_LEFT|RT_WRAP,text=1,backcolor=None),MultiContentEntryText(pos=(87,116),size=(327,31),font=1,flags=RT_HALIGN_LEFT|RT_WRAP,text=2,color=0xa0a0a0,color_sel=0xa0a0a0,backcolor=None),MultiContentEntryText(pos=(87,153),size=(327,31),font=1,flags=RT_HALIGN_LEFT|RT_WRAP,text=3,color=0xa0a0a0,color_sel=0xa0a0a0,backcolor=None),MultiContentEntryText(pos=(0,0),size=(427,187),font=1,flags=RT_VALIGN_CENTER,text="",border_width=1,border_color=0x595959),],"itemHeight":187,"selectionEnabled":False,"fonts":[gFont("Regular",31),gFont("Regular",27),gFont("Regular",23)]}
\ No newline at end of file
diff --git a/src/skin/Default-WQHD/skin.xml b/src/skin/Default-WQHD/skin.xml
new file mode 100644
index 0000000..bab9f29
--- /dev/null
+++ b/src/skin/Default-WQHD/skin.xml
@@ -0,0 +1,108 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {"templates":{"default":(53,[MultiContentEntryText(pos=(7,0),size=(1333,53),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=0),MultiContentEntryText(pos=(667,0),size=(667,53),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=1,color=0xa0a0a0),]),"channel_bouquet":(53,[MultiContentEntryText(pos=(7,0),size=(467,53),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=0,backcolor=None),MultiContentEntryText(pos=(480,0),size=(467,53),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=1,backcolor=None),MultiContentEntryText(pos=(960,0),size=(467,53),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=2,backcolor=None),MultiContentEntryText(pos=(1440,0),size=(467,53),font=1,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=3,backcolor=None),MultiContentEntryText(pos=(1920,0),size=(467,53),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=4,backcolor=None),MultiContentEntryText(pos=(473,0),size=(1,53),font=0,flags=RT_VALIGN_CENTER,text="",backcolor=0xa0a0a0),MultiContentEntryText(pos=(953,0),size=(1,53),font=0,flags=RT_VALIGN_CENTER,text="",backcolor=0xa0a0a0),MultiContentEntryText(pos=(1433,0),size=(1,53),font=0,flags=RT_VALIGN_CENTER,text="",backcolor=0xa0a0a0),MultiContentEntryText(pos=(1913,0),size=(1,53),font=0,flags=RT_VALIGN_CENTER,text="",backcolor=0xa0a0a0),])},"fonts":[gFont("Regular",33),gFont("Regular",27)],"itemHeight":53}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/skin/Makefile.am b/src/skin/Makefile.am
new file mode 100644
index 0000000..6bbf689
--- /dev/null
+++ b/src/skin/Makefile.am
@@ -0,0 +1,2 @@
+SUBDIRS = images Default-HD Default-FHD Default-WQHD Other-WQHD Shadow-FHD
+install_DATA = skin.xml *.tpl
diff --git a/src/skin/Other-WQHD/Makefile.am b/src/skin/Other-WQHD/Makefile.am
new file mode 100644
index 0000000..582addd
--- /dev/null
+++ b/src/skin/Other-WQHD/Makefile.am
@@ -0,0 +1,2 @@
+installdir = $(libdir)/enigma2/python/Plugins/Extensions/TVMagazineCockpit/skin/Other-WQHD
+install_DATA = skin.xml screenpart_program_template.tpl
diff --git a/src/skin/Other-WQHD/colors.xmlinc b/src/skin/Other-WQHD/colors.xmlinc
new file mode 100644
index 0000000..88b18fa
--- /dev/null
+++ b/src/skin/Other-WQHD/colors.xmlinc
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/skin/Other-WQHD/screenpart_program_template.tpl b/src/skin/Other-WQHD/screenpart_program_template.tpl
new file mode 100644
index 0000000..e42ce7e
--- /dev/null
+++ b/src/skin/Other-WQHD/screenpart_program_template.tpl
@@ -0,0 +1 @@
+{"template":[MultiContentEntryText(pos=(7,9),size=(73,31),font=1,flags=RT_HALIGN_LEFT,text=0,backcolor=None),MultiContentEntryText(pos=(87,7),size=(327,100),font=0,flags=RT_HALIGN_LEFT|RT_WRAP,text=1,backcolor=None),MultiContentEntryText(pos=(87,116),size=(327,31),font=1,flags=RT_HALIGN_LEFT|RT_WRAP,text=2,color=0xa0a0a0,color_sel=0xa0a0a0,backcolor=None),MultiContentEntryText(pos=(87,153),size=(327,31),font=1,flags=RT_HALIGN_LEFT|RT_WRAP,text=3,color=0xa0a0a0,color_sel=0xa0a0a0,backcolor=None),MultiContentEntryText(pos=(0,0),size=(427,187),font=1,flags=RT_VALIGN_CENTER,text="",border_width=1,border_color=0x595959),],"itemHeight":187,"selectionEnabled":False,"fonts":[gFont("Regular",31),gFont("Regular",27),gFont("Regular",23)]}
\ No newline at end of file
diff --git a/src/skin/Other-WQHD/skin.xml b/src/skin/Other-WQHD/skin.xml
new file mode 100644
index 0000000..7ec262d
--- /dev/null
+++ b/src/skin/Other-WQHD/skin.xml
@@ -0,0 +1,104 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Format:%A, %d. %B - %H:%M
+
+
+ {"templates":{"default":(53,[MultiContentEntryText(pos=(7,0),size=(1333,53),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=0),MultiContentEntryText(pos=(667,0),size=(667,53),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=1,color=0xa0a0a0),]),"channel_bouquet":(53,[MultiContentEntryText(pos=(7,0),size=(467,53),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=0,backcolor=None),MultiContentEntryText(pos=(480,0),size=(467,53),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=1,backcolor=None),MultiContentEntryText(pos=(960,0),size=(467,53),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=2,backcolor=None),MultiContentEntryText(pos=(1440,0),size=(467,53),font=1,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=3,backcolor=None),MultiContentEntryText(pos=(1920,0),size=(467,53),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=4,backcolor=None),MultiContentEntryText(pos=(473,0),size=(1,53),font=0,flags=RT_VALIGN_CENTER,text="",backcolor=0xa0a0a0),MultiContentEntryText(pos=(953,0),size=(1,53),font=0,flags=RT_VALIGN_CENTER,text="",backcolor=0xa0a0a0),MultiContentEntryText(pos=(1433,0),size=(1,53),font=0,flags=RT_VALIGN_CENTER,text="",backcolor=0xa0a0a0),MultiContentEntryText(pos=(1913,0),size=(1,53),font=0,flags=RT_VALIGN_CENTER,text="",backcolor=0xa0a0a0),])},"fonts":[gFont("Regular",33),gFont("Regular",27)],itemHeight":40}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Date
+
+
+ Default
+
+
+
+
+
+
+
diff --git a/src/skin/Shadow-FHD/Makefile.am b/src/skin/Shadow-FHD/Makefile.am
new file mode 100644
index 0000000..9fdb498
--- /dev/null
+++ b/src/skin/Shadow-FHD/Makefile.am
@@ -0,0 +1,2 @@
+installdir = $(libdir)/enigma2/python/Plugins/Extensions/TVMagazineCockpit/skin/Shadow-FHD
+install_DATA = skin.xml screenpart_program_template.tpl
diff --git a/src/skin/Shadow-FHD/colors.xmlinc b/src/skin/Shadow-FHD/colors.xmlinc
new file mode 100644
index 0000000..218bc31
--- /dev/null
+++ b/src/skin/Shadow-FHD/colors.xmlinc
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/skin/Shadow-FHD/screen_ChannelManagement.xmlinc b/src/skin/Shadow-FHD/screen_ChannelManagement.xmlinc
new file mode 100755
index 0000000..cdceddf
--- /dev/null
+++ b/src/skin/Shadow-FHD/screen_ChannelManagement.xmlinc
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+ {"templates":
+ {"default":(40,[
+ MultiContentEntryText(pos=(5,0),size=(1000,40),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=0),
+ MultiContentEntryText(pos=(500,0),size=(500,40),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=1,color=0xa0a0a0),
+ ]),
+ "channel_bouquet":(40,[
+ MultiContentEntryText(pos=(5,0),size=(350,40),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=0, backcolor=None),
+ MultiContentEntryText(pos=(360,0),size=(350,40),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=1, backcolor=None),
+ MultiContentEntryText(pos=(720,0),size=(350,40),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=2, backcolor=None),
+ MultiContentEntryText(pos=(1080,0),size=(350,40),font=1,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=3, backcolor=None),
+ MultiContentEntryText(pos=(1440,0),size=(350,40),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=4, backcolor=None),
+ MultiContentEntryText(pos=(355,0),size=(1,40),font=0,flags=RT_VALIGN_CENTER,text="", backcolor=0xa0a0a0),
+ MultiContentEntryText(pos=(715,0),size=(1,40),font=0,flags=RT_VALIGN_CENTER,text="", backcolor=0xa0a0a0),
+ MultiContentEntryText(pos=(1075,0),size=(1,40),font=0,flags=RT_VALIGN_CENTER,text="", backcolor=0xa0a0a0),
+ MultiContentEntryText(pos=(1435,0),size=(1,40),font=0,flags=RT_VALIGN_CENTER,text="", backcolor=0xa0a0a0),
+ ])
+ },
+ "fonts": [gFont("Regular",25),gFont("Regular",20)],
+ "itemHeight": 40
+ }
+
+
+
+
+
+
diff --git a/src/skin/Shadow-FHD/screen_ConfigScreen.xmlinc b/src/skin/Shadow-FHD/screen_ConfigScreen.xmlinc
new file mode 100644
index 0000000..9a76096
--- /dev/null
+++ b/src/skin/Shadow-FHD/screen_ConfigScreen.xmlinc
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/src/skin/Shadow-FHD/screen_EventDetails.xmlinc b/src/skin/Shadow-FHD/screen_EventDetails.xmlinc
new file mode 100755
index 0000000..ca8574b
--- /dev/null
+++ b/src/skin/Shadow-FHD/screen_EventDetails.xmlinc
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/src/skin/Shadow-FHD/screen_ProgramColumns.xmlinc b/src/skin/Shadow-FHD/screen_ProgramColumns.xmlinc
new file mode 100644
index 0000000..c001f31
--- /dev/null
+++ b/src/skin/Shadow-FHD/screen_ProgramColumns.xmlinc
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/src/skin/Shadow-FHD/screenpart_ProgramColumnsPrime.xmlinc b/src/skin/Shadow-FHD/screenpart_ProgramColumnsPrime.xmlinc
new file mode 100644
index 0000000..27bd2a0
--- /dev/null
+++ b/src/skin/Shadow-FHD/screenpart_ProgramColumnsPrime.xmlinc
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/skin/Shadow-FHD/screenpart_program_template.tpl b/src/skin/Shadow-FHD/screenpart_program_template.tpl
new file mode 100644
index 0000000..cdea211
--- /dev/null
+++ b/src/skin/Shadow-FHD/screenpart_program_template.tpl
@@ -0,0 +1 @@
+{"template":[MultiContentEntryText(pos=(5,7),size=(55,23),font=1,flags=RT_HALIGN_LEFT,text=0,backcolor=None),MultiContentEntryText(pos=(65,5),size=(245,75),font=0,flags=RT_HALIGN_LEFT|RT_WRAP,text=1,backcolor=None),MultiContentEntryText(pos=(65,87),size=(245,23),font=1,flags=RT_HALIGN_LEFT|RT_WRAP,text=2,color=0xa0a0a0,color_sel=0xa0a0a0,backcolor=None),MultiContentEntryText(pos=(65,115),size=(245,23),font=1,flags=RT_HALIGN_LEFT|RT_WRAP,text=3,color=0xa0a0a0,color_sel=0xa0a0a0,backcolor=None),MultiContentEntryText(pos=(0,0),size=(320,140),font=1,flags=RT_VALIGN_CENTER,text="",border_width=1,border_color=0x595959),],"itemHeight":140,"selectionEnabled":False,"fonts":[gFont("Regular",23),gFont("Regular",20),gFont("Regular",17)]}
\ No newline at end of file
diff --git a/src/skin/Shadow-FHD/skin.xml b/src/skin/Shadow-FHD/skin.xml
new file mode 100644
index 0000000..856b9d5
--- /dev/null
+++ b/src/skin/Shadow-FHD/skin.xml
@@ -0,0 +1,108 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {"templates": {"default":(40,[ MultiContentEntryText(pos=(5,0),size=(1000,40),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=0), MultiContentEntryText(pos=(500,0),size=(500,40),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=1,color=0xa0a0a0), ]), "channel_bouquet":(40,[ MultiContentEntryText(pos=(5,0),size=(350,40),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=0, backcolor=None), MultiContentEntryText(pos=(360,0),size=(350,40),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=1, backcolor=None), MultiContentEntryText(pos=(720,0),size=(350,40),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=2, backcolor=None), MultiContentEntryText(pos=(1080,0),size=(350,40),font=1,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=3, backcolor=None), MultiContentEntryText(pos=(1440,0),size=(350,40),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=4, backcolor=None), MultiContentEntryText(pos=(355,0),size=(1,40),font=0,flags=RT_VALIGN_CENTER,text="", backcolor=0xa0a0a0), MultiContentEntryText(pos=(715,0),size=(1,40),font=0,flags=RT_VALIGN_CENTER,text="", backcolor=0xa0a0a0), MultiContentEntryText(pos=(1075,0),size=(1,40),font=0,flags=RT_VALIGN_CENTER,text="", backcolor=0xa0a0a0), MultiContentEntryText(pos=(1435,0),size=(1,40),font=0,flags=RT_VALIGN_CENTER,text="", backcolor=0xa0a0a0), ]) }, "fonts": [gFont("Regular",25),gFont("Regular",20)], "itemHeight": 40 }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/skin/images/Makefile.am b/src/skin/images/Makefile.am
new file mode 100644
index 0000000..1ae8610
--- /dev/null
+++ b/src/skin/images/Makefile.am
@@ -0,0 +1,2 @@
+installdir = $(libdir)/enigma2/python/Plugins/Extensions/TVMagazineCockpit/images
+install_DATA = *.png *.svg
diff --git a/src/skin/images/default.png b/src/skin/images/default.png
new file mode 100755
index 0000000..593fa85
Binary files /dev/null and b/src/skin/images/default.png differ
diff --git a/src/skin/images/icon-video.png b/src/skin/images/icon-video.png
new file mode 100755
index 0000000..3fcc17c
Binary files /dev/null and b/src/skin/images/icon-video.png differ
diff --git a/src/skin/images/thumb0.svg b/src/skin/images/thumb0.svg
new file mode 100755
index 0000000..3c79685
--- /dev/null
+++ b/src/skin/images/thumb0.svg
@@ -0,0 +1,114 @@
+
+
+
+
diff --git a/src/skin/images/thumb1.svg b/src/skin/images/thumb1.svg
new file mode 100755
index 0000000..e4917bc
--- /dev/null
+++ b/src/skin/images/thumb1.svg
@@ -0,0 +1,144 @@
+
+
+
+
diff --git a/src/skin/images/thumb2.svg b/src/skin/images/thumb2.svg
new file mode 100755
index 0000000..72dbb55
--- /dev/null
+++ b/src/skin/images/thumb2.svg
@@ -0,0 +1,209 @@
+
+
+
+
diff --git a/src/skin/screen_ChannelManagement.xmlinc b/src/skin/screen_ChannelManagement.xmlinc
new file mode 100755
index 0000000..02a5491
--- /dev/null
+++ b/src/skin/screen_ChannelManagement.xmlinc
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+ Format:%A, %d. %B - %H:%M
+
+
+
+ {"templates":
+ {"default":(40,[
+ MultiContentEntryText(pos=(5,0),size=(1000,40),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=0),
+ MultiContentEntryText(pos=(500,0),size=(500,40),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=1,color=0xa0a0a0),
+ ]),
+ "channel_bouquet":(40,[
+ MultiContentEntryText(pos=(5,0),size=(350,40),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=0, backcolor=None),
+ MultiContentEntryText(pos=(360,0),size=(350,40),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=1, backcolor=None),
+ MultiContentEntryText(pos=(720,0),size=(350,40),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=2, backcolor=None),
+ MultiContentEntryText(pos=(1080,0),size=(350,40),font=1,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=3, backcolor=None),
+ MultiContentEntryText(pos=(1440,0),size=(350,40),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=4, backcolor=None),
+ MultiContentEntryText(pos=(355,0),size=(1,40),font=0,flags=RT_VALIGN_CENTER,text="", backcolor=0xa0a0a0),
+ MultiContentEntryText(pos=(715,0),size=(1,40),font=0,flags=RT_VALIGN_CENTER,text="", backcolor=0xa0a0a0),
+ MultiContentEntryText(pos=(1075,0),size=(1,40),font=0,flags=RT_VALIGN_CENTER,text="", backcolor=0xa0a0a0),
+ MultiContentEntryText(pos=(1435,0),size=(1,40),font=0,flags=RT_VALIGN_CENTER,text="", backcolor=0xa0a0a0),
+ ])
+ },
+ "fonts": [gFont("Regular",25),gFont("Regular",20)],
+ itemHeight":40
+ }
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/skin/screen_ConfigScreen.xmlinc b/src/skin/screen_ConfigScreen.xmlinc
new file mode 100644
index 0000000..87ec0c7
--- /dev/null
+++ b/src/skin/screen_ConfigScreen.xmlinc
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/src/skin/screen_EventDetails.xmlinc b/src/skin/screen_EventDetails.xmlinc
new file mode 100755
index 0000000..ed95dec
--- /dev/null
+++ b/src/skin/screen_EventDetails.xmlinc
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/src/skin/screen_ProgramColumns.xmlinc b/src/skin/screen_ProgramColumns.xmlinc
new file mode 100755
index 0000000..7fddbad
--- /dev/null
+++ b/src/skin/screen_ProgramColumns.xmlinc
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/src/skin/screenpart_1Button_icon.xmlinc b/src/skin/screenpart_1Button_icon.xmlinc
new file mode 100644
index 0000000..7fdff5f
--- /dev/null
+++ b/src/skin/screenpart_1Button_icon.xmlinc
@@ -0,0 +1 @@
+
diff --git a/src/skin/screenpart_1Button_name.xmlinc b/src/skin/screenpart_1Button_name.xmlinc
new file mode 100644
index 0000000..99ded21
--- /dev/null
+++ b/src/skin/screenpart_1Button_name.xmlinc
@@ -0,0 +1 @@
+
diff --git a/src/skin/screenpart_1Button_source.xmlinc b/src/skin/screenpart_1Button_source.xmlinc
new file mode 100644
index 0000000..7770d75
--- /dev/null
+++ b/src/skin/screenpart_1Button_source.xmlinc
@@ -0,0 +1 @@
+
diff --git a/src/skin/screenpart_4Buttons_icon.xmlinc b/src/skin/screenpart_4Buttons_icon.xmlinc
new file mode 100644
index 0000000..3494407
--- /dev/null
+++ b/src/skin/screenpart_4Buttons_icon.xmlinc
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/src/skin/screenpart_4Buttons_name.xmlinc b/src/skin/screenpart_4Buttons_name.xmlinc
new file mode 100644
index 0000000..478a313
--- /dev/null
+++ b/src/skin/screenpart_4Buttons_name.xmlinc
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/src/skin/screenpart_4Buttons_source.xmlinc b/src/skin/screenpart_4Buttons_source.xmlinc
new file mode 100644
index 0000000..1ad6074
--- /dev/null
+++ b/src/skin/screenpart_4Buttons_source.xmlinc
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/src/skin/screenpart_Background.xmlinc b/src/skin/screenpart_Background.xmlinc
new file mode 100644
index 0000000..73bed6f
--- /dev/null
+++ b/src/skin/screenpart_Background.xmlinc
@@ -0,0 +1,3 @@
+
+
+
diff --git a/src/skin/screenpart_ColorButtons.xmlinc b/src/skin/screenpart_ColorButtons.xmlinc
new file mode 100644
index 0000000..ed3e06a
--- /dev/null
+++ b/src/skin/screenpart_ColorButtons.xmlinc
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/src/skin/screenpart_ColorButtonsLabels.xmlinc b/src/skin/screenpart_ColorButtonsLabels.xmlinc
new file mode 100644
index 0000000..8babe13
--- /dev/null
+++ b/src/skin/screenpart_ColorButtonsLabels.xmlinc
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/src/skin/screenpart_DateTime.xmlinc b/src/skin/screenpart_DateTime.xmlinc
new file mode 100644
index 0000000..b25906a
--- /dev/null
+++ b/src/skin/screenpart_DateTime.xmlinc
@@ -0,0 +1,6 @@
+
+ Date
+
+
+ Default
+
diff --git a/src/skin/screenpart_EventDetailsPics.xmlinc b/src/skin/screenpart_EventDetailsPics.xmlinc
new file mode 100755
index 0000000..fe8a5ee
--- /dev/null
+++ b/src/skin/screenpart_EventDetailsPics.xmlinc
@@ -0,0 +1,2 @@
+
+
diff --git a/src/skin/screenpart_ProgramColumnsButtons.xmlinc b/src/skin/screenpart_ProgramColumnsButtons.xmlinc
new file mode 100755
index 0000000..2c3c109
--- /dev/null
+++ b/src/skin/screenpart_ProgramColumnsButtons.xmlinc
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/src/skin/screenpart_ProgramColumnsLists.xmlinc b/src/skin/screenpart_ProgramColumnsLists.xmlinc
new file mode 100755
index 0000000..96dcc58
--- /dev/null
+++ b/src/skin/screenpart_ProgramColumnsLists.xmlinc
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/src/skin/screenpart_ProgramColumnsPrime.xmlinc b/src/skin/screenpart_ProgramColumnsPrime.xmlinc
new file mode 100755
index 0000000..307d471
--- /dev/null
+++ b/src/skin/screenpart_ProgramColumnsPrime.xmlinc
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/skin/screenpart_TitleOnly.xmlinc b/src/skin/screenpart_TitleOnly.xmlinc
new file mode 100644
index 0000000..8360b2d
--- /dev/null
+++ b/src/skin/screenpart_TitleOnly.xmlinc
@@ -0,0 +1 @@
+
diff --git a/src/skin/screenpart_program_template.tpl b/src/skin/screenpart_program_template.tpl
new file mode 100644
index 0000000..c1f080d
--- /dev/null
+++ b/src/skin/screenpart_program_template.tpl
@@ -0,0 +1,16 @@
+{
+ "template": [
+ MultiContentEntryText(pos=(5,7),size=(55,23),font=1,flags=RT_HALIGN_LEFT,text=0,backcolor=None),
+ MultiContentEntryText(pos=(65,5),size=(245,75),font=0,flags=RT_HALIGN_LEFT|RT_WRAP,text=1,backcolor=None),
+ MultiContentEntryText(pos=(65,87),size=(245,23),font=1,flags=RT_HALIGN_LEFT|RT_WRAP,text=2,color=0xa0a0a0,color_sel=0xa0a0a0,backcolor=None),
+ MultiContentEntryText(pos=(65,115),size=(245,23),font=1,flags=RT_HALIGN_LEFT|RT_WRAP,text=3,color=0xa0a0a0,color_sel=0xa0a0a0,backcolor=None),
+ MultiContentEntryText(pos=(0,0),size=(320,140),font=1,flags=RT_VALIGN_CENTER,text="",border_width=1,border_color=0x595959),
+ ],
+ "itemHeight":140,
+ "selectionEnabled":False,
+ "fonts":[
+ gFont("Regular",23),
+ gFont("Regular",20),
+ gFont("Regular",17)
+ ]
+}
diff --git a/src/skin/skin_src.xml b/src/skin/skin_src.xml
new file mode 100644
index 0000000..fcc907e
--- /dev/null
+++ b/src/skin/skin_src.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/tvc1.png b/tvc1.png
new file mode 100755
index 0000000..888ca88
Binary files /dev/null and b/tvc1.png differ
diff --git a/tvc2.png b/tvc2.png
new file mode 100755
index 0000000..5283c76
Binary files /dev/null and b/tvc2.png differ