The branch, eden-pre has been updated
via 969e46d1ff679373f1cdd7c24a50b16b1e67a128 (commit)
via 0da2f410378a81c7ecb2870bcbc6ba46da393cef (commit)
from 0eddba994a7f2cf82e6fc4a39a835aeab602ab5a (commit)
- Log -----------------------------------------------------------------
http://xbmc.git.sourceforge.net/git/gitweb.cgi?p=xbmc/scripts;a=commit;h=969e46d1ff679373f1cdd7c24a50b16b1e67a128
commit 969e46d1ff679373f1cdd7c24a50b16b1e67a128
Author: amet <[email protected]>
Date: Tue Sep 13 01:02:18 2011 +0400
[script.tvguide] - v 1.0.1
- Made paging of channels more logical to navigate
- Better handling of errors if EPG data is unavailable
- Improved visual feedback while loading
- Added option in settings to clear cached EPG data (useful if you change
source)
diff --git a/script.tvguide/addon.xml b/script.tvguide/addon.xml
index 202d8ec..8a6972a 100644
--- a/script.tvguide/addon.xml
+++ b/script.tvguide/addon.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<addon id="script.tvguide"
name="TV Guide"
- version="1.0.0"
+ version="1.0.1"
provider-name="twinther [[email protected]]">
<requires>
<import addon="xbmc.python" version="2.0"/>
diff --git a/script.tvguide/changelog.txt b/script.tvguide/changelog.txt
index 25e68bd..f17d501 100644
--- a/script.tvguide/changelog.txt
+++ b/script.tvguide/changelog.txt
@@ -1,3 +1,9 @@
+[B]Version 1.0.1 - 2011-09-10[/B]
+- Made paging of channels more logical to navigate
+- Better handling of errors if EPG data is unavailable
+- Improved visual feedback while loading
+- Added option in settings to clear cached EPG data (useful if you change
source)
+
[B]Version 1.0.0 - 2011-08-17[/B]
- Background loading of EPG data on XBMC startup (Only available in Eden)
- Otherwise same as v. 0.3.0.
diff --git a/script.tvguide/gui.py b/script.tvguide/gui.py
index e0cafb0..6f09607 100644
--- a/script.tvguide/gui.py
+++ b/script.tvguide/gui.py
@@ -37,6 +37,7 @@ class TVGuide(xbmcgui.WindowXML):
C_MAIN_DESCRIPTION = 4022
C_MAIN_IMAGE = 4023
C_MAIN_LOADING = 4200
+ C_MAIN_LOADING_PROGRESS = 4201
def __new__(cls, source):
return super(TVGuide, cls).__new__(cls, 'script-tvguide-main.xml',
ADDON.getAddonInfo('path'))
@@ -47,18 +48,18 @@ class TVGuide(xbmcgui.WindowXML):
self.source = source
self.controlToProgramMap = {}
self.focusX = 0
- self.channelIndex = 0
+ self.page = 0
# find nearest half hour
self.date = datetime.datetime.today()
self.date -= datetime.timedelta(minutes = self.date.minute % 30)
def onInit(self):
- self._redrawEpg(0, self.date)
+ self.onRedrawEPG(0, self.date)
self.getControl(self.C_MAIN_IMAGE).setImage('tvguide-logo-%s.png' %
self.source.KEY)
def onAction(self, action):
- if action.getId() == KEY_BACK or action.getId() == KEY_MENU or
action.getId() == KEY_NAV_BACK:
+ if action.getId() in [KEY_BACK, KEY_MENU, KEY_NAV_BACK]:
self.close()
return
@@ -67,8 +68,9 @@ class TVGuide(xbmcgui.WindowXML):
(left, top) = controlInFocus.getPosition()
currentX = left + (controlInFocus.getWidth() / 2)
currentY = top + (controlInFocus.getHeight() / 2)
- except TypeError, ex:
- return # ignore
+ except TypeError:
+ currentX = None
+ currentY = None
control = None
@@ -116,7 +118,7 @@ class TVGuide(xbmcgui.WindowXML):
control = self._findControlOnLeft(currentX, currentY)
if control is None:
self.date -= datetime.timedelta(hours = 2)
- self._redrawEpg(self.channelIndex, self.date)
+ self.onRedrawEPG(self.page, self.date)
control = self._findControlOnLeft(1280, currentY)
(left, top) = control.getPosition()
@@ -127,7 +129,7 @@ class TVGuide(xbmcgui.WindowXML):
control = self._findControlOnRight(currentX, currentY)
if control is None:
self.date += datetime.timedelta(hours = 2)
- self._redrawEpg(self.channelIndex, self.date)
+ self.onRedrawEPG(self.page, self.date)
control = self._findControlOnRight(0, currentY)
(left, top) = control.getPosition()
@@ -137,32 +139,32 @@ class TVGuide(xbmcgui.WindowXML):
def _up(self, currentY):
control = self._findControlAbove(currentY)
if control is None:
- self.channelIndex = self._redrawEpg(self.channelIndex -
CHANNELS_PER_PAGE, self.date)
+ self.page = self.onRedrawEPG(self.page - 1, self.date)
control = self._findControlAbove(720)
return control
def _down(self, currentY):
control = self._findControlBelow(currentY)
if control is None:
- self.channelIndex = self._redrawEpg(self.channelIndex +
CHANNELS_PER_PAGE, self.date)
+ self.page = self.onRedrawEPG(self.page + 1, self.date)
control = self._findControlBelow(0)
return control
def _pageUp(self):
- self.channelIndex = self._redrawEpg(self.channelIndex -
CHANNELS_PER_PAGE, self.date)
+ self.page = self.onRedrawEPG(self.page - 1, self.date)
return self._findControlAbove(720)
def _pageDown(self):
- self.channelIndex = self._redrawEpg(self.channelIndex +
CHANNELS_PER_PAGE, self.date)
+ self.page = self.onRedrawEPG(self.page+ 1, self.date)
return self._findControlBelow(0)
- def _redrawEpg(self, startChannel, startTime):
- for controlId in self.controlToProgramMap.keys():
- self.removeControl(self.getControl(controlId))
-
+ def onRedrawEPG(self, page, startTime):
+ oldControltoProgramMap = self.controlToProgramMap.copy()
self.controlToProgramMap.clear()
+
+ progressControl = self.getControl(self.C_MAIN_LOADING_PROGRESS)
+ progressControl.setPercent(0)
self.getControl(self.C_MAIN_LOADING).setVisible(True)
- xbmc.sleep(250)
# move timebar to current time
timeDelta = datetime.datetime.today() - self.date
@@ -181,19 +183,30 @@ class TVGuide(xbmcgui.WindowXML):
# channels
channels = self.source.getChannelList()
- if startChannel < 0:
- startChannel = len(channels) - CHANNELS_PER_PAGE
- elif startChannel > len(channels) - CHANNELS_PER_PAGE:
- startChannel = 0
+ if channels is None:
+ self.onEPGLoadError()
+ return
+ totalPages = len(channels) / CHANNELS_PER_PAGE
+ if len(channels) % CHANNELS_PER_PAGE == 0:
+ totalPages -= 1
- controlsToAdd = list()
- for idx, channel in enumerate(channels[startChannel : startChannel +
CHANNELS_PER_PAGE]):
- if self.source.hasChannelIcons() and channel.logo is not None:
- self.getControl(4110 + idx).setImage(channel.logo)
- else:
- self.getControl(4010 + idx).setLabel(channel.title)
+ if page < 0:
+ page = totalPages
+ elif page > totalPages:
+ page = 0
+
+ channelStart = page * CHANNELS_PER_PAGE
+ channelEnd = page * CHANNELS_PER_PAGE + CHANNELS_PER_PAGE
- for program in self.source.getProgramList(channel):
+ controlsToAdd = list()
+ for idx, channel in enumerate(channels[channelStart : channelEnd]):
+ progressControl.setPercent(idx * 100 / CHANNELS_PER_PAGE)
+ programs = self.source.getProgramList(channel)
+ if programs is None:
+ self.onEPGLoadError()
+ return
+
+ for program in programs:
if program.endDate <= self.date:
continue
@@ -220,6 +233,10 @@ class TVGuide(xbmcgui.WindowXML):
controlsToAdd.append([control, program])
+ for controlId in oldControltoProgramMap:
+ self.removeControl(self.getControl(controlId))
+
+ # add program controls
for control, program in controlsToAdd:
self.addControl(control)
self.controlToProgramMap[control.getId()] = program
@@ -232,8 +249,25 @@ class TVGuide(xbmcgui.WindowXML):
self.getControl(self.C_MAIN_LOADING).setVisible(False)
- return startChannel
+ # set channel logo or text
+ channelsToShow = channels[channelStart : channelEnd]
+ for idx in range(0, CHANNELS_PER_PAGE):
+ if idx >= len(channelsToShow):
+ self.getControl(4110 + idx).setImage('')
+ self.getControl(4010 + idx).setLabel('')
+ else:
+ channel = channelsToShow[idx]
+ if self.source.hasChannelIcons() and channel.logo is not None:
+ self.getControl(4110 + idx).setImage(channel.logo)
+ else:
+ self.getControl(4010 + idx).setLabel(channel.title)
+ return page
+
+ def onEPGLoadError(self):
+ self.getControl(self.C_MAIN_LOADING).setVisible(False)
+ xbmcgui.Dialog().ok(strings(LOAD_ERROR_TITLE),
strings(LOAD_ERROR_LINE1), strings(LOAD_ERROR_LINE2))
+ self.close()
def _secondsToXposition(self, seconds):
return CELL_WIDTH_CHANNELS + (seconds * CELL_WIDTH / 1800)
@@ -280,12 +314,13 @@ class TVGuide(xbmcgui.WindowXML):
for controlId in self.controlToProgramMap.keys():
control = self.getControl(controlId)
- (left, top) = control.getPosition()
+ (leftEdge, top) = control.getPosition()
y = top + (control.getHeight() / 2)
if currentY < y:
- if(left <= self.focusX and left + control.getWidth() >
self.focusX
- and (nearestControl is None or
nearestControl.getPosition()[1] > top)):
+ rightEdge = leftEdge + control.getWidth()
+ if(leftEdge <= self.focusX < rightEdge
+ and (nearestControl is None or
nearestControl.getPosition()[1] > top)):
nearestControl = control
return nearestControl
@@ -295,12 +330,13 @@ class TVGuide(xbmcgui.WindowXML):
for controlId in self.controlToProgramMap.keys():
control = self.getControl(controlId)
- (left, top) = control.getPosition()
+ (leftEdge, top) = control.getPosition()
y = top + (control.getHeight() / 2)
if currentY > y:
- if(left <= self.focusX and left + control.getWidth() >
self.focusX
- and (nearestControl is None or
nearestControl.getPosition()[1] < top)):
+ rightEdge = leftEdge + control.getWidth()
+ if(leftEdge <= self.focusX < rightEdge
+ and (nearestControl is None or
nearestControl.getPosition()[1] < top)):
nearestControl = control
return nearestControl
diff --git a/script.tvguide/resources/language/Danish/strings.xml
b/script.tvguide/resources/language/Danish/strings.xml
index 20415f0..e736c45 100644
--- a/script.tvguide/resources/language/Danish/strings.xml
+++ b/script.tvguide/resources/language/Danish/strings.xml
@@ -7,5 +7,11 @@
<string id="30101">Kilde</string>
<string id="30102">Vis kanaler i kategori</string>
<string id="30103">XMLTV fil</string>
+ <string id="30104">Slet midlertidige filer...</string>
+ <string id="30105">Færdig!</string>
+
+ <string id="30110">Ups, det er pinligt!</string>
+ <string id="30111">Det var ikke muligt at indlæse program data,</string>
+ <string id="30112">prøv igen senere...</string>
</strings>
diff --git a/script.tvguide/resources/language/English/strings.xml
b/script.tvguide/resources/language/English/strings.xml
index 2bdac31..6529561 100644
--- a/script.tvguide/resources/language/English/strings.xml
+++ b/script.tvguide/resources/language/English/strings.xml
@@ -7,5 +7,12 @@
<string id="30101">Source</string>
<string id="30102">Show channels from category</string>
<string id="30103">XMLTV file</string>
+ <string id="30104">Clear cache...</string>
+ <string id="30105">Done!</string>
+
+ <string id="30110">Oops, sorry about that!</string>
+ <string id="30111">It was not possible to load program data,</string>
+ <string id="30112">please try again later...</string>
+
</strings>
diff --git a/script.tvguide/resources/settings.xml
b/script.tvguide/resources/settings.xml
index f97cca7..fac253e 100644
--- a/script.tvguide/resources/settings.xml
+++ b/script.tvguide/resources/settings.xml
@@ -9,6 +9,9 @@
visible="eq(-1,0)" />
<setting id="xmltv.file" label="30103" type="file" visible="eq(-2,3)"
/>
+
+ <setting type="sep" />
+ <setting label="30104" type="action"
action="RunScript($CWD/clear_cache.py)" />
</category>
</settings>
diff --git
a/script.tvguide/resources/skins/Default/720p/script-tvguide-main.xml
b/script.tvguide/resources/skins/Default/720p/script-tvguide-main.xml
index 5369f8d..4fb6b26 100644
--- a/script.tvguide/resources/skins/Default/720p/script-tvguide-main.xml
+++ b/script.tvguide/resources/skins/Default/720p/script-tvguide-main.xml
@@ -182,6 +182,7 @@
<width>160</width>
<height>45</height>
<aspectratio>keep</aspectratio>
+ <fadetime>500</fadetime>
</control>
<control type="image" id="4111">
<description>2nd channel</description>
@@ -190,6 +191,7 @@
<width>160</width>
<height>45</height>
<aspectratio>keep</aspectratio>
+ <fadetime>500</fadetime>
</control>
<control type="image" id="4112">
<description>3rd channel</description>
@@ -198,6 +200,7 @@
<width>160</width>
<height>45</height>
<aspectratio>keep</aspectratio>
+ <fadetime>500</fadetime>
</control>
<control type="image" id="4113">
<description>4th channel</description>
@@ -206,6 +209,7 @@
<width>160</width>
<height>45</height>
<aspectratio>keep</aspectratio>
+ <fadetime>500</fadetime>
</control>
<control type="image" id="4114">
<description>5th channel</description>
@@ -214,6 +218,7 @@
<width>160</width>
<height>45</height>
<aspectratio>keep</aspectratio>
+ <fadetime>500</fadetime>
</control>
<control type="image" id="4115">
<description>6th channel</description>
@@ -222,6 +227,7 @@
<width>160</width>
<height>45</height>
<aspectratio>keep</aspectratio>
+ <fadetime>500</fadetime>
</control>
<control type="image" id="4116">
<description>7th channel</description>
@@ -230,6 +236,7 @@
<width>160</width>
<height>45</height>
<aspectratio>keep</aspectratio>
+ <fadetime>500</fadetime>
</control>
<control type="image" id="4117">
<description>8th channel</description>
@@ -238,6 +245,7 @@
<width>160</width>
<height>45</height>
<aspectratio>keep</aspectratio>
+ <fadetime>500</fadetime>
</control>
</control><!-- end group -->
@@ -296,17 +304,35 @@
<texture>timebar.png</texture>
</control>
- <!-- loading splash -->
- <control type="label" id ="4200">
- <posx>0</posx>
- <posy>500</posy>
- <width>1280</width>
- <height>220</height>
- <label>$ADDON[script.tvguide 30001]</label>
- <textcolor>ffffffff</textcolor>
- <font>font30</font>
- <align>center</align>
- <aligny>center</aligny>
+
+ <control type="group" id="4200">
+ <posx>350</posx>
+ <posy>580</posy>
+ <width>580</width>
+ <height>60</height>
+
+ <control type="progress" id="4201">
+ <posx>0</posx>
+ <posy>0</posy>
+ <width>580</width>
+ <height>60</height>
+ <texturebg>cell-bg.png</texturebg>
+ <lefttexture />
+ <midtexture>cell-bg-selected.png</midtexture>
+ <righttexture />
+ </control>
+ <control type="label">
+ <description>loading splash</description>
+ <posx>0</posx>
+ <posy>10</posy>
+ <width>580</width>
+ <height>40</height>
+ <label>$ADDON[script.tvguide 30001]</label>
+ <textcolor>ffffffff</textcolor>
+ <font>font30</font>
+ <align>center</align>
+ <aligny>center</aligny>
+ </control>
</control>
</control><!-- id="5000" -->
diff --git a/script.tvguide/source.py b/script.tvguide/source.py
index e542225..0b77cc7 100644
--- a/script.tvguide/source.py
+++ b/script.tvguide/source.py
@@ -15,7 +15,7 @@ class Channel(object):
self.title = title
self.logo = logo
- def __str__(self):
+ def __repr__(self):
return 'Channel(id=%s, title=%s, logo=%s)' \
% (self.id, self.title, self.logo)
@@ -29,7 +29,7 @@ class Program(object):
self.imageLarge = imageLarge
self.imageSmall = imageSmall
- def __str__(self):
+ def __repr__(self):
return 'Program(channel=%s, title=%s, startDate=%s, endDate=%s,
description=%s, imageLarge=%s, imageSmall=%s)' % \
(self.channel, self.title, self.startDate, self.endDate,
self.description, self.imageLarge, self.imageSmall)
@@ -53,12 +53,19 @@ class Source(object):
except OSError:
cacheHit = False
+ channelList = None
if not cacheHit:
- channelList = self._getChannelList()
- pickle.dump(channelList, open(cacheFile, 'w'))
+ try:
+ channelList = self._getChannelList()
+ pickle.dump(channelList, open(cacheFile, 'w'))
+ except Exception, ex:
+ print "Unable to get channel list\n" + str(ex)
else:
channelList = pickle.load(open(cacheFile))
+ if channelList:
+ print "Loaded %d channels" % len(channelList)
+
return channelList
def _getChannelList(self):
@@ -68,18 +75,27 @@ class Source(object):
id = str(channel.id).replace('/', '')
cacheFile = os.path.join(self.cachePath, self.KEY + '-' + id +
'.programlist')
+ print cacheFile
+
try:
cachedOn =
datetime.datetime.fromtimestamp(os.path.getmtime(cacheFile))
cacheHit = cachedOn.day == datetime.datetime.now().day
except OSError:
cacheHit = False
+ programList = None
if not cacheHit:
- programList = self._getProgramList(channel)
- pickle.dump(programList, open(cacheFile, 'w'))
+ try:
+ programList = self._getProgramList(channel)
+ pickle.dump(programList, open(cacheFile, 'w'))
+ except Exception, ex:
+ print "Unable to get program list for channel: " + channel +
"\n" + str(ex)
else:
programList = pickle.load(open(cacheFile))
+ if programList:
+ print "Loaded %d programs for channel %s" % (len(programList),
channel.id)
+
return programList
def _getProgramList(self, channel):
@@ -230,9 +246,15 @@ class XMLTVSource(Source):
KEY = 'xmltv'
def __init__(self, settings):
- Source.__init__(self, settings, True)
self.xmlTvFile = settings['xmltv.file']
self.time = time.time()
+ try:
+ doc = self._loadXml()
+ hasChannelIcons = doc.find('channel/icon') is not None
+ except Exception:
+ hasChannelIcons = False
+
+ super(XMLTVSource, self).__init__(settings, hasChannelIcons)
# calculate nearest hour
self.time -= self.time % 3600
@@ -241,7 +263,10 @@ class XMLTVSource(Source):
doc = self._loadXml()
channelList = list()
for channel in doc.findall('channel'):
- c = Channel(id = channel.get('id'), title =
channel.findtext('display-name'), logo = channel.find('icon').get('src'))
+ logo = None
+ if channel.find('icon'):
+ logo = channel.find('icon').get('src')
+ c = Channel(id = channel.get('id'), title =
channel.findtext('display-name'), logo = logo)
channelList.append(c)
return channelList
diff --git a/script.tvguide/strings.py b/script.tvguide/strings.py
index 11aec71..f0efe26 100644
--- a/script.tvguide/strings.py
+++ b/script.tvguide/strings.py
@@ -6,6 +6,13 @@ NO_STREAM_AVAILABLE_TITLE = 30100
NO_STREAM_AVAILABLE_LINE1 = 30101
NO_STREAM_AVAILABLE_LINE2 = 30102
+CLEAR_CACHE = 30104
+CLEAR_CACHE_DONE = 30105
+
+LOAD_ERROR_TITLE = 30110
+LOAD_ERROR_LINE1 = 30111
+LOAD_ERROR_LINE2 = 30112
+
def strings(id, replacements = None):
string = xbmcaddon.Addon(id = 'script.tvguide').getLocalizedString(id)
if replacements is not None:
http://xbmc.git.sourceforge.net/git/gitweb.cgi?p=xbmc/scripts;a=commit;h=0da2f410378a81c7ecb2870bcbc6ba46da393cef
-----------------------------------------------------------------------
Summary of changes:
script.tvguide/addon.xml | 2 +-
script.tvguide/changelog.txt | 6 +
script.tvguide/clear_cache.py | 18 +
script.tvguide/gui.py | 104 ++-
.../resources/language/Danish/strings.xml | 6 +
.../resources/language/English/strings.xml | 7 +
script.tvguide/resources/settings.xml | 3 +
.../skins/Default/720p/script-tvguide-main.xml | 48 +-
.../skins/Default/media/tvguide-background.xcf | Bin 982043 -> 0 bytes
script.tvguide/source.py | 41 +-
script.tvguide/strings.py | 7 +
.../LICENSE.txt | 0
script.xbmc-pbx-addon/addon.xml | 21 +
.../backend_files/extensions_custom.conf.sample | 18 +
.../backend_files/manager_custom.conf | 6 +
.../backend_files/xbmc-pbx-addon.php | 248 +++++
script.xbmc-pbx-addon/bgservice.py | 258 +++++
script.xbmc-pbx-addon/changelog.txt | 68 ++
script.xbmc-pbx-addon/default.py | 336 +++++++
script.xbmc-pbx-addon/fanart.jpg | Bin 0 -> 394846 bytes
script.xbmc-pbx-addon/icon.png | Bin 0 -> 61096 bytes
.../resources/language/English/strings.xml | 110 ++
.../resources/lib/Asterisk/Manager.py | 1037 ++++++++++++++++++++
.../resources/lib/Asterisk/Util.py | 215 ++++
.../resources/lib/Asterisk/__init__.py | 46 +
.../resources/media/xbmc-pbx-addon.png | Bin 0 -> 63957 bytes
script.xbmc-pbx-addon/resources/settings.xml | 50 +
.../resources/skins/Default/720p/includes.xml | 2 +
.../resources/skins/Default/720p/main_gui.xml | 610 ++++++++++++
.../skins/Default/media/xbmc-pbx-addon.png | Bin 0 -> 63957 bytes
30 files changed, 3213 insertions(+), 54 deletions(-)
create mode 100644 script.tvguide/clear_cache.py
delete mode 100644
script.tvguide/resources/skins/Default/media/tvguide-background.xcf
copy {script.games.rom.collection.browser =>
script.xbmc-pbx-addon}/LICENSE.txt (100%)
create mode 100644 script.xbmc-pbx-addon/addon.xml
create mode 100644
script.xbmc-pbx-addon/backend_files/extensions_custom.conf.sample
create mode 100644 script.xbmc-pbx-addon/backend_files/manager_custom.conf
create mode 100644 script.xbmc-pbx-addon/backend_files/xbmc-pbx-addon.php
create mode 100644 script.xbmc-pbx-addon/bgservice.py
create mode 100644 script.xbmc-pbx-addon/changelog.txt
create mode 100644 script.xbmc-pbx-addon/default.py
create mode 100644 script.xbmc-pbx-addon/fanart.jpg
create mode 100644 script.xbmc-pbx-addon/icon.png
create mode 100644 script.xbmc-pbx-addon/resources/language/English/strings.xml
create mode 100644 script.xbmc-pbx-addon/resources/lib/Asterisk/Manager.py
create mode 100644 script.xbmc-pbx-addon/resources/lib/Asterisk/Util.py
create mode 100644 script.xbmc-pbx-addon/resources/lib/Asterisk/__init__.py
create mode 100755 script.xbmc-pbx-addon/resources/media/xbmc-pbx-addon.png
create mode 100644 script.xbmc-pbx-addon/resources/settings.xml
create mode 100644
script.xbmc-pbx-addon/resources/skins/Default/720p/includes.xml
create mode 100644
script.xbmc-pbx-addon/resources/skins/Default/720p/main_gui.xml
create mode 100644
script.xbmc-pbx-addon/resources/skins/Default/media/xbmc-pbx-addon.png
hooks/post-receive
--
Scripts
------------------------------------------------------------------------------
Doing More with Less: The Next Generation Virtual Desktop
What are the key obstacles that have prevented many mid-market businesses
from deploying virtual desktops? How do next-generation virtual desktops
provide companies an easier-to-deploy, easier-to-manage and more affordable
virtual desktop model.http://www.accelacomm.com/jaw/sfnl/114/51426474/
_______________________________________________
Xbmc-addons mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/xbmc-addons