Skip to content

Commit

Permalink
[v0.1.0] initial release
Browse files Browse the repository at this point in the history
  • Loading branch information
bluezed committed Feb 28, 2015
1 parent 4316d7c commit ef2e6f9
Show file tree
Hide file tree
Showing 9 changed files with 197 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,4 @@ docs/_build/

# PyBuilder
target/
Thumbs.db
File renamed without changes.
20 changes: 20 additions & 0 deletions addon.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<addon id="script.ftvguide_sync" name="FTV Guide Sync" version="0.1.0" provider-name="bluezed">
<requires>
<import addon="xbmc.python" version="2.19.0"/>
<import addon="script.module.requests" version="2.4.3"/>
</requires>
<extension point="xbmc.service" library="service.py" start="login"/>
<extension point="xbmc.addon.metadata">
<summary>FTV Guide Sync</summary>
<description>This Service will try to sync your FTV Guide database and settings with a WebDAV-compatible server that you can specify in the Service-Settings. This should allow you to have the same channels and settings across multiple devices.</description>
<disclaimer>PLEASE NOTE: This Service is still very much EXPERIMENTAL and there is still a risk that data might get lost!</disclaimer>
<language></language>
<platform>all</platform>
<license>GPLv2</license>
<forum>http://forums.tvaddons.ag/forums/181-FTV-GUIDE-FOR-KODI</forum>
<website></website>
<email>bluezed.apps@gmail.com</email>
<source>https://github.com/bluezed/script.ftvguide_sync</source>
</extension>
</addon>
4 changes: 4 additions & 0 deletions changelog.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
--------------------------
FTV Guide Sync - 0.1.0
--------------------------
+ Initial Release
Binary file added fanart.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions resources/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

11 changes: 11 additions & 0 deletions resources/settings.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<settings>
<setting type="lsep" label="To enable the service a restart of Kodi is required"/>
<setting id="service.enabled" label="Service enabled" type="bool" default="false" />
<setting id="service.interval" label="Sync-Interval (minutes)" type="number" default="15" />
<setting id="webdav.protocol" label="Protocol" type="labelenum" default="http" values="http|https" />
<setting id="webdav.url" label="Server Url" type="text" default="webdav.smartdrive.web.de" />
<setting id="webdav.user" label="Username" type="text" default="" />
<setting id="webdav.password" label="Password" type="text" option="hidden" default="" />
<setting id="webdav.folder" label="Remote folder" type="text" default="/FTVGuideSync" />
</settings>
160 changes: 160 additions & 0 deletions service.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
#
# FTV Guide Sync
# Copyright (C) 2015 Thomas Geppert
# [bluezed] - bluezed.apps@gmail.com
#
# 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 2, 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; see the file LICENSE.txt. If not, write to
# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
# http://www.gnu.org/copyleft/gpl.html
#
import xbmc
import xbmcaddon
import os
import datetime

from resources.lib import easywebdav

ADDON = xbmcaddon.Addon(id='script.ftvguide_sync')


class Sync():

webdav = None
localFolder = xbmc.translatePath(os.path.join('special://profile', 'addon_data', 'script.ftvguide'))
db = 'source.db'
settings = 'settings.xml'
lastMod = 0

protocol = ADDON.getSetting('webdav.protocol')
url = ADDON.getSetting('webdav.url')
user = ADDON.getSetting('webdav.user')
password = ADDON.getSetting('webdav.password')
remoteFolder = ADDON.getSetting('webdav.folder')

NO_CHANGE = 0
REMOTE_NEWER = 1
LOCAL_NEWER = 2

def __init__(self):
xbmc.log('[script.ftvguide_sync] Started...', level=xbmc.LOGNOTICE)

self.webdav = easywebdav.connect(self.url,
username=self.user,
password=self.password,
protocol=self.protocol)

if not self.webdav.exists(self.remoteFolder):
self.webdav.mkdir(self.remoteFolder)
xbmc.log('[script.ftvguide_sync] Folder created', level=xbmc.LOGNOTICE)
else:
xbmc.log('[script.ftvguide_sync] Folder exists', level=xbmc.LOGNOTICE)

self.doSync()

def doSync(self):
xbmc.log('[script.ftvguide_sync] Sync called', level=xbmc.LOGNOTICE)

ret = self.checkFile(self.settings)
if ret == self.LOCAL_NEWER:
self.uploadFile(self.settings)
elif ret == self.REMOTE_NEWER:
self.downloadFile(self.settings)

