''',
- re.DOTALL).findall(response)
- for title, link, date, size, seeds, leechers in result:
- info = {}
- num = num - 1
- original_title = None
- year = 0
- img = ''
- size = size.replace(' ', ' ')
- date = self.stripHtml(date.replace(' ', ' '))
+ self.debug(response)
+ regex = '''
.+?">(.+?).+?
Uploaded (.+?), Size (.+?), .+?.+?(\d+?) | .+?
(\d+?) | '
+ for tr in re.compile(regex, re.DOTALL).findall(response):
+ result = re.compile(regex_tr, re.DOTALL).findall(tr)
+ self.debug(tr + ' -> ' + str(result))
+ if result:
+ (title, link, date, size, seeds, leechers) = result[0]
- # info
+ info = {}
+ num = num - 1
+ original_title = None
+ year = 0
+ img = ''
+ size = size.replace(' ', ' ')
+ date = self.stripHtml(date.replace(' ', ' '))
- info['label'] = info['title'] = self.unescape(title)
- info['link'] = link
- info['plot'] = info['title'] + '\r\n[I](%s) [S/L: %s/%s] [/I]\r\n%s' % (size, seeds, leechers, date)
- contentList.append((
- int(int(self.sourceWeight) * (int(num))),
- original_title, title, int(year), img, info,
- ))
+ # info
+
+ info['label'] = info['title'] = self.unescape(title)
+ info['link'] = link
+ self.log(info['link'])
+ info['plot'] = info['title'] + '\r\n[I](%s) [S/L: %s/%s] [/I]\r\n%s' % (size, seeds, leechers, date)
+ contentList.append((
+ int(int(self.sourceWeight) * (int(num))),
+ original_title, title, int(year), img, info,
+ ))
return contentList
diff --git a/resources/pyxbmct/__init__.py b/resources/contenters/__init__.py
similarity index 100%
rename from resources/pyxbmct/__init__.py
rename to resources/contenters/__init__.py
diff --git a/resources/contenters/CXZ.py b/resources/contenters/unused/CXZ.py
similarity index 100%
rename from resources/contenters/CXZ.py
rename to resources/contenters/unused/CXZ.py
diff --git a/resources/contenters/EZTV.py b/resources/contenters/unused/EZTV.py
similarity index 98%
rename from resources/contenters/EZTV.py
rename to resources/contenters/unused/EZTV.py
index 8cf2e13..5396b8c 100644
--- a/resources/contenters/EZTV.py
+++ b/resources/contenters/unused/EZTV.py
@@ -28,7 +28,7 @@ class EZTV(Content.Content):
'hot': ('Most Recent', '/', {'page': '/page_%d', 'increase': 1, 'second_page': 1}),
}
- baseurl = "https://eztv.ch"
+ baseurl = "https://eztv.ag"
headers = [('User-Agent',
'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.124' + \
' YaBrowser/14.10.2062.12061 Safari/537.36'),
diff --git a/resources/skins/__init__.py b/resources/contenters/unused/__init__.py
similarity index 100%
rename from resources/skins/__init__.py
rename to resources/contenters/unused/__init__.py
diff --git a/resources/language/English/strings.xml b/resources/language/English/strings.xml
index 8897896..cac403a 100644
--- a/resources/language/English/strings.xml
+++ b/resources/language/English/strings.xml
@@ -68,11 +68,24 @@
pyrrent2http (python-libtorrent via http)
Append size to file name
Enable DHT
+
Estuary (by DiMartino)
+
Стиль информации о раздаче
+
In the end
+
In the beginning
+
Second string
+
Arctic: Zephyr (by xbmc00)
Interface
P2P Network
Advanced
Torrent-client
Hentai (fine-tuning)
+
Search Window Mode
+
Enabled, hide old style
+
Enabled, replace old style
+
Enabled, optional
+
Disabled
+
Search Window Transparent Background
+
Disable Notifications
Save path
Call dialog
Default
diff --git a/resources/language/Hungarian/strings.xml b/resources/language/Hungarian/strings.xml
new file mode 100644
index 0000000..0eb3145
--- /dev/null
+++ b/resources/language/Hungarian/strings.xml
@@ -0,0 +1,97 @@
+
+
+ Kezelőfelület nyelve
+ Mappák nézetének lezárása
+ Ki
+ Fájlok mentése mappába (nem FAT32)
+ Magnet-linkek használata
+ Letöltött fájlok megtartása
+ Letöltött fájlok seedben tartása
+ Feltöltési sebességkorlát MBits/sec (0 - korlátlan)
+ Letöltési sebességkorlát MBits/sec (0 - korlátlan)
+ Csak rendszerszintű libtorrent használata
+ A következő epizód előtöltése és lejátszása
+ Metaadatok letöltése a Tartalmak Listájába
+ Hibakeresés (Fejlesztői Mód)
+ Confluence (by slng)
+ Transperency (by slng)
+ Confluence (by DiMartino)
+ Confluence (by RussakHH)
+ Keresési Előzmények engedélyezése
+ python-libtorrent
+ Ace Stream
+ P2P Lejátszó
+ Egyéb beállítások a programban - AceStream Client
+ Keresés időkorlátja
+ Rövid (10s)
+ Normál (20s)
+ Hosszú (30s)
+ Feliratok előtöltése az összes mappából
+ Seedben tartás megtekintés után
+ Kérdezzen rá a tárolóhely váltására lejátszás előtt
+ Orosz tartalmak törlése
+ Orosz tartalmak visszaállítása
+ Torrentre kattintás művelete
+ Torrent fájl megnyitása
+ Helyi menü megnyitása
+ Letöltés torrentkliensen keresztül
+ Letöltés python-libtorrenten keresztül
+ Keresések rendezése seed alapján
+ Egyéni keresési lehetőség kifejezésre
+ Titkosítás
+ Keresési szálak száma
+ Törölje a fájlokat
+ Mentse a fájlokat
+ Kérdezzen rá
+ Torrent2HTTP (libtorrent via http)
+ Proxy automatikus feloldása
+ Ki
+ Anti-zapret
+ Immunicity
+ Max. kapcsolatok (0 - korlátlan)
+ Véletlen port használata
+ Port a bejövő kapcsolatokhoz
+ Előtöltendő adat lejátszás előtt (MB)
+ Következő epizód automatikus lejátszása (vagy kérdezzen)
+ Eszköz konfiguráció
+ Átlagos/Jó PC
+ Átlag alatti PC/router
+ Tárolóhely legkisebb mérete automatikus tisztítás miatt (GB)
+ Videó szüneteltetése elindítás után
+ Keresési eredmények rendezése
+ Seed alapján
+ Ne rendezze
+ Név alapján
+ Ne adja Megtek. Előzm.-hez ennél kevesebb lejátszásnál (%)
+ Confluence (by safonov_ivan)
+ Aeon Nox (by joyrider)
+ pyrrent2http (python-libtorrent via http)
+ Méret mellékelése a fájl nevéhez
+ DHT engedélyezése
+ Kezelőfelület
+ P2P Hálózat
+ Haladó
+ Torrentkliens
+ Hentai (finomhangolás)
+ Mentési útvonal
+ Párbeszédablak
+ Alapértelmezett
+ Elérési út
+ Alkönyvtár készítése a leolvasó számára
+ Gazdagép
+ Port
+ URL
+ Felhasználónév
+ Jelszó
+ Torrentkliens
+ URL (csak No SSL)
+ Elérési út helyettesítése (csak távoli)
+ Bezár
+ Beállítások megnyitása
+ Torrentkliens Böngésző
+ Trackerek telepítése
+ Tracker beállítások
+ Tárolóhely tisztítása
+ Kereső választása
+ Nem rendelkezel külső keresővel. Kérlek, telepíts egyet.
+
diff --git a/resources/language/Russian/strings.xml b/resources/language/Russian/strings.xml
index fb67ec9..0d0603d 100644
--- a/resources/language/Russian/strings.xml
+++ b/resources/language/Russian/strings.xml
@@ -68,11 +68,24 @@
pyrrent2http (python-libtorrent по http)
Добавлять размер к имени файла
Включить DHT
+
Estuary (от DiMartino)
+
Стиль информации о раздаче
+
В конце
+
В начале
+
Второй строкой
+
Arctic: Zephyr (от xbmc00)
Интерфейс
P2P Сеть
Дополнительные
Торрент-клиент
Hentai (тонкая настр.)
+
Режим работы Окна Поиска
+
Включен, убрать старый вид
+
Включен, заменить старый вид
+
Включен, как опция
+
Отключен
+
Прозрачность Окна Поиска
+
Отключить Уведомления
Директория для сохранения файлов
Вызывать диалог
Задать по умолчанию
diff --git a/resources/language/spanish/strings.xml b/resources/language/spanish/strings.xml
new file mode 100644
index 0000000..b91427a
--- /dev/null
+++ b/resources/language/spanish/strings.xml
@@ -0,0 +1,110 @@
+
+
+ Idioma de la interfaz
+ Modo vista de carpetas
+ No fijar
+ Carpeta en la que guardar archivos (no FAT32)
+ Utilizar enlaces magnet
+ Almacenaje de archivos descargados
+ Seguir compartiendo archivos descargados
+ Máx. vel. de subida en Mbit/s (0 = ilimitada)
+ Máx. vel. de descarga en Mbit/s (0 = ilimitada)
+ Utilizar solo libtorrent
+ Lanzar descarga de episodio siguiente
+ Descargar metadatos para listas de contenido
+ Depuración (Modo desarrollador)
+ Confluence (de slng)
+ Transperency (de slng)
+ Confluence (de DiMartino)
+ Confluence (de RussakHH)
+ Habilitar el historial de búsquedas
+ python-libtorrent
+ Ace Stream
+ Reproductor P2P
+ Restablecer ajustes en Add-ons de programas -- AceStream client
+ Duración de las búsquedas
+ Breve (10 s)
+ Normal (20 s)
+ Larga (30 s)
+ Predescargar los subtítulos de todas las carpetas
+ Seguir compartiendo después de ver el vídeo
+ Preguntar para cambiar de almacén antes de la descarga
+ Eliminar material ruso
+ Restituir material ruso
+ Efecto de clic sobre torrent
+ Abrir archivo torrent
+ Abrir menú contextual
+ Descargar vía cliente BitTorrent
+ Descargar vía python-libtorrent
+ Ordenar resultados por fuentes
+ Términos para búsqueda personalizada
+ Cifrado
+ Número de hilos de búsqueda
+ Eliminar archivos
+ Guardar archivos
+ Preguntar para guardar
+ Torrent2HTTP (libtorrent vía HTTP)
+ Desbloqueo automático de proxy
+ Ninguno
+ Anti-zapret (antirestricción)
+ Inmunidad
+ Núm. máx. de conexiones (0 = ilimitadas)
+ Utilizar puertos aleatorios
+ Puerto para conexiones entrantes
+ Tamaño de precarga para empezar a reproducir (MB)
+ Autorreproducir episodio siguiente (o preguntar)
+ Configuración de dispositivo
+ Promedio/Buen PC
+ Por debajo de la media, PC/router
+ Tamaño mínimo de almacenaje para autoborrado (GB)
+ Diferir inicio del reproductor
+ Ordenar resultados de la búsqueda
+ Por fuentes
+ No ordenar
+ Por nombre
+ Añadir al historial de vistos después del (%)
+ Confluence (de safonov_ivan)
+ Aeon Nox (de joyrider)
+ pyrrent2http (python-libtorrent vía HTTP)
+ Añadir tamaño a nombre de archivo
+ Activar protocolo DHT
+ Estuary (de DiMartino)
+ Modo presentación de datos
+ Al final
+ Al principio
+ En segunda línea
+ Arctic: Zephyr (de xbmc00)
+ Interfaz
+ Red P2P
+ Avanzado
+ Cliente de BitTorrent
+ Hentai (reajustes)
+ Modo ventana de búsquedas
+ Activado ocultar estilo anterior
+ Activado remplazar estilo anterior
+ Activado opcional
+ Desactivado
+ Fondo transparente de ventana de búsquedas
+ Desactivar notificaciones
+ Ruta para guardar
+ Preguntar
+ Por defecto
+ Ruta
+ Crear subdirectorio para scrapper
+ Host
+ Puerto
+ URL
+ Usuario
+ Contraseña
+ Cliente de BitTorrent
+ URL (no SSL)
+ Sustitución de ruta (Solo remoto)
+ Cerrar
+ Abrir "Ajustes"
+ Navegador de cliente BitTorrent
+ Instalar rastreadores
+ Ajustes de rastreadores
+ Vaciar almacén
+ Seleccionar buscador
+ No hay buscador externo. Instale uno primero.
+
diff --git a/resources/proxy/antizapret.py b/resources/proxy/antizapret.py
index 0decbe2..eee5f43 100644
--- a/resources/proxy/antizapret.py
+++ b/resources/proxy/antizapret.py
@@ -1,66 +1,72 @@
# -*- coding: utf-8 -*-
-import os, re, fnmatch, threading, urllib2
+import os, re, fnmatch, threading, urllib2, time, shelve, anydbm
from contextlib import contextmanager, closing
from functions import log, debug, tempdir
-LOCKS = {}
PAC_URL = "http://antizapret.prostovpn.org/proxy.pac"
CACHE_DIR = tempdir()
USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.116 Safari/537.36"
+CONFIG_LOCK = threading.Lock()
if not os.path.exists(CACHE_DIR):
os.makedirs(CACHE_DIR)
-CACHE = 24 * 3600 # 24 hour caching
-
-#@contextmanager
-def shelf(filename, ttl=0):
- import shelve
- filename = os.path.join(CACHE_DIR, filename)
- with LOCKS.get(filename, threading.RLock()):
-# with closing(shelve.open(filename, writeback=True)) as d:
- d = shelve.open(filename, writeback=True)
- try:
- import time
- if not dict(d):
- d.update({
- "created_at": time.time(),
- "data": {},
- })
- elif ttl > 0 and (time.time() - d["created_at"]) > ttl:
- d["created_at"] = time.time()
- d["data"] = {}
- return d
- except:
- d.close()
- raise
-
-_config = {}
+CACHE_LIFETIME = 24 * 3600 # 24 hour caching
def config():
- global _config
- if not _config:
-# with shelf("antizapret.pac_config", ttl=CACHE) as pac_config:
- d = shelf("antizapret.pac_config2", ttl=CACHE)
- pac_config = d['data']
- if not pac_config:
- log("[antizapret]: Fetching Antizapret PAC file on %s" %PAC_URL)
- try:
- pac_data = urllib2.urlopen(PAC_URL).read()
- except:
- pac_data = ""
+ shelf = None
+ try:
+ CONFIG_LOCK.acquire()
+ filename = os.path.join(CACHE_DIR, "antizapret.pac_config2")
+ try:
+ shelf = shelve.open(filename)
+ except anydbm.error:
+ os.remove(filename)
+ shelf = shelve.open(filename)
- r = re.search(r"\"PROXY (.*); DIRECT", pac_data)
- if r:
- pac_config["server"] = r.group(1)
- pac_config["domains"] = map(lambda x: x.replace(r"\Z(?ms)", "").replace("\\", ""), map(fnmatch.translate, re.findall(r"\"(.*?)\",", pac_data)))
- else:
- pac_config["server"] = None
- pac_config["domains"] = []
- d.close()
- _config = pac_config
- return _config
+ created_at = 0
+ data = {}
+
+ if 'created_at' in shelf:
+ created_at = shelf['created_at']
+
+ if 'data' in shelf:
+ data = shelf['data']
+
+ if((time.time() - created_at) <= CACHE_LIFETIME
+ and 'domains' in data
+ and len(data['domains']) > 0):
+ return data
+
+ log("[antizapret]: Fetching Antizapret PAC file on %s" %PAC_URL)
+ try:
+ pac_data = urllib2.urlopen(PAC_URL).read()
+ except:
+ pac_data = ""
+
+ r = re.search(r"\"PROXY (.*); DIRECT", pac_data)
+ if r:
+ data["server"] = r.group(1)
+ data["domains"] = map(lambda x: x.replace(r"\Z(?ms)", "").replace("\\", ""), map(fnmatch.translate, re.findall(r"\"(.*?)\",", pac_data)))
+ else:
+ data["server"] = None
+ data["domains"] = []
+
+ shelf.clear()
+ shelf.update({
+ "created_at": time.time(),
+ "data": data,
+ })
+ return data
+ except Exception as ex:
+ debug("[antizapret]: " + str(ex))
+ raise
+ finally:
+ if shelf:
+ shelf.close()
+ if CONFIG_LOCK.locked():
+ CONFIG_LOCK.release()
class AntizapretProxyHandler(urllib2.ProxyHandler, object):
def __init__(self):
@@ -73,7 +79,8 @@ class AntizapretProxyHandler(urllib2.ProxyHandler, object):
def proxy_open(self, req, proxy, type):
import socket
- if socket.gethostbyname(req.get_host().split(":")[0]) in self.config["domains"]:
+ hostname = req.get_host().split(":")[0]
+ if socket.gethostbyname(hostname) in self.config["domains"] or hostname in self.config["domains"]:
debug("[antizapret]: Pass request through proxy " + self.config["server"])
return urllib2.ProxyHandler.proxy_open(self, req, self.config["server"], type)
@@ -104,5 +111,4 @@ def url_get(url, params={}, headers={}, post = None):
return data
except urllib2.HTTPError as e:
log("[antizapret]: HTTP Error(%s): %s" % (e.errno, e.strerror))
- return None
-
+ return None
\ No newline at end of file
diff --git a/resources/pyxbmct/addonwindow.py b/resources/pyxbmct/addonwindow.py
deleted file mode 100644
index c4825e9..0000000
--- a/resources/pyxbmct/addonwindow.py
+++ /dev/null
@@ -1,786 +0,0 @@
-# -*- coding: utf-8 -*-
-# This is a "local" version of PyXBMCt to be used in standalone addons.
-#
-# PyXBMCt is a mini-framework for creating XBMC Python addons with arbitrary UI
-# made of controls - decendants of xbmcgui.Control class.
-# The framework uses image textures from XBMC Confluence skin.
-#
-# Licence: GPL v.3 http://www.gnu.org/licenses/gpl.html
-#
-## @package addonwindow
-# PyXBMCt framework module
-
-import os
-
-import xbmc
-import xbmcgui
-
-
-# _addon = xbmcaddon.Addon()
-_images = os.path.join(os.path.dirname(__file__), 'textures', 'default')
-
-
-# Text alighnment constants. Mixed variants are obtained by bit OR (|)
-ALIGN_LEFT = 0
-ALIGN_RIGHT = 1
-ALIGN_CENTER_X = 2
-ALIGN_CENTER_Y = 4
-ALIGN_CENTER = 6
-ALIGN_TRUNCATED = 8
-ALIGN_JUSTIFY = 10
-
-# XBMC key action codes.
-# More codes at https://github.com/xbmc/xbmc/blob/master/xbmc/guilib/Key.h
-## ESC action
-ACTION_PREVIOUS_MENU = 10
-## Backspace action
-ACTION_NAV_BACK = 92
-## Left arrow key
-ACTION_MOVE_LEFT = 1
-## Right arrow key
-ACTION_MOVE_RIGHT = 2
-## Up arrow key
-ACTION_MOVE_UP = 3
-## Down arrow key
-ACTION_MOVE_DOWN = 4
-## Mouse wheel up
-ACTION_MOUSE_WHEEL_UP = 104
-## Mouse wheel down
-ACTION_MOUSE_WHEEL_DOWN = 105
-## Mouse drag
-ACTION_MOUSE_DRAG = 106
-## Mouse move
-ACTION_MOUSE_MOVE = 107
-
-
-def _set_textures(textures={}, kwargs={}):
- """Set texture arguments for controls."""
- for texture in textures.keys():
- try:
- kwargs[texture]
- except KeyError:
- kwargs[texture] = textures[texture]
-
-
-class AddonWindowError(Exception):
- """Custom exception."""
- pass
-
-
-class Label(xbmcgui.ControlLabel):
- """ControlLabel class.
-
- Parameters:
- label: string or unicode - text string.
- font: string - font used for label text. (e.g. 'font13')
- textColor: hexstring - color of enabled label's label. (e.g. '0xFFFFFFFF')
- disabledColor: hexstring - color of disabled label's label. (e.g. '0xFFFF3300')
- alignment: integer - alignment of label - *Note, see xbfont.h
- hasPath: bool - True=stores a path / False=no path.
- angle: integer - angle of control. (+ rotates CCW, - rotates CW)"
-
- Note:
- After you create the control, you need to add it to the window with placeControl().
-
- Example:
- self.label = Label('Status', angle=45)
- """
-
- def __new__(cls, *args, **kwargs):
- return super(Label, cls).__new__(cls, -10, -10, 1, 1, *args, **kwargs)
-
-
-class FadeLabel(xbmcgui.ControlFadeLabel):
- """Control that scrolls label text.
-
- Parameters:
- font: string - font used for label text. (e.g. 'font13')
- textColor: hexstring - color of fadelabel's labels. (e.g. '0xFFFFFFFF')
- _alignment: integer - alignment of label - *Note, see xbfont.h
-
- Note:
- After you create the control, you need to add it to the window with placeControl().
-
- Example:
- self.fadelabel = FadeLabel(textColor='0xFFFFFFFF')
- """
-
- def __new__(cls, *args, **kwargs):
- return super(FadeLabel, cls).__new__(cls, -10, -10, 1, 1, *args, **kwargs)
-
-
-class TextBox(xbmcgui.ControlTextBox):
- """ControlTextBox class.
-
- Parameters:
- font: string - font used for text. (e.g. 'font13')
- textColor: hexstring - color of textbox's text. (e.g. '0xFFFFFFFF')
-
- Note:
- After you create the control, you need to add it to the window with placeControl().
-
- Example:
- self.textbox = TextBox(textColor='0xFFFFFFFF')
- """
-
- def __new__(cls, *args, **kwargs):
- return super(TextBox, cls).__new__(cls, -10, -10, 1, 1, *args, **kwargs)
-
-
-class Image(xbmcgui.ControlImage):
- """ControlImage class.
-
- Parameters:
- filename: string - image filename.
- colorKey: hexString - (example, '0xFFFF3300')
- aspectRatio: integer - (values 0 = stretch (default), 1 = scale up (crops), 2 = scale down (black bars)
- colorDiffuse: hexString - (example, '0xC0FF0000' (red tint)).
-
- Note:
- After you create the control, you need to add it to the window with placeControl().
-
- Example:
- self.image = Image('d:\images\picture.jpg', aspectRatio=2)
- """
-
- def __new__(cls, *args, **kwargs):
- return super(Image, cls).__new__(cls, -10, -10, 1, 1, *args, **kwargs)
-
-
-class Button(xbmcgui.ControlButton):
- """ControlButton class.
-
- Parameters:
- label: string or unicode - text string.
- focusTexture: string - filename for focus texture.
- noFocusTexture: string - filename for no focus texture.
- textOffsetX: integer - x offset of label.
- textOffsetY: integer - y offset of label.
- alignment: integer - alignment of label - *Note, see xbfont.h
- font: string - font used for label text. (e.g. 'font13')
- textColor: hexstring - color of enabled button's label. (e.g. '0xFFFFFFFF')
- disabledColor: hexstring - color of disabled button's label. (e.g. '0xFFFF3300')
- angle: integer - angle of control. (+ rotates CCW, - rotates CW)
- shadowColor: hexstring - color of button's label's shadow. (e.g. '0xFF000000')
- focusedColor: hexstring - color of focused button's label. (e.g. '0xFF00FFFF')
-
- Note:
- After you create the control, you need to add it to the window with placeControl().
-
- Example:
- self.button = Button('Status', font='font14')
- """
-
- def __new__(cls, *args, **kwargs):
- textures = {'focusTexture': os.path.join(_images, 'Button', 'KeyboardKey.png'),
- 'noFocusTexture': os.path.join(_images, 'Button', 'KeyboardKeyNF.png')}
- _set_textures(textures, kwargs)
- try:
- kwargs['alignment']
- except KeyError:
- kwargs['alignment'] = ALIGN_CENTER
- return super(Button, cls).__new__(cls, -10, -10, 1, 1, *args, **kwargs)
-
-
-class RadioButton(xbmcgui.ControlRadioButton):
- """ControlRadioButton class.
-
- Parameters:
- label: string or unicode - text string.
- focusTexture: string - filename for focus texture.
- noFocusTexture: string - filename for no focus texture.
- textOffsetX: integer - x offset of label.
- textOffsetY: integer - y offset of label.
- _alignment: integer - alignment of label - *Note, see xbfont.h
- font: string - font used for label text. (e.g. 'font13')
- textColor: hexstring - color of enabled radio button's label. (e.g. '0xFFFFFFFF')
- disabledColor: hexstring - color of disabled radio button's label. (e.g. '0xFFFF3300')
- angle: integer - angle of control. (+ rotates CCW, - rotates CW)
- shadowColor: hexstring - color of radio button's label's shadow. (e.g. '0xFF000000')
- focusedColor: hexstring - color of focused radio button's label. (e.g. '0xFF00FFFF')
- focusOnTexture: string - filename for radio focused/checked texture.
- noFocusOnTexture: string - filename for radio not focused/checked texture.
- focusOffTexture: string - filename for radio focused/unchecked texture.
- noFocusOffTexture: string - filename for radio not focused/unchecked texture.
- Note: To customize RadioButton all 4 abovementioned textures need to be provided.
-
- Note:
- After you create the control, you need to add it to the window with placeControl().
-
- Example:
- self.radiobutton = RadioButton('Status', font='font14')
- """
-
- def __new__(cls, *args, **kwargs):
- if int(xbmc.getInfoLabel('System.BuildVersion')[:2]) >= 13:
- textures = {'focusTexture': os.path.join(_images, 'RadioButton', 'MenuItemFO.png'),
- 'noFocusTexture': os.path.join(_images, 'RadioButton', 'MenuItemNF.png'),
- 'focusOnTexture': os.path.join(_images, 'RadioButton', 'radiobutton-focus.png'),
- 'noFocusOnTexture': os.path.join(_images, 'RadioButton', 'radiobutton-focus.png'),
- 'focusOffTexture': os.path.join(_images, 'RadioButton', 'radiobutton-nofocus.png'),
- 'noFocusOffTexture': os.path.join(_images, 'RadioButton', 'radiobutton-nofocus.png')}
- else: # This is for compatibility with Frodo and earlier versions.
- textures = {'focusTexture': os.path.join(_images, 'RadioButton', 'MenuItemFO.png'),
- 'noFocusTexture': os.path.join(_images, 'RadioButton', 'MenuItemNF.png'),
- 'TextureRadioFocus': os.path.join(_images, 'RadioButton', 'radiobutton-focus.png'),
- 'TextureRadioNoFocus': os.path.join(_images, 'RadioButton', 'radiobutton-nofocus.png')}
- _set_textures(textures, kwargs)
- return super(RadioButton, cls).__new__(cls, -10, -10, 1, 1, *args, **kwargs)
-
-
-class Edit(xbmcgui.ControlEdit):
- """
- ControlEdit class.
-
- Edit(label[, font, textColor, disabledColor, alignment, focusTexture, noFocusTexture])
-
- Parameters:
- label : string or unicode - text string.
- font : [opt] string - font used for label text. (e.g. 'font13')
- textColor : [opt] hexstring - color of enabled label's label. (e.g. '0xFFFFFFFF')
- disabledColor : [opt] hexstring - color of disabled label's label. (e.g. '0xFFFF3300')
- _alignment : [opt] integer - alignment of label - *Note, see xbfont.h
- focusTexture : [opt] string - filename for focus texture.
- noFocusTexture : [opt] string - filename for no focus texture.
- isPassword : [opt] bool - if true, mask text value.
-
- *Note, You can use the above as keywords for arguments and skip certain optional arguments.
- Once you use a keyword, all following arguments require the keyword.
- After you create the control, you need to add it to the window with palceControl().
-
- example:
- - self.edit = Edit('Status')
- """
-
- def __new__(cls, *args, **kwargs):
- textures = {'focusTexture': os.path.join(_images, 'Edit', 'button-focus.png'),
- 'noFocusTexture': os.path.join(_images, 'Edit', 'black-back2.png')}
- _set_textures(textures, kwargs)
- return super(Edit, cls).__new__(cls, -10, -10, 1, 1, *args, **kwargs)
-
-
-class List(xbmcgui.ControlList):
- """ControlList class.
-
- Parameters:
- font: string - font used for items label. (e.g. 'font13')
- textColor: hexstring - color of items label. (e.g. '0xFFFFFFFF')
- buttonTexture: string - filename for no focus texture.
- buttonFocusTexture: string - filename for focus texture.
- selectedColor: integer - x offset of label.
- _imageWidth: integer - width of items icon or thumbnail.
- _imageHeight: integer - height of items icon or thumbnail.
- _itemTextXOffset: integer - x offset of items label.
- _itemTextYOffset: integer - y offset of items label.
- _itemHeight: integer - height of items.
- _space: integer - space between items.
- _alignmentY: integer - Y-axis alignment of items label - *Note, see xbfont.h
-
- Note:
- After you create the control, you need to add it to the window with placeControl().
-
- Example:
- self.cList = List('font14', space=5)
- """
-
- def __new__(cls, *args, **kwargs):
- textures = {'buttonTexture': os.path.join(_images, 'List', 'MenuItemNF.png'),
- 'buttonFocusTexture': os.path.join(_images, 'List', 'MenuItemFO.png')}
- _set_textures(textures, kwargs)
- return super(List, cls).__new__(cls, -10, -10, 1, 1, *args, **kwargs)
-
-
-class Slider(xbmcgui.ControlSlider):
- """ControlSlider class.
-
- Parameters:
- textureback: string - image filename.
- texture: string - image filename.
- texturefocus: string - image filename.
-
- Note:
- After you create the control, you need to add it to the window with placeControl().
-
- Example:
- self.slider = Slider()
- """
-
- def __new__(cls, *args, **kwargs):
- textures = {'textureback': os.path.join(_images, 'Slider', 'osd_slider_bg.png'),
- 'texture': os.path.join(_images, 'Slider', 'osd_slider_nibNF.png'),
- 'texturefocus': os.path.join(_images, 'Slider', 'osd_slider_nib.png')}
- _set_textures(textures, kwargs)
- return super(Slider, cls).__new__(cls, -10, -10, 1, 1, *args, **kwargs)
-
-
-class _AbstractWindow(object):
- """
- Top-level control window.
-
- The control windows serves as a parent widget for other XBMC UI controls
- much like Tkinter.Tk or PyQt QWidget class.
- This is an abstract class which is not supposed to be instantiated directly
- and will raise exeptions.
-
- This class is a basic "skeleton" for a control window.
- """
-
- def __init__(self):
- """Constructor method."""
- self.actions_connected = []
- self.controls_connected = []
-
- def setGeometry(self, width_, height_, rows_, columns_, pos_x=-1, pos_y=-1):
- """
- Set width, height, Grid layout, and coordinates (optional) for a new control window.
-
- Parameters:
- width_, height_: widgh and height of the created window.
- rows_, columns_: rows and colums of the Grid layout to place controls on.
- pos_x, pos_y (optional): coordinates of the top left corner of the window.
- If pos_x and pos_y are not privided, the window will be placed
- at the center of the screen.
- Example:
- self.setGeometry(400, 500, 5, 4)
- """
- self.width = width_
- self.height = height_
- self.rows = rows_
- self.columns = columns_
- if pos_x > 0 and pos_y > 0:
- self.x = pos_x
- self.y = pos_y
- else:
- self.x = 640 - self.width / 2
- self.y = 360 - self.height / 2
- self.setGrid()
-
- def setGrid(self):
- """
- Set window grid layout of rows * columns.
- This is a helper method not to be called directly.
- """
- self.grid_x = self.x
- self.grid_y = self.y
- self.tile_width = self.width / self.columns
- self.tile_height = self.height / self.rows
-
- def placeControl(self, control, row, column, rowspan=1, columnspan=1, pad_x=5, pad_y=5):
- """
- Place a control within the window grid layout.
-
- pad_x, pad_y: horisontal and vertical padding for control's
- size and aspect adjustments. Negative values can be used
- to make a control overlap with grid cells next to it, if necessary.
- Raises AddonWindowError if a grid has not yet been set.
- Example:
- self.placeControl(self.label, 0, 1)
- """
- try:
- control_x = (self.grid_x + self.tile_width * column) + pad_x
- control_y = (self.grid_y + self.tile_height * row) + pad_y
- control_width = self.tile_width * columnspan - 2 * pad_x
- control_height = self.tile_height * rowspan - 2 * pad_y
- except AttributeError:
- raise AddonWindowError('Window geometry is not defined! Call setGeometry first.')
- control.setPosition(control_x, control_y)
- control.setWidth(control_width)
- control.setHeight(control_height)
- self.addControl(control)
- self.setAnimation(control)
-
- def getX(self):
- """Get X coordinate of the top-left corner of the window."""
- try:
- return self.x
- except AttributeError:
- raise AddonWindowError('Window geometry is not defined! Call setGeometry first.')
-
- def getY(self):
- """Get Y coordinate of the top-left corner of the window."""
- try:
- return self.y
- except AttributeError:
- raise AddonWindowError('Window geometry is not defined! Call setGeometry first.')
-
- def getWindowWidth(self):
- """Get window width."""
- try:
- return self.width
- except AttributeError:
- raise AddonWindowError('Window geometry is not defined! Call setGeometry first.')
-
- def getWindowHeight(self):
- """Get window height."""
- try:
- return self.height
- except AttributeError:
- raise AddonWindowError('Window geometry is not defined! Call setGeometry first.')
-
- def getRows(self):
- """
- Get grid rows count.
- Raises AddonWindowError if a grid has not yet been set.
- """
- try:
- return self.rows
- except AttributeError:
- raise AddonWindowError('Grid layot is not set! Call setGeometry first.')
-
- def getColumns(self):
- """
- Get grid columns count.
- Raises AddonWindowError if a grid has not yet been set.
- """
- try:
- return self.columns
- except AttributeError:
- raise AddonWindowError('Grid layout is not set! Call setGeometry first.')
-
- def connect(self, event, function):
- """
- Connect an event to a function.
-
- An event can be an inctance of a Control object or an integer key action code.
- Several basic key action codes are provided by PyXBMCT. More action codes can be found at
- https://github.com/xbmc/xbmc/blob/master/xbmc/guilib/Key.h
-
- You can connect the following Controls: Button, RadioButton and List. Other Controls do not
- generate any control events when activated so their connections won't work.
- To catch Slider events you need to connect the following key actions:
- ACTION_MOVE_LEFT, ACTION_MOVE_RIGHT and ACTION_MOUSE_DRAG, and do a check
- whether the Slider is focused.
-
- "function" parameter is a function or a method to be executed. Note that you must provide
- a function object [without brackets ()], not a function call!
- lambda can be used as a function to call another function or method with parameters.
-
- Examples:
- self.connect(self.exit_button, self.close)
- or
- self.connect(ACTION_NAV_BACK, self.close)
- """
- try:
- self.disconnect(event)
- except AddonWindowError:
- if type(event) == int:
- self.actions_connected.append([event, function])
- else:
- self.controls_connected.append([event, function])
-
- def connectEventList(self, events, function):
- """
- Connect a list of controls/action codes to a function.
- See connect docstring for more info.
- """
- [self.connect(event, function) for event in events]
-
- def disconnect(self, event):
- """
- Disconnect an event from a function.
-
- An event can be an inctance of a Control object or an integer key action code
- which has previously been connected to a function or a method.
- Raises AddonWindowError if an event is not connected to any function.
-
- Examples:
- self.disconnect(self.exit_button)
- or
- self.disconnect(ACTION_NAV_BACK)
- """
- if type(event) == int:
- event_list = self.actions_connected
- else:
- event_list = self.controls_connected
- for index in range(len(event_list)):
- if event == event_list[index][0]:
- event_list.pop(index)
- break
- else:
- raise AddonWindowError('The action or control %s is not connected!' % event)
-
- def disconnectEventList(self, events):
- """
- Disconnect a list of controls/action codes from functions.
- See disconnect docstring for more info.
- Raises AddonWindowError if at least one event in the list
- is not connected to any function.
- """
- [self.disconnect(event) for event in events]
-
- def executeConnected(self, event, connected_list):
- """
- Execute a connected event (an action or a control).
- This is a helper method not to be called directly.
- """
- for item in connected_list:
- if event == item[0]:
- item[1]()
- break
-
- def setAnimation(self, control):
- """
- This method is called to set animation properties for all controls
- added to the current addon window instance - both built-in controls
- (window background, title bar etc.) and controls added with placeControl().
- It receives a control instance as the 2nd positional argument (besides self).
- By default the method does nothing, i.e. no animation is set for controls.
- To add animation you need to re-implement this menthod in your child class.
-
- E.g:
- def setAnimation(self, control):
- control.setAnimations([('WindowOpen', 'effect=fade start=0 end=100 time=1000',),
- ('WindowClose', 'effect=fade start=100 end=0 time=1000',)])
- """
- pass
-
-
-class _AddonWindow(_AbstractWindow):
- """
- Top-level control window.
-
- The control windows serves as a parent widget for other XBMC UI controls
- much like Tkinter.Tk or PyQt QWidget class.
- This is an abstract class which is not supposed to be instantiated directly
- and will raise exeptions. It is designed to be implemented in a grand-child class
- with the second inheritance from xbmcgui.Window or xbmcgui.WindowDialog
- in a direct child class.
-
- This class provides a control window with a background and a header
- similar to top-level widgets of desktop UI frameworks.
- """
-
- def __init__(self, title=''):
- """Constructor method."""
- super(_AddonWindow, self).__init__()
- self.setFrame(title)
-
- def setFrame(self, title):
- """
- Define paths to images for window background and title background textures,
- and set control position adjustment constants used in setGrid.
- This is a helper method not to be called directly.
- """
- # Window background image
- self.background_img = os.path.join(_images, 'AddonWindow', 'ContentPanel.png')
- # Background for a window header
- self.title_background_img = os.path.join(_images, 'AddonWindow', 'dialogheader.png')
- # Horisontal adjustment for a header background if the main background has transparent edges.
- self.X_MARGIN = 5
- # Vertical adjustment for a header background if the main background has transparent edges
- self.Y_MARGIN = 5
- # Header position adjustment if the main backround has visible borders.
- self.Y_SHIFT = 4
- # The height of a window header (for the title background and the title label).
- self.HEADER_HEIGHT = 35
- self.background = xbmcgui.ControlImage(-10, -10, 1, 1, self.background_img)
- self.addControl(self.background)
- self.setAnimation(self.background)
- self.title_background = xbmcgui.ControlImage(-10, -10, 1, 1, self.title_background_img)
- self.addControl(self.title_background)
- self.setAnimation(self.title_background)
- self.title_bar = xbmcgui.ControlLabel(-10, -10, 1, 1, title, alignment=ALIGN_CENTER, textColor='0xFFFFA500',
- font='font13_title')
- self.addControl(self.title_bar)
- self.setAnimation(self.title_bar)
- self.window_close_button = xbmcgui.ControlButton(-100, -100, 60, 30, '',
- focusTexture=os.path.join(_images, 'AddonWindow',
- 'DialogCloseButton-focus.png'),
- noFocusTexture=os.path.join(_images, 'AddonWindow',
- 'DialogCloseButton.png'))
- self.addControl(self.window_close_button)
- self.setAnimation(self.window_close_button)
-
- def setGeometry(self, width_, height_, rows_, columns_, pos_x=-1, pos_y=-1, padding=5):
- """
- Set width, height, Grid layout, and coordinates (optional) for a new control window.
-
- Parameters:
- width_, height_: widgh and height of the created window.
- rows_, columns_: rows and colums of the Grid layout to place controls on.
- pos_x, pos_y (optional): coordinates of the top left corner of the window.
- If pos_x and pos_y are not privided, the window will be placed
- at the center of the screen.
- padding (optional): padding between outer edges of the window and
- controls placed on it.
- Example:
- self.setGeometry(400, 500, 5, 4)
- """
- self.win_padding = padding
- super(_AddonWindow, self).setGeometry(width_, height_, rows_, columns_, pos_x, pos_y)
- self.background.setPosition(self.x, self.y)
- self.background.setWidth(self.width)
- self.background.setHeight(self.height)
- self.title_background.setPosition(self.x + self.X_MARGIN, self.y + self.Y_MARGIN + self.Y_SHIFT)
- self.title_background.setWidth(self.width - 2 * self.X_MARGIN)
- self.title_background.setHeight(self.HEADER_HEIGHT)
- self.title_bar.setPosition(self.x + self.X_MARGIN, self.y + self.Y_MARGIN + self.Y_SHIFT)
- self.title_bar.setWidth(self.width - 2 * self.X_MARGIN)
- self.title_bar.setHeight(self.HEADER_HEIGHT)
- self.window_close_button.setPosition(self.x + self.width - 70, self.y + self.Y_MARGIN + self.Y_SHIFT)
-
- def setGrid(self):
- """
- Set window grid layout of rows * columns.
- This is a helper method not to be called directly.
- """
- self.grid_x = self.x + self.X_MARGIN + self.win_padding
- self.grid_y = self.y + self.Y_MARGIN + self.Y_SHIFT + self.HEADER_HEIGHT + self.win_padding
- self.tile_width = (self.width - 2 * (self.X_MARGIN + self.win_padding)) / self.columns
- self.tile_height = (
- self.height - self.HEADER_HEIGHT - self.Y_SHIFT - 2 * (
- self.Y_MARGIN + self.win_padding)) / self.rows
-
- def setWindowTitle(self, title=''):
- """
- Set window title.
- This method must be called AFTER (!!!) setGeometry(),
- otherwise there is some werid bug with all skin text labels set to the 'title' text.
- Example:
- self.setWindowTitle('My Cool Addon')
- """
- self.title_bar.setLabel(title)
-
- def getWindowTitle(self):
- """Get window title."""
- return self.title_bar.getLabel()
-
-
-class _FullWindow(xbmcgui.Window):
- """An abstract class to define window event processing."""
-
- def onAction(self, action):
- """
- Catch button actions.
- Note that, despite being compared to an integer,
- action is an instance of xbmcgui.Action class.
- """
- if action == ACTION_PREVIOUS_MENU:
- self.close()
- else:
- self.executeConnected(action, self.actions_connected)
-
- def onControl(self, control):
- """
- Catch activated controls.
- Control is an instance of xbmcgui.Control class.
- """
- if control == self.window_close_button:
- self.close()
- else:
- self.executeConnected(control, self.controls_connected)
-
-
-class _DialogWindow(xbmcgui.WindowDialog):
- """An abstract class to define window event processing."""
-
- def onAction(self, action):
- """
- Catch button actions.
- Note that, despite being compared to an integer,
- action is an instance of xbmcgui.Action class.
- """
- if action == ACTION_PREVIOUS_MENU:
- self.close()
- else:
- self.executeConnected(action, self.actions_connected)
-
- def onControl(self, control):
- """
- Catch activated controls.
- Control is an instance of xbmcgui.Control class.
- """
- if control == self.window_close_button:
- self.close()
- else:
- self.executeConnected(control, self.controls_connected)
-
-
-class BlankFullWindow(_FullWindow, _AbstractWindow):
- """
- Addon UI container with a solid background.
- This is a blank window with a black background and without any elements whatsoever.
- The decoration and layout are completely up to an addon developer.
- The window controls can hide under video or music visualization.
- Window ID can be passed on class instantiation an agrument
- but __init__ must have the 2nd fake argument, e.g:
-
- def __init__(self, *args)
-
- Minimal example:
-
- addon = MyAddon('My Cool Addon')
- addon.setGeometry(400, 300, 4, 3)
- addon.doModal()
- """
- pass
-
-
-class BlankDialogWindow(_DialogWindow, _AbstractWindow):
- """
- Addon UI container with a transparent background.
- This is a blank window with a transparent background and without any elements whatsoever.
- The decoration and layout are completely up to an addon developer.
- The window controls are always displayed over video or music visualization.
- Minimal example:
-
- addon = MyAddon('My Cool Addon')
- addon.setGeometry(400, 300, 4, 3)
- addon.doModal()
- """
- pass
-
-
-class AddonFullWindow(_FullWindow, _AddonWindow):
- """
- Addon UI container with a solid background.
- Control window is displayed on top of the main background image - self.main_bg.
- Video and music visualization are displayed unhindered.
- Window ID can be passed on class instantiation as the 2nd positional agrument
- but __init__ must have the 3rd fake argument, e.g:
-
- def __init__(self, title='', *args)
-
- Minimal example:
-
- addon = MyAddon('My Cool Addon')
- addon.setGeometry(400, 300, 4, 3)
- addon.doModal()
- """
-
- def __new__(cls, title='', *args, **kwargs):
- return super(AddonFullWindow, cls).__new__(cls, *args, **kwargs)
-
- def setFrame(self, title):
- """
- Set the image for for the fullscreen background.
- """
- # Image for the fullscreen background.
- self.main_bg_img = os.path.join(_images, 'AddonWindow', 'SKINDEFAULT.jpg')
- # Fullscreen background image control.
- self.main_bg = xbmcgui.ControlImage(1, 1, 1280, 720, self.main_bg_img)
- self.addControl(self.main_bg)
- super(AddonFullWindow, self).setFrame(title)
-
- def setBackground(self, image=''):
- """
- Set the main bacground to an image file.
- image: path to an image file as str.
- Example:
- self.setBackground('d:\images\bacground.png')
- """
- self.main_bg.setImage(image)
-
-
-class AddonDialogWindow(_DialogWindow, _AddonWindow):
- """
- Addon UI container with a transparent background.
- Control window is displayed on top of XBMC UI,
- including video an music visualization!
- Minimal example:
-
- addon = MyAddon('My Cool Addon')
- addon.setGeometry(400, 300, 4, 3)
- addon.doModal()
- """
- pass
diff --git a/resources/pyxbmct/textures/default/AddonWindow/ContentPanel.png b/resources/pyxbmct/textures/default/AddonWindow/ContentPanel.png
deleted file mode 100644
index eb022d6..0000000
Binary files a/resources/pyxbmct/textures/default/AddonWindow/ContentPanel.png and /dev/null differ
diff --git a/resources/pyxbmct/textures/default/AddonWindow/DialogCloseButton-focus.png b/resources/pyxbmct/textures/default/AddonWindow/DialogCloseButton-focus.png
deleted file mode 100644
index fdde65c..0000000
Binary files a/resources/pyxbmct/textures/default/AddonWindow/DialogCloseButton-focus.png and /dev/null differ
diff --git a/resources/pyxbmct/textures/default/AddonWindow/DialogCloseButton.png b/resources/pyxbmct/textures/default/AddonWindow/DialogCloseButton.png
deleted file mode 100644
index 7f5d105..0000000
Binary files a/resources/pyxbmct/textures/default/AddonWindow/DialogCloseButton.png and /dev/null differ
diff --git a/resources/pyxbmct/textures/default/AddonWindow/SKINDEFAULT.jpg b/resources/pyxbmct/textures/default/AddonWindow/SKINDEFAULT.jpg
deleted file mode 100644
index 3d5b572..0000000
Binary files a/resources/pyxbmct/textures/default/AddonWindow/SKINDEFAULT.jpg and /dev/null differ
diff --git a/resources/pyxbmct/textures/default/AddonWindow/dialogheader.png b/resources/pyxbmct/textures/default/AddonWindow/dialogheader.png
deleted file mode 100644
index af7ba85..0000000
Binary files a/resources/pyxbmct/textures/default/AddonWindow/dialogheader.png and /dev/null differ
diff --git a/resources/pyxbmct/textures/default/Button/KeyboardKey.png b/resources/pyxbmct/textures/default/Button/KeyboardKey.png
deleted file mode 100644
index 5c8b2bf..0000000
Binary files a/resources/pyxbmct/textures/default/Button/KeyboardKey.png and /dev/null differ
diff --git a/resources/pyxbmct/textures/default/Button/KeyboardKeyNF.png b/resources/pyxbmct/textures/default/Button/KeyboardKeyNF.png
deleted file mode 100644
index 077777f..0000000
Binary files a/resources/pyxbmct/textures/default/Button/KeyboardKeyNF.png and /dev/null differ
diff --git a/resources/pyxbmct/textures/default/Edit/black-back2.png b/resources/pyxbmct/textures/default/Edit/black-back2.png
deleted file mode 100644
index 399e2d0..0000000
Binary files a/resources/pyxbmct/textures/default/Edit/black-back2.png and /dev/null differ
diff --git a/resources/pyxbmct/textures/default/Edit/button-focus.png b/resources/pyxbmct/textures/default/Edit/button-focus.png
deleted file mode 100644
index 831dd45..0000000
Binary files a/resources/pyxbmct/textures/default/Edit/button-focus.png and /dev/null differ
diff --git a/resources/pyxbmct/textures/default/List/MenuItemFO.png b/resources/pyxbmct/textures/default/List/MenuItemFO.png
deleted file mode 100644
index 14230c0..0000000
Binary files a/resources/pyxbmct/textures/default/List/MenuItemFO.png and /dev/null differ
diff --git a/resources/pyxbmct/textures/default/List/MenuItemNF.png b/resources/pyxbmct/textures/default/List/MenuItemNF.png
deleted file mode 100644
index ecbf84f..0000000
Binary files a/resources/pyxbmct/textures/default/List/MenuItemNF.png and /dev/null differ
diff --git a/resources/pyxbmct/textures/default/RadioButton/MenuItemFO.png b/resources/pyxbmct/textures/default/RadioButton/MenuItemFO.png
deleted file mode 100644
index 14230c0..0000000
Binary files a/resources/pyxbmct/textures/default/RadioButton/MenuItemFO.png and /dev/null differ
diff --git a/resources/pyxbmct/textures/default/RadioButton/MenuItemNF.png b/resources/pyxbmct/textures/default/RadioButton/MenuItemNF.png
deleted file mode 100644
index ecbf84f..0000000
Binary files a/resources/pyxbmct/textures/default/RadioButton/MenuItemNF.png and /dev/null differ
diff --git a/resources/pyxbmct/textures/default/RadioButton/radiobutton-focus.png b/resources/pyxbmct/textures/default/RadioButton/radiobutton-focus.png
deleted file mode 100644
index bcb4cb5..0000000
Binary files a/resources/pyxbmct/textures/default/RadioButton/radiobutton-focus.png and /dev/null differ
diff --git a/resources/pyxbmct/textures/default/RadioButton/radiobutton-nofocus.png b/resources/pyxbmct/textures/default/RadioButton/radiobutton-nofocus.png
deleted file mode 100644
index 282396d..0000000
Binary files a/resources/pyxbmct/textures/default/RadioButton/radiobutton-nofocus.png and /dev/null differ
diff --git a/resources/pyxbmct/textures/default/Slider/osd_slider_bg.png b/resources/pyxbmct/textures/default/Slider/osd_slider_bg.png
deleted file mode 100644
index 4b5160b..0000000
Binary files a/resources/pyxbmct/textures/default/Slider/osd_slider_bg.png and /dev/null differ
diff --git a/resources/pyxbmct/textures/default/Slider/osd_slider_bg_2.png b/resources/pyxbmct/textures/default/Slider/osd_slider_bg_2.png
deleted file mode 100644
index 37dc249..0000000
Binary files a/resources/pyxbmct/textures/default/Slider/osd_slider_bg_2.png and /dev/null differ
diff --git a/resources/pyxbmct/textures/default/Slider/osd_slider_nib.png b/resources/pyxbmct/textures/default/Slider/osd_slider_nib.png
deleted file mode 100644
index 4e57eb1..0000000
Binary files a/resources/pyxbmct/textures/default/Slider/osd_slider_nib.png and /dev/null differ
diff --git a/resources/pyxbmct/textures/default/Slider/osd_slider_nibNF.png b/resources/pyxbmct/textures/default/Slider/osd_slider_nibNF.png
deleted file mode 100644
index 638d4f8..0000000
Binary files a/resources/pyxbmct/textures/default/Slider/osd_slider_nibNF.png and /dev/null differ
diff --git a/resources/settings.xml b/resources/settings.xml
index 43c2b1d..b435dd3 100644
--- a/resources/settings.xml
+++ b/resources/settings.xml
@@ -1,11 +1,12 @@
-
+
-
+
+
@@ -61,15 +62,18 @@
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/resources/skins/Default/720p/movieinfo.xml b/resources/skins/Default/720p/movieinfo.xml
deleted file mode 100644
index 27494b1..0000000
--- a/resources/skins/Default/720p/movieinfo.xml
+++ /dev/null
@@ -1,218 +0,0 @@
-
-
- 1
- 240
- 20
-
- dialogeffect
-
-
- WindowOpen
- WindowClose
-
- background image
- 0
- 0
- 800
- 680
- ConfluenceDialogBack.png
-
-
- Dialog Header image
- 40
- 16
- 720
- 40
- Confluencedialogheader.png
-
-
- header label
- 40
- 20
- 720
- 30
- font13_title
-
- center
- center
- selected
- black
-
-
-
- Close Window button
- 710
- 15
- 64
- 32
-
- -
- PreviousMenu
- ConfluenceDialogCloseButton-focus.png
- ConfluenceDialogCloseButton.png
- 10
- 10
- 10
- 10
- system.getbool(input.enablemouse)
-
-
-
- 760
- 100
- 25
- 495
- ScrollBarV.png
- ScrollBarV_bar.png
- ScrollBarV_bar_focus.png
- ScrollBarNib.png
- ScrollBarNib.png
- 30
- 131
- true
- IntegerGreaterThan(Container(32).NumPages,1)
- vertical
-
-
-
- Dialog Header image
- 33
- 85
- 104
- 149
-
-
-
-
- rating
- 34
- 240
- 102
- 20
- true
- left
- center
- false
-
- false
- font10
- white
- black
- false
-
-
-
- rating
- 34
- 260
- 102
- 20
- true
- left
- center
- false
-
- false
- font10
- white
- black
- false
-
-
-
- kinopoisk
- 34
- 292
- 102
- 38
-
-
-
-
- filepath
- 180
- 70
- 550
- 60
- 470
- left
- top
- font18
- Нет описания
- center
- center
- white
- black
- true
-
-
- 615
- 50
-
-
- close
- 350
- 0
- 320
- 40
- center
- center
- font12_title
-
- 33
- 60
- 30
- 30
-
-
-
- play
- 20
- -50
- 320
- 40
- center
- center
- font12_title
-
- 60
- 30
- 33
- 33
-
-
-
- libtorrent
- 350
- -50
- 320
- 40
- center
- center
- font12_title
-
- 131
- 60
- 22
- 22
-
-
-
- tclient
- 20
- 0
- 320
- 40
- center
- center
- font12_title
-
- 22
- 22
- 131
- 131
-
-
-
-
-
diff --git a/resources/skins/Default/720p/reviews.xml b/resources/skins/Default/720p/reviews.xml
deleted file mode 100644
index ccc51dc..0000000
--- a/resources/skins/Default/720p/reviews.xml
+++ /dev/null
@@ -1,127 +0,0 @@
-
-
- 1
- 240
- 20
-
- dialogeffect
-
-
- WindowOpen
- WindowClose
-
- background image
- 0
- 0
- 800
- 680
- DialogBack.png
-
-
- Dialog Header image
- 40
- 16
- 720
- 40
- dialogheader.png
-
-
- header label
- 40
- 20
- 720
- 30
- font13_title
-
- center
- center
- selected
- black
-
-
-
- Close Window button
- 710
- 15
- 64
- 32
-
- -
- PreviousMenu
- DialogCloseButton-focus.png
- DialogCloseButton.png
- 10
- 10
- 10
- 10
- system.getbool(input.enablemouse)
-
-
-
- 760
- 100
- 25
- 495
- ScrollBarV.png
- ScrollBarV_bar.png
- ScrollBarV_bar_focus.png
- ScrollBarNib.png
- ScrollBarNib.png
- 22
- 22
- true
- IntegerGreaterThan(Container(32).NumPages,1)
- vertical
-
-
-
- Dialog Header image
- 33
- 85
- 104
- 149
-
-
-
-
-
- filepath
- 60
- 70
- 690
- 60
- 530
- left
- top
- font12
- Нет отзывов
- center
- center
- white
- black
- true
-
-
- 615
- 50
-
-
- close
- 20
- 0
- 650
- 40
- center
- center
- font12_title
-
- 60
- 60
- 60
- 60
-
-
-
-
-
-
diff --git a/resources/skins/Default/media/ConfluenceDialogBack.png b/resources/skins/Default/media/ConfluenceDialogBack.png
deleted file mode 100644
index 812801a..0000000
Binary files a/resources/skins/Default/media/ConfluenceDialogBack.png and /dev/null differ
diff --git a/resources/skins/Default/media/ConfluenceDialogCloseButton-focus.png b/resources/skins/Default/media/ConfluenceDialogCloseButton-focus.png
deleted file mode 100644
index fdde65c..0000000
Binary files a/resources/skins/Default/media/ConfluenceDialogCloseButton-focus.png and /dev/null differ
diff --git a/resources/skins/Default/media/ConfluenceDialogCloseButton.png b/resources/skins/Default/media/ConfluenceDialogCloseButton.png
deleted file mode 100644
index 7f5d105..0000000
Binary files a/resources/skins/Default/media/ConfluenceDialogCloseButton.png and /dev/null differ
diff --git a/resources/skins/Default/media/Confluencedialogheader.png b/resources/skins/Default/media/Confluencedialogheader.png
deleted file mode 100644
index af7ba85..0000000
Binary files a/resources/skins/Default/media/Confluencedialogheader.png and /dev/null differ
diff --git a/resources/skins/DialogReviews.py b/resources/skins/DialogReviews.py
deleted file mode 100644
index 959f46d..0000000
--- a/resources/skins/DialogReviews.py
+++ /dev/null
@@ -1,63 +0,0 @@
-# -*- coding: utf-8 -*-
-
-import re
-import htmlentitydefs
-
-import xbmcgui
-
-pattern = re.compile("&(\w+?);")
-
-def html_entity_decode_char(m, defs=htmlentitydefs.entitydefs):
- try:
- return defs[m.group(1)]
- except KeyError:
- return m.group(0)
-
-def html_entity_decode(string):
- return pattern.sub(html_entity_decode_char, string)
-
-KEY_BUTTON_BACK = 275
-KEY_KEYBOARD_ESC = 61467
-ACTION_PREVIOUS_MENU = 10
-ACTION_NAV_BACK = 92
-class DialogReviews(xbmcgui.WindowXMLDialog):
- def onInit(self):
- print "DialogReviews(): Window Initialized"
- self.reviews_box = self.getControl(32)
- self.reviews_box.setText(self.get_reviews())
-
- self.setFocus(self.getControl(22))
-
- def onAction(self, action):
- buttonCode = action.getButtonCode()
- if (action == ACTION_NAV_BACK or action == ACTION_PREVIOUS_MENU):
- self.close()
- if (buttonCode == KEY_BUTTON_BACK or buttonCode == KEY_KEYBOARD_ESC):
- self.close()
-
- def onClick(self, controlID):
- if (controlID == 2 or controlID == 22):
- self.close()
-
-
- def onFocus(self, controlID):
- #print "onFocus(): control %i" % controlID
- pass
-
-
- def doModal(self, movieHtml):
- self.movieHtml = movieHtml
- xbmcgui.WindowXMLDialog.doModal(self)
-
-
- def get_reviews(self):
- reviews_texts = re.compile('',re.S).findall(self.movieHtml)
- reviews_autors = re.compile('
',re.S).findall(self.movieHtml)
- reviews_dates = re.compile('
([^<]+)
',re.S).findall(self.movieHtml)
- texts = ''
- i = 0
- for text in reviews_texts:
- texts = texts+"\n[B][COLOR purple]"+reviews_autors[i]+"[/COLOR][/B] [I]"+reviews_dates[i]+"[/I]\n"
- texts = texts+html_entity_decode(text)+"\n"
- i = i + 1
- return texts
diff --git a/resources/skins/DialogXml.py b/resources/skins/DialogXml.py
deleted file mode 100644
index ad29c21..0000000
--- a/resources/skins/DialogXml.py
+++ /dev/null
@@ -1,83 +0,0 @@
-# -*- coding: utf-8 -*-
-import sys
-
-import xbmcgui
-import Localization
-import xbmc
-
-KEY_BUTTON_BACK = 275
-KEY_KEYBOARD_ESC = 61467
-ACTION_PREVIOUS_MENU = 10
-ACTION_NAV_BACK = 92
-
-
-class DialogXml(xbmcgui.WindowXMLDialog):
- def onInit(self):
- print "onInit(): Window Initialized"
- localize = Localization.localize
- color = '[COLOR %s]%s[/COLOR]'
- self.movie_label = self.getControl(32)
- self.movie_label.setText(self.movieInfo['desc'])
-
- if self.movieInfo.get('views'):
- self.view_label = self.getControl(34)
- self.view_label.setLabel(color % ('blue', localize('Views:')) + self.movieInfo['views'])
-
- self.view_label = self.getControl(35)
- self.ratingcolor = 'green'
- self.ratingint = int(self.movieInfo['rating'])
- if (self.ratingint < 70):
- self.ratingcolor = 'red'
- self.view_label.setLabel(
- color % ('blue', localize('Rating:')) + color % (self.ratingcolor, self.movieInfo['rating']))
-
- self.movie_label = self.getControl(1)
- self.movie_label.setLabel(self.movieInfo['title'])
-
- self.movie_label = self.getControl(32)
- self.movie_label.setText(self.movieInfo['desc'])
-
- self.poster = self.getControl(31)
- self.poster.setImage(self.movieInfo['poster'])
-
- self.poster = self.getControl(36)
- self.poster.setImage(self.movieInfo['kinopoisk'])
- self.getControl(22).setLabel(localize('Close'))
- self.getControl(33).setLabel(localize('Download via T-client'))
- self.getControl(30).setLabel(localize('Download via Libtorrent'))
- self.getControl(131).setLabel(localize('Play'))
-
- self.setFocus(self.getControl(22))
-
- def onAction(self, action):
- buttonCode = action.getButtonCode()
- if (action == ACTION_NAV_BACK or action == ACTION_PREVIOUS_MENU):
- self.close()
- if (buttonCode == KEY_BUTTON_BACK or buttonCode == KEY_KEYBOARD_ESC):
- self.close()
-
- def onClick(self, controlID):
- if (controlID == 2 or controlID == 22):
- self.close()
- if (controlID == 30):
- self.RunPlugin('downloadLibtorrent')
- if (controlID == 33):
- self.RunPlugin('downloadFilesList')
- if (controlID == 131):
- self.RunPlugin('openTorrent&external=1')
-
- def RunPlugin(self, action):
- if self.link:
- exec_str = 'XBMC.RunPlugin(%s)' % \
- ('%s?action=%s&url=%s') % \
- (sys.argv[0], action, self.link)
- xbmc.executebuiltin(exec_str)
-
- def onFocus(self, controlID):
- # print "onFocus(): control %i" % controlID
- pass
-
- def doModal(self, movieInfo, url):
- self.movieInfo = movieInfo
- self.link = url
- xbmcgui.WindowXMLDialog.doModal(self)
diff --git a/searchwindow.py b/searchwindow.py
new file mode 100644
index 0000000..e6403fd
--- /dev/null
+++ b/searchwindow.py
@@ -0,0 +1,1371 @@
+# -*- coding: utf-8 -*-
+'''
+ Torrenter v2 plugin for XBMC/Kodi
+ Copyright (C) 2012-2015 Vadim Skorba v1 - DiMartino v2
+ https://forums.tvaddons.ag/addon-releases/29224-torrenter-v2.html
+
+ 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.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see
.
+'''
+import pyxbmct.addonwindow as pyxbmct
+import xbmcaddon
+import xbmcgui
+import xbmcvfs
+import xbmc
+
+from functions import *
+
+__settings__ = xbmcaddon.Addon(id='plugin.video.torrenter')
+__language__ = __settings__.getLocalizedString
+__version__ = __settings__.getAddonInfo('version')
+__plugin__ = __settings__.getAddonInfo('name') + " v." + __version__
+__root__ = __settings__.getAddonInfo('path')
+
+log('SYS ARGV: ' + str(sys.argv))
+
+# https://github.com/xbmc/xbmc/blob/8d4a5bba55638dfd0bdc5e7de34f3e5293f99933/xbmc/input/Key.h
+ACTION_STOP = 13
+ACTION_PLAYER_PLAY = 79
+ACTION_MOUSE_RIGHT_CLICK = 101
+ACTION_CONTEXT_MENU = 117
+ACTION_SHOW_OSD = 24
+
+
+class SearchWindow(pyxbmct.AddonDialogWindow):
+ __settings__ = sys.modules["__main__"].__settings__
+ right_buttons_count = 7
+ right_label_count = 7
+ last_right_buttons_count = 0
+ last_top_button = None
+ last_right_button = None
+ last_listing_mode = None
+ route = {}
+ count = 0
+ navi_right_menu = []
+ navi_top_menu = []
+
+ icon = __root__ + '/icons/searchwindow/%s.png'
+ icon_tc = __root__ + '/icons/searchwindow/%s' + getTorrentClientIcon()
+
+ def __init__(self, params = None):
+ log('SearchWindow init params: '+str(params))
+ super(SearchWindow, self).__init__(self.localize('Torrenter Search Window'))
+ __settings__.setSetting('loadsw_onstop', 'false')
+ self.setGeometry(1280, 720, 9, 16)
+ self.set_navi()
+ self.set_controls()
+ self.set_focus()
+ self.connect_controls()
+ if params and params.get('mode'):
+ if params.get('mode') == 'load':
+ self.navi_load()
+ elif params.get('mode') == 'search':
+ self.search(params)
+ elif params.get('mode') == 'externalsearch':
+ self.externalsearch(params)
+ elif params.get('mode') == 'history':
+ self.history()
+ elif params.get('mode') == 'downloadstatus':
+ self.downloadstatus()
+ elif params.get('mode') == 'browser':
+ self.browser()
+ elif params.get('mode') == 'watched':
+ self.watched()
+ elif params.get('mode') == 'open_torrent':
+ self.open_torrent(params)
+ elif params.get('mode') == 'file_browser':
+ self.file_browser(params)
+ else:
+ self.navi_load()
+
+ def set_navi(self):
+ self.navi = {
+ 'last_top_button': 4,
+ 'last_right_button': 1,
+ 'contentList': [],
+ 'searchersList': [],
+ 'filesList': [],
+ 'last_addtime': None,
+ 'last_query': None,
+ 'last_link': None,
+ 'last_filename': None,
+ 'route': [{'mode': 'close', 'params': {}, 'last_listing_item': 0}]
+ }
+
+ def set_controls(self):
+ if not __settings__.getSetting('sw_transparent_back') == 'true':
+ self.background.setImage('%s/icons/%s.png' % (__root__, 'ContentPanel'))
+
+ # Top menu
+ self.button_downloadstatus = pyxbmct.Button("",
+ focusTexture=self.icon % 'fdownloadstatus',
+ noFocusTexture=self.icon % 'nfdownloadstatus')
+ self.placeControl(self.button_downloadstatus, 0, 1, 1, 1)
+
+ self.button_browser = pyxbmct.Button("",
+ focusTexture=self.icon_tc % 'f',
+ noFocusTexture=self.icon_tc % 'nf')
+ self.placeControl(self.button_browser, 0, 2, 1, 1)
+ self.button_controlcenter = pyxbmct.Button("", focusTexture=self.icon % 'fcontrolcenter',
+ noFocusTexture=self.icon % 'nfcontrolcenter')
+ self.placeControl(self.button_controlcenter, 0, 3, 1, 1)
+ self.button_filter = pyxbmct.Button("", focusTexture=self.icon % 'fkeyboard',
+ noFocusTexture=self.icon % 'nfkeyboard')
+ self.placeControl(self.button_filter, 0, 4, 1, 1)
+ self.input_search = pyxbmct.Edit("", _alignment=pyxbmct.ALIGN_CENTER_X | pyxbmct.ALIGN_CENTER_Y)
+ self.placeControl(self.input_search, 0, 5, 1, 6)
+ self.button_search = pyxbmct.Button("", focusTexture=self.icon % 'fsearch',
+ noFocusTexture=self.icon % 'nfsearch')
+ self.placeControl(self.button_search, 0, 11, 1, 1)
+ self.button_history = pyxbmct.Button("", focusTexture=self.icon % 'fhistory',
+ noFocusTexture=self.icon % 'nfhistory')
+ self.placeControl(self.button_history, 0, 12, 1, 1)
+ self.button_watched = pyxbmct.Button("", focusTexture=self.icon % 'fwatched',
+ noFocusTexture=self.icon % 'nfwatched')
+ self.placeControl(self.button_watched, 0, 13, 1, 1)
+
+ # Main
+ self.listing = pyxbmct.List(_imageWidth=60, _imageHeight=60, _itemTextXOffset=1,
+ _itemTextYOffset=0, _itemHeight=60, _space=0, _alignmentY=4)
+ self.placeControl(self.listing, 1, 0, 8, 14)
+
+ self.navi_top_menu = [self.button_downloadstatus, self.button_browser, self.button_controlcenter,
+ self.input_search, self.button_search, self.button_history, self.button_watched]
+
+ # Right menu
+ self.right_menu()
+
+ def connect_controls(self):
+ self.connect(self.listing, self.right_press1)
+ self.connect(self.button_history, self.history)
+ self.connect(self.button_search, self.search)
+ self.connect(self.button_controlcenter, self.controlcenter)
+ self.connect(self.button_browser, self.browser)
+ self.connect(self.button_downloadstatus, self.downloadstatus)
+ self.connect(self.button_watched, self.watched)
+ self.connect(self.button_filter, self.filter)
+
+ self.connect(pyxbmct.ACTION_NAV_BACK, self.navi_back)
+ self.connect(pyxbmct.ACTION_PREVIOUS_MENU, self.navi_back)
+ self.connect(xbmcgui.ACTION_BACKSPACE, self.navi_back)
+ self.connect(xbmcgui.KEY_BUTTON_BACK, self.navi_back)
+
+ self.connect(ACTION_MOUSE_RIGHT_CLICK, self.context)
+ self.connect(ACTION_CONTEXT_MENU, self.context)
+ self.connect(ACTION_SHOW_OSD, self.context)
+
+ self.connect(pyxbmct.ACTION_MOVE_LEFT, self.navi_update)
+ self.connect(pyxbmct.ACTION_MOVE_RIGHT, self.navi_update)
+ self.connect(pyxbmct.ACTION_MOVE_UP, self.navi_update)
+ self.connect(pyxbmct.ACTION_MOVE_DOWN, self.navi_update)
+
+ def set_navigation(self):
+ # Top menu
+ self.button_browser.setNavigation(self.window_close_button, self.listing, self.button_downloadstatus,
+ self.button_controlcenter)
+ self.button_controlcenter.setNavigation(self.window_close_button, self.listing, self.button_browser, self.button_filter)
+ self.button_filter.setNavigation(self.window_close_button, self.listing, self.button_controlcenter, self.input_search)
+ self.input_search.setNavigation(self.window_close_button, self.listing, self.button_filter, self.button_search)
+ self.button_search.setNavigation(self.window_close_button, self.listing, self.input_search, self.button_history)
+ self.button_history.setNavigation(self.window_close_button, self.listing, self.button_search, self.button_watched)
+ self.update_navigation()
+
+ def update_navigation(self):
+ self.last_top_button = self.navi_top_menu[self.navi['last_top_button'] - 1]
+ if self.navi['last_right_button'] > self.right_label_count:
+ self.navi['last_right_button'] = self.right_label_count
+ self.last_right_button = self.navi_right_menu[self.navi['last_right_button'] - 1]
+
+ # Top menu
+ self.button_downloadstatus.setNavigation(self.window_close_button, self.listing, self.last_right_button,
+ self.button_browser)
+ self.button_watched.setNavigation(self.window_close_button, self.listing, self.button_history, self.last_right_button)
+ self.window_close_button.setNavigation(self.listing, self.last_top_button, self.button_watched,
+ self.button_downloadstatus)
+ # Main
+ self.listing.setNavigation(self.last_top_button, self.input_search, self.button_downloadstatus,
+ self.last_right_button)
+
+ def setAnimation(self, control):
+ # Set fade animation for all add-on window controls
+ control.setAnimations([('WindowOpen', 'effect=fade start=0 end=100 time=500',),
+ ('WindowClose', 'effect=fade start=100 end=0 time=500',)])
+
+ def navi_back(self):
+ debug('navi_back init')
+ self.navi['route'].pop(-1)
+ self.navi_restore()
+
+ def navi_route_reset(self):
+ debug('navi_route_reset init')
+ self.navi['route'] = [self.navi['route'][0]]
+
+ def navi_route_pop(self):
+ debug('navi_route_pop init')
+ self.navi['route'].pop(-1)
+
+ def navi_restore(self):
+ debug('navi_restore init')
+ self.route = self.navi['route'].pop(-1)
+ action = getattr(self, self.route['mode'])
+ try:
+ if self.route['params']:
+ action(self.route['params'])
+ else:
+ action()
+
+ self.set_focus(self.route['mode'])
+
+ debug('self.route[last_listing_item]: ' + str(self.route['last_listing_item']))
+ if self.route['last_listing_item'] > 0:
+ self.listing.selectItem(self.route['last_listing_item'])
+ except:
+ import traceback
+ debug('navi_restore ERROR '+traceback.format_exc())
+ self.set_navi()
+ self.history()
+
+ def navi_load(self):
+ debug('navi_load init')
+ __tmppath__ = os.path.join(xbmc.translatePath('special://temp'), 'xbmcup', 'plugin.video.torrenter')
+ if not xbmcvfs.exists(__tmppath__):
+ xbmcvfs.mkdirs(__tmppath__)
+ navi_file = os.path.join(__tmppath__, 'navi.txt')
+ if not xbmcvfs.exists(navi_file):
+ self.set_navi()
+ self.navi['route'].append({"last_listing_item": 0, "params": {}, "mode": "history"})
+ with open(navi_file, 'w') as f: f.write(json.dumps(self.navi))
+
+ with open(navi_file, 'r') as read: navi = read.read()
+
+ try:
+ debug('navi_load navi: '+str(navi))
+ log('navi_load navi: ' + str(navi['route']))
+ except:
+ log('navi_load load error')
+
+ if navi and len(navi) > 0:
+ self.navi = json.loads(navi)
+ self.navi_restore()
+
+ def navi_save(self, mode = None):
+ debug('navi_save init')
+
+ self.set_focus(mode)
+
+ navi = json.dumps(self.navi)
+
+ __tmppath__ = os.path.join(xbmc.translatePath('special://temp'), 'xbmcup', 'plugin.video.torrenter')
+ if not xbmcvfs.exists(__tmppath__):
+ xbmcvfs.mkdirs(__tmppath__)
+ navi_file = os.path.join(__tmppath__, 'navi.txt')
+ write = xbmcvfs.File(navi_file, 'w')
+ write.write(navi)
+ write.close()
+
+ def navi_update(self):
+ debug('navi_update init')
+ try:
+ focused_control = self.getFocus()
+ except:
+ focused_control = None
+ debug('start navi_update' + str(focused_control))
+ debug(str(self.navi['route']))
+
+ if focused_control == self.listing:
+ item_index = self.listing.getSelectedPosition()
+ self.navi['route'][-1]['last_listing_item'] = item_index
+ debug('self.listing getSelectedPosition ' + str(item_index))
+
+ item = self.listing.getSelectedItem()
+ params = json.loads(item.getfilename())
+ mode = params.get('mode')
+ debug('navi_update:' + str(mode))
+ if self.last_listing_mode != mode:
+ self.last_listing_mode = mode
+ debug('set_menulist navi_update:' + str(mode))
+ self.set_menulist(mode)
+ self.update_navigation()
+
+ elif focused_control in self.navi_top_menu:
+ self.navi['last_top_button'] = self.navi_top_menu.index(focused_control) + 1
+ self.update_navigation()
+
+ elif focused_control in self.navi_right_menu:
+ self.navi['last_right_button'] = self.navi_right_menu.index(focused_control) + 1
+ self.update_navigation()
+
+ def navi_route(self, mode, params = {}, right_menu = None):
+ debug('navi_route init')
+ try:
+ focused_control = self.getFocus()
+ except:
+ focused_control = None
+
+ if focused_control in self.navi_top_menu:
+ debug('focused_control in self.navi[\'top_menu\']')
+ self.navi_route_reset()
+
+ debug('***** self.navi[\'route\'].append *****' + str(mode) + str(params))
+
+ self.navi['route'].append({'mode': mode,
+ 'params': params,
+ 'last_listing_item': 0})
+
+ self.right_menu(mode if not right_menu else right_menu)
+ self.listing.reset()
+
+ def set_focus(self, mode = None):
+ if not self.listing.size():
+ if mode and hasattr(self, "button_" + mode):
+ self.setFocus(getattr(self, "button_" + mode))
+ else:
+ self.setFocus(self.input_search)
+ else:
+ self.setFocus(self.listing)
+
+ def search(self, params = {}):
+ log('search init params: ' + str(params))
+ self.navi_route('search', params)
+
+ get = params.get
+ addtime = get('addtime')
+ query = get('query')
+ self.route = self.navi['route'][-1]
+
+ if query:
+ self.input_search.setText(query)
+ else:
+ if self.input_search.getText() not in ['', None]:
+ query = self.input_search.getText()
+ elif self.navi['last_query'] not in ['', None]:
+ query = self.navi['last_query']
+ self.input_search.setText(self.navi['last_query'])
+
+ log('Search query: ' + str(query))
+
+ if not addtime and query == self.navi['last_query']:
+ addtime = self.navi['last_addtime']
+
+ searchersList = get_searchersList(addtime)
+
+ # cache
+ self.route['params']['query'] = query
+ if (query != self.navi['last_query'] or self.navi['searchersList'] != searchersList) and len(query) > 0:
+ self.navi['filesList'] = get_filesList(query, searchersList, addtime)
+ self.route['params']['addtime'] = addtime
+ self.navi['last_addtime'] = addtime
+ self.navi['searchersList'] = searchersList
+ self.navi['last_query'] = query
+ elif len(query) == 0:
+ self.navi['filesList'] = []
+
+ if self.navi['filesList']:
+ for (order, seeds, leechers, size, title, link, image) in self.navi['filesList']:
+ title = titleMake(seeds, leechers, size, title)
+ self.drawItem(title, {'mode': 'search_item', 'filename': link}, image)
+ self.setFocus(self.listing)
+
+ def externalsearch(self, params={}):
+ log('search init params: ' + str(params))
+
+ if hasattr(self, 'params'):
+ params = self.params
+
+ self.params = params
+ get = params.get
+ query = unquote(get('query'),'')
+ external = unquote(params.get("external"), 'torrenterall')
+ back_url = unquote(get("back_url"),'')
+ self.return_name = unquote(get("return_name"),'')
+ sdata = unquote(get("sdata"),'{}')
+
+ self.reconnect(self.button_search, self.externalsearch)
+ self.navi_route('externalsearch', params)
+
+ try:
+ sdata = json.loads(sdata)
+ except:
+ sdata = json.loads(urllib.unquote_plus(sdata))
+
+
+ if self.input_search.getText() not in ['', None]:
+ query = self.input_search.getText()
+ else:
+ self.input_search.setText(query)
+
+ #contextMenu = [
+ # (self.localize('Add to %s') % return_name,
+ # 'XBMC.RunPlugin(%s)' % (back_url + '&stringdata=' + urllib.quote_plus(
+ # json.dumps(sdata)))),
+
+
+ # url = 'plugin://plugin.video.torrenter/?action=searchWindow&mode=externalsearch&query=%s' \
+ # '&sdata=%s&external=%s&back_url=%s&return_name=%s' % \
+ # (urllib.quote_plus(query), urllib.quote_plus(json.dumps(sdata)),
+ # self.externals[self.stype], urllib.quote_plus(back_self.url),
+ # urllib.quote_plus(return_name))
+
+ log('Search query: ' + str(query))
+
+ searchersList = []
+
+ if not external or external == 'torrenterall':
+ searchersList = get_searchersList()
+ elif external == 'torrenterone':
+ slist = Searchers().list().keys()
+ ret = xbmcgui.Dialog().select(self.localize('Choose searcher')+':', slist)
+ if ret > -1 and ret < len(slist):
+ external = slist[ret]
+ searchersList.append(external)
+ else:
+ searchersList.append(external)
+
+ if len(query) > 0:
+ self.navi['filesList'] = get_filesList(query, searchersList)
+ else:
+ self.navi['filesList'] = []
+
+ if self.navi['filesList']:
+ for (order, seeds, leechers, size, title, link, image) in self.navi['filesList']:
+ title = titleMake(seeds, leechers, size, title)
+ sdata['filename'] = link
+ stringdata = json.dumps(sdata)
+ self.drawItem(title, {'mode': 'externalsearch_item', 'filename': link,
+ 'stringdata': stringdata, 'back_url': back_url}, image)
+ self.setFocus(self.listing)
+
+ def history(self, params = {}):
+ self.navi_route('history', params)
+
+ db = HistoryDB()
+ items = db.get_all()
+ favlist = [(1, '[B]%s[/B]'), (0, '%s')]
+ last_listing_item = 0
+ last_addtime_fav = False
+ if items:
+ for favbool, bbstring in favlist:
+ for addtime, string, fav in items:
+ if favbool == int(fav):
+ title = string.encode('utf-8')
+
+ if int(fav) == 1:
+ img = __root__ + '/icons/fav.png'
+ if str(self.navi['last_addtime']) == str(addtime):
+ last_addtime_fav = True
+ if not last_addtime_fav:
+ last_listing_item += 1
+ else:
+ img = __root__ + '/icons/unfav.png'
+
+ link = {'mode': 'history_item', 'query': title, 'addtime': str(addtime),
+ 'fav': str(fav)}
+ self.drawItem(bbstring % title, link, img)
+ self.route['last_listing_item'] = last_listing_item
+ self.navi_save('history')
+
+ def history_action(self, action, addtime, fav):
+ db = HistoryDB()
+
+ if action == 'delete':
+ db.delete(addtime)
+ showMessage(self.localize('Search History'), self.localize('Deleted!'))
+
+ if action == 'fav' and fav == '0':
+ db.fav(addtime)
+ showMessage(self.localize('Favourites'), self.localize('Added!'))
+ elif action == 'fav':
+ db.unfav(addtime)
+ showMessage(self.localize('Favourites'), self.localize('Deleted!'))
+
+ self.navi_restore()
+
+ def watched(self, params = {}):
+ self.navi_route('watched', params)
+
+ db = WatchedHistoryDB()
+
+ items = db.get_all()
+ log('[WatchedHistory]: items - '+str(items))
+ if items:
+ for addtime, filename, foldername, path, url, seek, length, ind, size in items:
+ seek = int(seek) if int(seek) > 3*60 else 0
+ watchedPercent = int((float(seek) / float(length if length else 1)) * 100)
+ duration = '%02d:%02d:%02d' % ((length / (60*60)), (length / 60) % 60, length % 60)
+ title = '[%d%%][%s] %s [%d MB]' %\
+ (watchedPercent, duration, filename.encode('utf-8'), int(size))
+ clDimgray = '[COLOR FF696969]%s[/COLOR]'
+ clWhite = '[COLOR FFFFFFFF]%s[/COLOR]'
+
+ title = clWhite % title + chr(10) + clDimgray % '(%s)' % foldername.encode('utf-8')
+
+ if watchedPercent >= 85:
+ img = __root__ + '/icons/stop-icon.png'
+ else:
+ img = __root__ + '/icons/pause-icon.png'
+
+
+ link = {'mode': 'watched_item', 'addtime': str(addtime)}
+ self.drawItem(title, link, image=img)
+ self.navi_save('watched')
+
+ def watched_action(self, action, addtime):
+ db = WatchedHistoryDB()
+
+ if action == 'delete':
+ db.delete(addtime)
+ showMessage(self.localize('Watched History'), self.localize('Deleted!'))
+ self.navi_restore()
+
+ if action == 'open':
+ filename, foldername, path, url, seek, length, ind = db.get('filename, foldername, path, url, seek, length, ind', 'addtime', str(addtime))
+ params = {'link': path.encode('utf-8')}
+ self.open_torrent(params)
+
+ if action == 'playnoseek' or action == 'playwithseek':
+ filename, path, url, seek, length, ind = db.get('filename, path, url, seek, length, ind', 'addtime', str(addtime))
+
+ if action == 'playwithseek':
+ seek = int(seek)
+ else:
+ seek = 0
+
+ if os.path.exists(path):
+ __settings__.setSetting("lastTorrent", path)
+ else:
+ from Downloader import Downloader
+ torrent = Downloader.Torrent(self.userStorageDirectory, torrentFilesDirectory=self.torrentFilesDirectory)
+ __settings__.setSetting("lastTorrent", torrent.saveTorrent(url))
+ xbmc.executebuiltin('xbmc.RunPlugin("plugin://plugin.video.torrenter/?action=playTorrent&url='+str(ind)+'&seek='+str(seek)+'")')
+ __settings__.setSetting('loadsw_onstop', 'true')
+ self.close()
+
+ if action == 'clear':
+ db.clear()
+ showMessage(self.localize('Watched History'), self.localize('Clear!'))
+ self.navi_restore()
+
+ def browser(self, params = {}):
+ from resources.utorrent.net import Download
+ menu, dirs = [], []
+
+ get = params.get
+ hash = get('hash')
+ tdir = get('tdir')
+
+ DownloadList = Download().list()
+ if DownloadList == False:
+ showMessage(self.localize('Error'), self.localize('No connection! Check settings!'), forced=True)
+ return
+
+ if not hash:
+ self.navi_route('browser')
+ for data in DownloadList:
+ status = " "
+ img = ''
+ if data['status'] in ('seed_pending', 'stopped'):
+ status = TextBB(' [||] ', 'b')
+ elif data['status'] in ('seeding', 'downloading'):
+ status = TextBB(' [>] ', 'b')
+ if data['status'] == 'seed_pending':
+ img = os.path.join(__root__, 'icons', 'pause-icon.png')
+ elif data['status'] == 'stopped':
+ img = os.path.join(__root__, 'icons', 'stop-icon.png')
+ elif data['status'] == 'seeding':
+ img = os.path.join(__root__, 'icons', 'upload-icon.png')
+ elif data['status'] == 'downloading':
+ img = os.path.join(__root__, 'icons', 'download-icon.png')
+
+ title = '[%s%%]%s%s [%s]' % (str(data['progress']), status, data['name'], str(data['ratio']))
+ menu.append(
+ {"title": title, "image": img, "argv": {'mode': 'browser_item', 'hash': str(data['id'])}})
+ elif not tdir:
+ self.navi_route('browser', params, 'browser_subfolder')
+ self.drawItem('..', {'mode': 'browser_moveup'}, image = 'DefaultFolderBack.png', isFolder = True)
+ dllist = sorted(Download().listfiles(hash), key=lambda x: x[0])
+ for name, percent, ind, size in dllist:
+ if '/' not in name:
+ title = '[%s%%][%s]%s' % (str(percent), str(size), name)
+ menu.append({"title": title, "image": '',
+ "argv": {'mode': 'browser_file', 'hash': hash, 'ind': str(ind)}})
+ else:
+ newtdir = name.split('/')[0]
+ if newtdir not in dirs: dirs.append(newtdir)
+ elif tdir:
+ self.navi_route('browser', params, 'browser_subfolder')
+ self.drawItem('..', {'mode': 'browser_moveup'}, isFolder=True)
+ dllist = sorted(Download().listfiles(hash), key=lambda x: x[0])
+ for name, percent, ind, size in dllist:
+
+ if name[:len(tdir)] == tdir:
+ name = name[len(tdir) + 1:]
+ if '/' not in name:
+ title = '[%s%%][%s]%s' % (str(percent), str(size), name)
+ menu.append({"title": title, "image": '',
+ "argv": {'mode': 'browser_file', 'hash': hash, 'ind': str(ind)}})
+ else:
+ newtdir = tdir+'/'+name.split('/')[0]
+ if newtdir not in dirs: dirs.append(newtdir)
+
+ for tdir in dirs:
+ params = {'mode': 'browser_subfolder', 'hash': hash, 'tdir': tdir}
+ title = tdir.split('/')[-1] if '/' in tdir else tdir
+ self.drawItem(title, params, isFolder = True)
+
+ for i in menu:
+ params = i['argv']
+ img = i['image']
+ popup = []
+ if not hash:
+ folder = True
+ else:
+ folder = False
+
+ self.drawItem(i['title'], params, image = img, isFolder = folder)
+
+ self.navi_save('browser')
+
+ def browser_action(self, hash, action, tdir = None, ind = None):
+ from resources.utorrent.net import Download
+ menu = []
+
+ DownloadList = Download().list()
+ if DownloadList == False:
+ showMessage(self.localize('Error'), self.localize('No connection! Check settings!'), forced=True)
+ return False
+
+ if (ind or ind == 0) and action in ('0', '3'):
+ Download().setprio_simple(hash, action, ind)
+ elif action in ['play', 'copy']:
+ p, dllist, i, folder, filename = DownloadList, Download().listfiles(hash), 0, None, None
+ for data in p:
+ if data['id'] == hash:
+ folder = data['dir']
+ break
+ if isRemoteTorr():
+ torrent_dir = __settings__.getSetting("torrent_dir")
+ torrent_replacement = __settings__.getSetting("torrent_replacement")
+ empty = [None, '']
+ if torrent_dir in empty or torrent_replacement in empty:
+ if xbmcgui.Dialog().yesno(
+ self.localize('Remote Torrent-client'),
+ self.localize('You didn\'t set up replacement path in setting.'),
+ self.localize('For example /media/dl_torr/ to smb://SERVER/dl_torr/. Setup now?')):
+ if torrent_dir in empty:
+ torrent_dir()
+ __settings__.openSettings()
+ return
+
+ folder = folder.replace(torrent_dir, torrent_replacement)
+ if (ind or ind == 0) and action == 'play':
+ for data in dllist:
+ if data[2] == int(ind):
+ filename = data[0]
+ break
+ filename = os.path.join(folder, filename)
+ self.file_play(filename)
+ elif tdir and action == 'copy':
+ path = os.path.join(folder, tdir)
+ dirs, files = xbmcvfs.listdir(path)
+ if len(dirs) > 0:
+ dirs.insert(0, self.localize('./ (Root folder)'))
+ for dd in dirs:
+ dd = file_decode(dd)
+ dds = xbmcvfs.listdir(os.path.join(path, dd))[0]
+ if len(dds) > 0:
+ for d in dds:
+ dirs.append(dd + os.sep + d)
+ ret = xbmcgui.Dialog().select(self.localize('Choose directory:'), dirs)
+ if ret > 0:
+ path = os.path.join(path, dirs[ret])
+ dirs, files = xbmcvfs.listdir(path)
+ for file in files:
+ if not xbmcvfs.exists(os.path.join(path, file)):
+ xbmcvfs.delete(os.path.join(path, file))
+ xbmcvfs.copy(os.path.join(path, file), os.path.join(folder, file))
+ i = i + 1
+ showMessage(self.localize('Torrent-client Browser'), self.localize('Copied %d files!') % i, forced=True)
+ return True
+ elif not tdir and action not in ('0', '3'):
+ if action == 'removedata':
+ ok = xbmcgui.Dialog().yesno(self.localize('Torrent-client Browser'),
+ self.localize('Delete torrent with files?'))
+ if not ok: sys.exit(1)
+ Download().action_simple(action, hash)
+ elif action in ('0', '3'):
+ dllist = sorted(Download().listfiles(hash), key=lambda x: x[0])
+ for name, percent, ind, size in dllist:
+ if tdir:
+ if '/' in name and tdir in name:
+ menu.append((hash, action, str(ind)))
+ else:
+ menu.append((hash, action, str(ind)))
+ Download().setprio_simple_multi(menu)
+ return True
+ return True
+
+ def downloadstatus(self, params = {}):
+ self.navi_route('downloadstatus', params)
+
+ db = DownloadDB()
+ items = db.get_all()
+
+ if items:
+ for addtime, title, path, type, info, status, torrent, ind, lastupdate, storage in items:
+ jsoninfo = json.loads(urllib.unquote_plus(info))
+
+ if status != 'stopped' and int(lastupdate) < int(time.time()) - 10:
+ status = 'stopped'
+ db.update_status(addtime, status)
+
+ progress = int(jsoninfo.get('progress'))
+ if status == 'pause':
+ status_sign = '[||]'
+ img = os.path.join(__root__, 'icons', 'pause-icon.png')
+ elif status == 'stopped':
+ status_sign = '[X]'
+ img = os.path.join(__root__, 'icons', 'stop-icon.png')
+ else:
+ status_sign = '[>]'
+ if progress == 100:
+ img = os.path.join(__root__, 'icons', 'upload-icon.png')
+ else:
+ img = os.path.join(__root__, 'icons', 'download-icon.png')
+
+ title = '[%d%%]%s %s' % (progress, status_sign, title)
+ if jsoninfo.get('seeds') != None and jsoninfo.get('peers') != None and \
+ jsoninfo.get('download') != None and jsoninfo.get('upload') != None:
+ d, u = float(jsoninfo['download']) / 1000000, float(jsoninfo['upload']) / 1000000
+ s, p = str(jsoninfo['seeds']), str(jsoninfo['peers'])
+ second = '[D/U %.2f/%.2f (MB/s)][S/L %s/%s]' % (d, u, s, p)
+ title = dlstat_titleMake('[B]%s[/B]' % title if type == 'folder' else title, second)
+
+ params = {'addtime': addtime, 'type': type, 'path': path,
+ 'status': status, 'progress': progress, 'storage': storage}
+ params['mode'] = 'downloadstatus_subfolder' if type == 'folder' else 'downloadstatus_file'
+
+ self.drawItem(title, params, image=img, isFolder=type == 'folder')
+
+ # def drawItem(self, title, params, image = None, isFolder = False):
+
+ self.navi_save('downloadstatus')
+
+ def downloadstatus_action(self, action, addtime, path, type, progress, storage):
+
+ db = DownloadDB()
+
+ if action == 'play':
+ if type == 'file' and progress > 30 or progress == 100:
+ self.file_browser(type, path, path)
+ else:
+ showMessage(self.localize('Download Status'), self.localize('Download has not finished yet'))
+
+ elif action == 'delete':
+ db.delete(addtime)
+ showMessage(self.localize('Download Status'), self.localize('Stopped and Deleted!'))
+
+ elif action == 'pause':
+ db.update_status(addtime, 'pause')
+ showMessage(self.localize('Download Status'), self.localize('Paused!'))
+
+ elif action == 'stop':
+ db.update_status(addtime, 'stopped')
+ showMessage(self.localize('Download Status'), self.localize('Stopped!'))
+
+ elif action == 'start':
+ start = db.get_byaddtime(addtime)
+ if start[5] == 'pause':
+ db.update_status(addtime, 'downloading')
+ showMessage(self.localize('Download Status'), self.localize('Unpaused!'))
+ else:
+ torrent, ind = start[6], start[7]
+
+ del db
+
+ import SkorbaLoader
+ __settings__.setSetting("lastTorrent", torrent.encode('utf-8'))
+ torrent = SkorbaLoader.SkorbaLoader(storage.encode('utf-8'), torrent)
+ encryption = __settings__.getSetting('encryption') == 'true'
+ torrent.downloadProcess(ind, encryption)
+ showMessage(self.localize('Download Status'), self.localize('Started!'))
+ xbmc.sleep(1000)
+
+ elif action == 'masscontrol':
+ dialog_items = [self.localize('Start All'), self.localize('Stop All'),
+ self.localize('Clear %s') % self.localize('Download Status'), self.localize('Cancel')]
+ ret = xbmcgui.Dialog().select(self.localize('Mass Control'), dialog_items)
+ if ret == 0:
+ items = db.get_all()
+ del db
+ if items:
+ import SkorbaLoader
+ for addtime, title, path, type, info, status, torrent, ind, lastupdate, storage in items:
+ __settings__.setSetting("lastTorrent", torrent.encode('utf-8'))
+ torrent = SkorbaLoader.SkorbaLoader(storage.encode('utf-8'), torrent)
+ encryption = __settings__.getSetting('encryption') == 'true'
+ torrent.downloadProcess(ind, encryption)
+ xbmc.sleep(1000)
+
+ xbmc.sleep(2000)
+ showMessage(self.localize('Download Status'), self.localize('Started All!'))
+ elif ret == 1:
+ items = db.get_all()
+ if items:
+ for addtime, title, path, type, info, status, torrent, ind, lastupdate, storage in items:
+ db.update_status(addtime, 'stopped')
+ xbmc.sleep(1000)
+ showMessage(self.localize('Download Status'), self.localize('Stopped All!'))
+ elif ret == 2:
+ db.clear()
+ showMessage(self.localize('Download Status'), self.localize('Clear!'))
+
+ xbmc.sleep(1000)
+ self.downloadstatus()
+
+ def file_browser(self, params):
+ self.navi_route('file_browser', params)
+
+ get = params.get
+ mode = get('mode')
+ path = get('path')
+ tdir = get('tdir')
+
+ path = encode_msg(path)
+ tdir = encode_msg(tdir)
+
+ if mode == 'moveup' and tdir == os.path.dirname(path):
+ self.downloadstatus()
+ elif mode == 'file':
+ swPlayer().play(localize_path(tdir))
+ else:
+ self.drawItem('..', {'mode': 'moveup', 'path': path,
+ 'tdir': os.path.dirname(tdir)}, image = 'DefaultFolderBack.png', isFolder=True)
+
+ dirs, files = xbmcvfs.listdir(tdir + os.sep)
+ if len(dirs) > 0:
+ for dir in dirs:
+ link = {'mode': 'subfolder', 'path': path, 'type': 'folder',
+ 'tdir': os.path.join(tdir, dir)}
+ self.drawItem(dir, link, isFolder=True)
+ for file in files:
+ link = {'mode': 'file', 'path': path, 'type': 'file',
+ 'tdir': os.path.join(tdir, file)}
+ self.drawItem(file, link, isFolder=False)
+
+ self.navi_save('file_browser')
+
+ def file_play(self, file):
+ self.close()
+ swPlayer().play(item = file)
+
+ def open_torrent(self, params):
+ self.navi_route('open_torrent', params)
+
+ get = params.get
+ link = get('link')
+ tdir = get('tdir')
+
+ # cache
+ if link != self.navi['last_link']:
+ self.navi['contentList'], filename = get_contentList(link)
+ else:
+ filename = self.navi['last_filename']
+ self.navi['last_link'] = link
+ self.navi['last_filename'] = filename
+
+ dirList, contentListNew = cutFolder(self.navi['contentList'], tdir)
+
+ self.drawItem('..', {'mode': 'torrent_moveup', 'filename': link},
+ image = 'DefaultFolderBack.png', isFolder=True)
+
+ dirList = sorted(dirList, key=lambda x: x[0], reverse=False)
+ for title in dirList:
+ self.drawItem(title, {'mode': 'torrent_subfolder', 'tdir': title, 'filename': link}, isFolder=True)
+
+ ids_video_result = get_ids_video(contentListNew)
+ ids_video = ''
+
+ if len(ids_video_result) > 0:
+ for identifier in ids_video_result:
+ ids_video = ids_video + str(identifier) + ','
+
+ contentListNew = sorted(contentListNew, key=lambda x: x[0], reverse=False)
+ for title, identifier, filesize in contentListNew:
+ params = {'mode': 'torrent_play', 'index': identifier, 'url2': ids_video.rstrip(','), 'url': link,
+ 'filename': filename}
+ self.drawItem(title, params)
+
+ self.navi_save('open_torrent')
+
+ def get_menulist(self, mode):
+
+ label_list = ["Empty", "Empty", "Empty", "Empty", "Empty", "Empty", "Empty"]
+
+ if mode in ['search', 'search_item', 'torrent_play', 'open_torrent']:
+ label_list = [self.localize('Open'),
+ self.localize('Download via T-client'),
+ self.localize('Download via Libtorrent'),
+ self.localize('Info'),]
+ if mode in ['externalsearch', 'externalsearch_item']:
+ label_list = [self.localize('Add to %s') % self.return_name,
+ self.localize('Open'),
+ self.localize('Download via T-client'),
+ self.localize('Download via Libtorrent'),
+ self.localize('Info'),]
+ elif mode in ['torrent_subfolder', 'file_browser', 'subfolder']:
+ label_list = [self.localize('Open'),]
+ elif mode in ['torrent_moveup', 'browser_moveup']:
+ label_list = [self.localize('Move Up'),]
+ elif mode in ['file']:
+ label_list = [self.localize('Play'), ]
+ elif mode in ['history', 'history_item']:
+ label_list = [self.localize('Open'),
+ self.localize('Edit'),
+ self.localize('Individual Tracker Options'),
+ self.localize('Fav. / Unfav.'),
+ self.localize('Delete')]
+ elif mode in ['browser', 'browser_item']:
+ label_list = [self.localize('Open'), self.localize('Start'), self.localize('Stop'),
+ self.localize('Remove'), self.localize('High Priority'),
+ self.localize('Skip All Files'), self.localize('Remove with files')]
+ elif mode in ['browser_file']:
+ label_list = [self.localize('Play File'),
+ self.localize('High Priority'), self.localize('Skip File')]
+ elif mode in ['browser_subfolder']:
+ label_list = [self.localize('Open'),
+ self.localize('High Priority'),
+ self.localize('Skip All Files'),
+ self.localize('Copy in Root'), ]
+ elif mode in ['downloadstatus', 'downloadstatus_subfolder']:
+ label_list = [self.localize('Open'), self.localize('Start'), self.localize('Pause'),
+ self.localize('Stop'), self.localize('Delete'), self.localize('Mass Control'),]
+ elif mode in ['downloadstatus_file']:
+ label_list = [self.localize('Play'), self.localize('Start'), self.localize('Pause'),
+ self.localize('Stop'), self.localize('Delete'), self.localize('Mass Control'),]
+ elif mode in ['watched', 'watched_item']:
+ label_list = [self.localize('Open Torrent'), self.localize('Play (from start)'),
+ self.localize('Play (with seek)'), self.localize('Delete'), self.localize('Clear History'), ]
+ self.right_label_count = len(label_list)
+ return label_list
+
+ def context(self):
+ try:
+ focused_control = self.getFocus()
+ except:
+ focused_control = None
+ if focused_control == self.listing:
+ item = self.listing.getSelectedItem()
+ params = json.loads(item.getfilename())
+ mode = params.get('mode')
+ filename = params.get('filename')
+ label_list = self.get_menulist(mode)
+
+ if not self.version_check():
+ ret = xbmcgui.Dialog().select(self.localize('Context menu'), label_list)
+ else:
+ ret = xbmcgui.Dialog().contextmenu(list=[(x) for x in label_list])
+
+ if ret > -1 and ret < len(label_list):
+ getattr(self, "right_press" + str(ret + 1))()
+ elif focused_control == self.input_search:
+ self.input_search.setText('')
+
+ def right_menu(self, mode='place'):
+ if not mode == 'place':
+ self.last_right_buttons_count = self.right_buttons_count
+ remove_list = [getattr(self, "button_right" + str(index)) for index
+ in range(1, self.last_right_buttons_count + 1)]
+ self.disconnectEventList(remove_list)
+ self.removeControls(remove_list)
+
+ label_list = self.get_menulist(mode)
+ self.navi_right_menu = []
+
+ self.right_buttons_count = len(label_list)
+ button_num_list = range(1, self.right_buttons_count + 1)
+
+ for index in button_num_list:
+ setattr(self, "button_right" + str(index), pyxbmct.Button(label_list[index - 1]))
+ button = getattr(self, "button_right" + str(index))
+ self.connect(button, getattr(self, "right_press" + str(index)))
+ self.placeControl(button, index, 14, 1, 2)
+
+ # Navigation
+ self.navi['last_right_button'] = 1
+ for index in button_num_list:
+ button = getattr(self, "button_right" + str(index))
+ self.navi_right_menu.append(button)
+
+ if self.right_buttons_count == 1:
+ button.setNavigation(self.button_controlcenter,
+ self.button_right1, self.listing, self.input_search)
+ else:
+ if index == button_num_list[0]:
+ button.setNavigation(getattr(self, "button_right" + str(self.right_buttons_count)),
+ self.button_right2, self.listing, self.input_search)
+ elif index == button_num_list[-1]:
+ button.setNavigation(getattr(self, "button_right" + str(index - 1)), self.button_right1,
+ self.listing,
+ self.input_search)
+ else:
+ button.setNavigation(getattr(self, "button_right" + str(index - 1)),
+ getattr(self, "button_right" + str(index + 1)),
+ self.listing,
+ self.input_search)
+
+ self.set_menulist(mode)
+ self.set_navigation()
+
+ def set_menulist(self, mode):
+ self.count += 1
+ label_list = self.get_menulist(mode)
+ debug('set_menulist; ' + str(label_list))
+
+ button_num_list = range(1, self.right_label_count + 1)
+ debug('set_menulist button_num_list: ' + str(button_num_list))
+
+ for index in button_num_list:
+ button = getattr(self, "button_right" + str(index))
+ self.setlabel(button, (label_list[index - 1]))
+ button.setEnabled(True)
+
+ if self.right_buttons_count > self.right_label_count:
+ disable_button_num_list = range(self.right_label_count + 1, self.right_buttons_count + 1)
+ debug('set_menulist disable_button_num_list: ' + str(disable_button_num_list))
+ for index in disable_button_num_list:
+ button = getattr(self, "button_right" + str(index))
+ button.setLabel(' ')
+ button.setEnabled(False)
+
+ def setlabel(self, button, label):
+ label = label.decode('utf-8')
+
+ debug('setlabel: ' + label + ' ' + str(len(label)))
+
+ if len(label) > 10:
+ spaces = label.count(' ')
+ debug('setlabel spaces=' + str(spaces))
+ if spaces == 0:
+ words = [label[:10], label[10:]]
+ label = '%s-\r\n%s' % (words[0], words[1])
+ elif spaces == 1:
+ words = label.split(' ')
+ label = '%s\r\n%s' % (words[0], words[1])
+ elif spaces == 2:
+ words = label.split(' ')
+ if len(words[0]) <= len(words[2]):
+ words[0] = words[0] + ' ' + words[1]
+ words[1] = words[2]
+ else:
+ words[1] = words[1] + ' ' + words[2]
+ label = '%s\r\n%s' % (words[0], words[1])
+
+ button.setLabel(label)
+
+ def right_press1(self):
+ self.right_press(1)
+
+ def right_press2(self):
+ self.right_press(2)
+
+ def right_press3(self):
+ self.right_press(3)
+
+ def right_press4(self):
+ self.right_press(4)
+
+ def right_press5(self):
+ self.right_press(5)
+
+ def right_press6(self):
+ self.right_press(6)
+
+ def right_press7(self):
+ self.right_press(7)
+
+ def right_press(self, index):
+ item = self.listing.getSelectedItem()
+ params = json.loads(item.getfilename())
+ log('right_press %d params %s' % (index, str(params)))
+ mode = params.get('mode')
+ filename = params.get('filename')
+ hash = params.get('hash')
+ ind = params.get('ind')
+ tdir = params.get('tdir')
+ action = None
+
+ if mode in ['search_item', 'torrent_subfolder', 'externalsearch', 'externalsearch_item']:
+ if mode in ['externalsearch', 'externalsearch_item']:
+ index = index - 1
+
+ if index == 0:
+ url = params.get('back_url') + '&stringdata=' + urllib.quote_plus(params.get('stringdata'))
+ xbmc.executebuiltin('xbmc.RunPlugin("%s")' % (url))
+ elif index == 1:
+ params = {'link': filename, 'tdir': tdir}
+ self.open_torrent(params)
+ elif index == 2:
+ action = 'downloadFilesList'
+ link = {'url': filename}
+ url = self.form_link(action, link)
+ xbmc.executebuiltin('xbmc.RunPlugin("%s")' % (url))
+ elif index == 3:
+ action = 'downloadLibtorrent'
+ link = {'url': filename}
+ url = self.form_link(action, link)
+ xbmc.executebuiltin('xbmc.RunPlugin("%s")' % (url))
+ elif index == 4: #search_item
+ cleanlabel = re.sub('\[[^\]]*\]', '', item.getLabel())
+ ttl, yr = xbmc.getCleanMovieTitle(cleanlabel)
+ infoW = InfoWindow(ttl, yr)
+ infoW.doModal()
+ del infoW
+ elif mode in ['torrent_moveup', 'browser_moveup', 'moveup']:
+ self.navi_back()
+ elif mode == 'torrent_play':
+ if index == 1:
+ if filename and xbmcvfs.exists(filename):
+ params['url'] = ensure_str(filename)
+ url = self.form_link('playSTRM', params)
+ xbmc.executebuiltin('xbmc.RunPlugin("%s")' % (url))
+ __settings__.setSetting('loadsw_onstop', 'true')
+ self.close()
+ elif index == 2:
+ action = 'downloadFilesList'
+ link = {'ind': str(params.get('url'))}
+ url = self.form_link(action, link)
+ xbmc.executebuiltin('xbmc.RunPlugin("%s")' % (url))
+ elif index == 3:
+ action = 'downloadLibtorrent'
+ link = {'ind': str(params.get('url'))}
+ url = self.form_link(action, link)
+ xbmc.executebuiltin('xbmc.RunPlugin("%s")' % (url))
+ elif mode == 'history_item':
+ addtime = params.get('addtime')
+ fav = params.get('fav')
+ query = params.get('query')
+ if index == 1:
+ self.input_search.setText(query)
+ self.search({'addtime': addtime})
+ elif index == 2:
+ self.input_search.setText(query)
+ self.setFocus(self.input_search)
+ elif index == 3:
+ params['title'] = params.get('query')
+ self.controlCenter(params)
+ else:
+ if index == 4: action = 'fav'
+ elif index == 5: action = 'delete'
+ self.history_action(action, addtime, fav)
+ elif mode in ['browser_item', 'browser_subfolder']:
+ if index == 1:
+ self.browser(params)
+ elif index in [2, 3, 4] and mode =='browser_subfolder':
+ if index == 2: action = '3'
+ elif index == 3: action = '0'
+ elif index == 4: action = 'copy'
+
+ self.browser_action(hash, action, tdir=tdir, ind=ind)
+ else:
+ if index == 2: action = 'start'
+ elif index == 3: action = 'stop'
+ elif index == 4: action = 'remove'
+ elif index == 5: action = '3'
+ elif index == 6: action = '0'
+ elif index == 7: action = 'removedata'
+
+ if self.browser_action(hash, action):
+ self.navi_restore()
+ elif mode == 'browser_file':
+ if index == 1: action = 'play'
+ elif index == 2: action = '3'
+ elif index == 3: action = '0'
+
+ self.browser_action(hash, action, tdir = tdir, ind = ind)
+ elif mode in ['downloadstatus', 'downloadstatus_subfolder', 'downloadstatus_file']:
+ if index == 1: action = 'play'
+ elif index == 2: action = 'start'
+ elif index == 3: action = 'pause'
+ elif index == 4: action = 'stop'
+ elif index == 5: action = 'delete'
+ elif index == 6: action = 'masscontrol'
+ self.downloadstatus_action(action, params.get('addtime'), params.get('path'),
+ params.get('type'), params.get('progress'), params.get('storage'))
+ elif mode in ['subfolder', 'file']:
+ self.file_browser(params)
+ elif mode == 'watched_item':
+ if index == 1: action = 'open'
+ elif index == 2: action = 'playnoseek'
+ elif index == 3: action = 'playwithseek'
+ elif index == 4: action = 'delete'
+ elif index == 5: action = 'clear'
+ self.watched_action(action, params.get('addtime'))
+
+ def localize(self, string):
+ try:
+ return Localization.localize(string)
+ except:
+ return string
+
+ def drawItem(self, title, params, image=None, isFolder=False):
+ if isinstance(params, str):
+ params = {'mode': params}
+
+ if not image and isFolder:
+ image = 'DefaultFolder.png'
+ elif not image:
+ image = 'DefaultVideo.png'
+ listitem = xbmcgui.ListItem(title, '', image, image, json.dumps(params))
+ self.listing.addItem(listitem)
+
+ def form_link(self, action, link):
+ if isinstance(link, dict):
+ link_url = ''
+ for key in link.keys():
+ if link.get(key) and key != 'mode':
+ link_url = '%s&%s=%s' % (link_url, key, urllib.quote_plus(ensure_str(link.get(key))))
+ url = '%s?action=%s' % ('plugin://plugin.video.torrenter/', action) + link_url
+ else:
+ url = '%s?action=%s&url=%s' % ('plugin://plugin.video.torrenter/', action, urllib.quote_plus(link))
+
+ return url
+
+ def controlcenter(self, params={}):
+ import controlcenter
+ controlcenter.main()
+
+ def reconnect(self, event, callable):
+ self.disconnect(event)
+ self.connect(event, callable)
+
+ def version_check(self):
+ return False if int(xbmc.getInfoLabel("System.BuildVersion")[:2]) < 17 else True
+
+ def filter(self):
+ list = self.listing
+ self.listing.setPageControlVisible(True)
+ size = self.listing.size()
+ if size > 0:
+ for index in range(0, size):
+ listitem = self.listing.getListItem(index)
+
+class InfoWindow(pyxbmct.AddonDialogWindow):
+ def __init__(self, title="", year=""):
+ super(InfoWindow, self).__init__(title)
+ self.title = title
+ self.year = year
+ self.setGeometry(600, 600, 3, 3)
+ self.set_controls()
+ self.connect_controls()
+ # self.set_navigation()
+
+ def set_controls(self):
+ # pyxbmct.AddonWindow().setImage(__root__ + '/resources/skins/Default/media/ConfluenceDialogBack.png')
+ # self.placeControl(self.background, 0, 0, rowspan=3, columnspan=2)
+ self.listing = pyxbmct.List(_imageWidth=30, _imageHeight=30, _itemTextXOffset=1,
+ _itemTextYOffset=0, _itemHeight=30, _space=0, _alignmentY=0)
+ self.placeControl(self.listing, 0, 1, 2, 2)
+ self.logoimg = pyxbmct.Image('', aspectRatio=0)
+ self.placeControl(self.logoimg, 0, 0, rowspan=2)
+ self.plot = pyxbmct.TextBox()
+ self.placeControl(self.plot, 2, 0, 1, columnspan=3)
+ self.plot.autoScroll(1000, 1000, 1000)
+ # self.button_search = pyxbmct.Button("Search")
+ # self.placeControl(self.button_search, 0, 5, 1, 2)
+
+ def connect_controls(self):
+ from resources.scrapers.scrapers import Scrapers
+ self.Scraper = Scrapers()
+ meta = self.Scraper.scraper('tmdb', {'label': 'tmdb', 'search': self.title, 'year': ''}, 'en')
+ meta = meta.get('info')
+
+ """
+ meta results for xXx
+ {'info': {'count': 7451, 'plot': u'Xander Cage is your standard adrenaline junkie with no fear and a lousy attitude. When the US Government "recruits" him to go on a mission, he\'s not exactly thrilled. His mission: to gather information on an organization that may just be planning the destruction of the world, led by the nihilistic Yorgi.', 'votes': u'809', 'code': u'tt0295701', 'rating': 5.7000000000000002, 'title': u'xXx', 'tagline': u'A New Breed Of Secret Agent.', 'director': u'Rob Cohen', 'premiered': u'2002-08-09', 'originaltitle': u'xXx', 'cast': [u'Vin Diesel', u'Asia Argento', u'Marton Csokas', u'Samuel L. Jackson', u'Michael Roof', u'Petr J\xe1kl Jr.', u'Richy M\xfcller', u'Joe Bucaro III', u'Eve', u'Leila Arcieri', u'William Hope', u'Ted Maynard', u'Martin Hub'], 'castandrole': [u'Vin Diesel|Xander Cage', u'Asia Argento|Yelena', u'Marton Csokas|Yorgi', u'Samuel L. Jackson|Agent Gibbons', u'Michael Roof|Agent Toby Lee Shavers', u'Petr J\xe1kl Jr.|Kolya', u'Richy M\xfcller|Milan Sova', u'Joe Bucaro III|Virg', u'Eve|J.J.', u'Leila Arcieri|Jordan King', u'William Hope|Agent Roger Donnan', u'Ted Maynard|James Tannick', u'Martin Hub|Ivan Podrov'], 'studio': u'Columbia Pictures, Original Film, Revolution Studios', 'year': 2002, 'genre': u'Action', 'runtime': u'124'}, 'thumbnail': u'http://image.tmdb.org/t/p/original/fPHNTG1OXFBQ6aEVO7Lv8tSgfrY.jpg', 'label': 'tmdb', 'properties': {'fanart_image': u'http://image.tmdb.org/t/p/original/oNQIcuvJssiK93TjrXVtbERaKE1.jpg'}, 'icon': u'http://image.tmdb.org/t/p/original/fPHNTG1OXFBQ6aEVO7Lv8tSgfrY.jpg'}
+ """
+ self.connect(pyxbmct.ACTION_NAV_BACK, self.close)
+ self.connect(pyxbmct.ACTION_PREVIOUS_MENU, self.close)
+ self.listing.addItem("Title: %s" % meta.get('title'))
+ self.listing.addItem("genre: %s" % meta.get('genre'))
+ self.listing.addItem("rating: %s" % meta.get('rating'))
+ self.listing.addItem("year: %s" % meta.get('year'))
+ self.listing.addItem("runtime: %sm" % meta.get('runtime'))
+ if meta.get('thumbnail'):
+ self.logoimg.setImage(meta.get('thumbnail'))
+ self.plot.setText(meta.get('plot'))
+
+def log(msg):
+ try:
+ xbmc.log("#SW# [%s]: %s" % (__plugin__, msg,), level=xbmc.LOGNOTICE)
+ except UnicodeEncodeError:
+ xbmc.log("#SW# [%s]: %s" % (__plugin__, msg.encode("utf-8", "ignore"),), level=xbmc.LOGNOTICE)
+ except:
+ xbmc.log("#SW# [%s]: %s" % (__plugin__, 'ERROR LOG',), level=xbmc.LOGNOTICE)
+
+def titleMake(seeds, leechers, size, title):
+ # AARRGGBB
+ clGreen = '[COLOR FF008000]%s[/COLOR]'
+ clDodgerblue = '[COLOR FF1E90FF]%s[/COLOR]'
+ clDimgray = '[COLOR FF999999]%s[/COLOR]'
+ clWhite = '[COLOR FFFFFFFF]%s[/COLOR]'
+ clAliceblue = '[COLOR FFF0F8FF]%s[/COLOR]'
+ clRed = '[COLOR FFFF0000]%s[/COLOR]'
+
+ title = title.replace('720p', '[B]720p[/B]').replace('1080p', '[B]1080p[/B]')
+ title = clWhite % title
+ second = '[I](%s) [S/L: %d/%d] [/I]' % (size, seeds, leechers)
+ title += '\r\n' + clDimgray % second
+ return title
+
+def dlstat_titleMake(title, second):
+ # AARRGGBB
+ clDimgray = '[COLOR FF999999]%s[/COLOR]'
+ clWhite = '[COLOR FFFFFFFF]%s[/COLOR]'
+ title = clWhite % title
+ title += '\r\n' + clDimgray % second
+ return title
+
+def main(params = None):
+ dialog = SearchWindow(params)
+ dialog.doModal()
+ del dialog # You need to delete your instance when it is no longer needed
+ # because underlying xbmcgui classes are not grabage-collected.
+
+class swPlayer(xbmc.Player):
+ def play(self, item):
+ xbmc.Player().play(item = item)
+ i = 0
+ while not self.isPlaying() and i < 100:
+ i += 1
+ xbmc.sleep(500)
+ log('swPlayer not started '+str(i))
+
+ if i > 99:
+ return False
+ else:
+ while not xbmc.abortRequested and self.isPlaying():
+ xbmc.sleep(500)
+ log('swPlayer playing')
+
+ params = {'mode': 'load'}
+ main(params)
+
+if __name__ == '__main__':
+ try:
+ main()
+ except Exception, e:
+ import xbmc
+ import traceback
+
+ map(xbmc.log, traceback.format_exc().split("\n"))
+ raise