ret = self.checkFile(self.db)
if ret == self.LOCAL_NEWER:
self.uploadFile(self.db)
elif ret == self.REMOTE_NEWER:
self.downloadFile(self.db)

def checkFile(self, fName):
ret = self.NO_CHANGE
fPath = os.path.join(self.localFolder, fName)
localMod = datetime.datetime.utcfromtimestamp(os.path.getmtime(fPath))
xbmc.log('[script.ftvguide_sync] Local file "'+fName+'": ' + str(localMod), level=xbmc.LOGERROR)
remoteMod = self.getRemoteMod(fName)
xbmc.log('[script.ftvguide_sync] Remote file "'+fName+'": ' + str(remoteMod), level=xbmc.LOGERROR)
if remoteMod is None or localMod > remoteMod:
ret = self.LOCAL_NEWER
xbmc.log('[script.ftvguide_sync] Local file "'+fName+'" is newer', level=xbmc.LOGNOTICE)
elif localMod < remoteMod:
ret = self.REMOTE_NEWER
xbmc.log('[script.ftvguide_sync] Remote file "'+fName+'" is newer', level=xbmc.LOGNOTICE)
else:
xbmc.log('[script.ftvguide_sync] Files "'+fName+'" appear the same', level=xbmc.LOGNOTICE)
return ret

def getRemoteMod(self, fName):
mTime = None
remFile = self.remoteFolder + '/' + fName
try:
# returned data looks like this:
# [ File(name='/FTVGuideSync', size=0, mtime='Sat, 28 Feb 2015 11:23:22 GMT', ctime='2015-02-28T11:23:22Z', contenttype='httpd/unix-directory'),
# File(name='/FTVGuideSync/source.db', size=5121024, mtime='Sat, 28 Feb 2015 11:29:30 GMT', ctime='2015-02-28T11:23:23Z', contenttype='application/octetstream') ]
for fItem in self.webdav.ls(self.remoteFolder):
if fItem.contenttype != 'httpd/unix-directory' and fItem.name == remFile:
# 'Sat, 28 Feb 2015 11:29:30 GMT'
mTime = datetime.datetime.strptime(fItem.mtime, '%a, %d %b %Y %H:%M:%S %Z')
break
except:
xbmc.log('[script.ftvguide_sync] Error getting remote file listing', level=xbmc.LOGERROR)
return mTime

def uploadFile(self, fName):
localPath = os.path.join(self.localFolder, fName)
remotePath = self.remoteFolder + '/' + fName
try:
self.webdav.upload(localPath, remotePath)
self.updateModTime(fName)
xbmc.log('[script.ftvguide_sync] File "'+fName+'" uploaded', level=xbmc.LOGNOTICE)
except:
xbmc.log('[script.ftvguide_sync] Error uploading file "'+fName+'"', level=xbmc.LOGERROR)

def downloadFile(self, fName):
localPath = os.path.join(self.localFolder, fName)
remotePath = self.remoteFolder + '/' + fName
try:
self.webdav.download(remotePath, localPath)
self.updateModTime(fName)
xbmc.log('[script.ftvguide_sync] File "'+fName+'" downloaded', level=xbmc.LOGNOTICE)
except:
xbmc.log('[script.ftvguide_sync] Error downloading file "'+fName+'"', level=xbmc.LOGERROR)

def updateModTime(self, fName):
localPath = os.path.join(self.localFolder, fName)
remoteMod = self.getRemoteMod(fName)
td = remoteMod - datetime.datetime(1970,1,1)
# need to do it this way cause Android doesn't support .total_seconds() :(
self.lastMod = (td.microseconds + (td.seconds + td.days * 24 * 3600) * 10 ** 6) / 10 ** 6

os.utime(localPath, (self.lastMod, self.lastMod))
xbmc.log('[script.ftvguide_sync] Local file "'+fName+'" mod-time set to: ' + str(remoteMod), level=xbmc.LOGDEBUG)


if __name__ == '__main__':
if ADDON.getSetting('service.enabled') == 'true':
sync = Sync()
monitor = xbmc.Monitor()
while True:
# Sleep/wait for abort for the interval
interval = int(ADDON.getSetting('service.interval')) * 60
if monitor.waitForAbort(interval):
# Abort was requested while waiting. We should exit
break
if ADDON.getSetting('service.enabled') == 'true':
sync.doSync()
else:
xbmc.log('[script.ftvguide_sync] Has been stopped, exiting', level=xbmc.LOGNOTICE)
break
else:
xbmc.log('[script.ftvguide_sync] Not enabled, exiting', level=xbmc.LOGNOTICE)

0 comments on commit ef2e6f9

Please sign in to comment.