def checkMovie(self, movie): imdbNumber = movie["imdbnumber"] oldPosition = movie["top250"] if imdbNumber == "": util.logWarning("%(label)s: no IMDb id" % movie) return None if imdbNumber in self.top250: newPosition = self.top250[imdbNumber]["position"] self.notMissing.add(imdbNumber) if oldPosition == newPosition: util.logDebug("%(label)s: up to date" % movie) return None self.updateMovie(movie, newPosition) if oldPosition == 0: util.log("%s: added at position %s" % (movie["label"], newPosition)) return "added" util.log("%s: updated from %s to %s" % (movie["label"], oldPosition, newPosition)) return "updated" if oldPosition != 0: util.log("%(label)s: was removed because no more in IMDb Top250" % movie) self.updateMovie(movie, 0) return "removed"
def startLocalServer(self, port): """start a local server""" try: args = ['kajonggserver'] # the default if sys.argv[0].endswith('kajongg.py'): tryServer = sys.argv[0].replace('.py', 'server.py') if os.path.exists(tryServer): args = ['python', tryServer] if self.useSocket or os.name == 'nt': args.append('--local') if port: args.append('--port=%d' % port) if self.useSocket: args.append('--db=%slocal.db' % appdataDir()) if Debug.argString: args.append('--debug=%s' % Debug.argString) if Options.socket: args.append('--socket=%s' % Options.socket) process = subprocess.Popen(args, shell=os.name == 'nt') if Debug.connections: logDebug( m18n( 'started the local kajongg server: pid=<numid>%1</numid> %2', process.pid, ' '.join(args))) except OSError as exc: logException(exc)
def clientAction(self, client, move): """violation: player may not say mah jongg""" move.player.popupMsg(self) move.player.mayWin = False if Debug.originalCall: logDebug('%s: cleared mayWin' % move.player) return client.ask(move, [Message.OK])
def monitorPlayback(self, key, offset): progress = 0 #Whilst the file is playing back while xbmc.Player().isPlaying(): #Get the current playback time currentTime = int(xbmc.Player().getTime()) totalTime = int(xbmc.Player().getTotalTime()) try: progress = int(( float(currentTime) / float(totalTime) ) * 100) except: progress = 0 #If we are less than 95% complete, store resume time if progress > 0 and progress < 95: progress=currentTime*1000 if offset == 0: #Clear it, likely start from beginning clicked offset = 1 self.setMediaWatched(key) self.setMediaPlayedPosition(key, progress) #Otherwise, mark as watched elif progress >= 95: self.setMediaWatched(key) break xbmc.sleep(5000) #If we get this far, playback has stopped util.logDebug("Playback Stopped (or at 95%)")
def speak(self, text, angle): """text must be a sound filename without extension""" fileName = self.localTextName(text, angle) if not os.path.exists(fileName): if Debug.sound: logDebug('Voice.speak: fileName %s not found' % fileName) Sound.speak(fileName)
def start(self, dummyResults='DIREKT'): """start the animation, returning its deferred""" assert self.state() != QAbstractAnimation.Running tiles = set() for animation in self.animations: tile = animation.targetObject() self.debug |= tile.element in Debug.animation tiles.add(tile) tile.setActiveAnimation(animation) self.addAnimation(animation) propName = animation.pName() animation.setStartValue(tile.getValue(propName)) if propName == 'rotation': # change direction if that makes the difference smaller endValue = animation.unpackEndValue() currValue = tile.rotation if endValue - currValue > 180: animation.setStartValue(currValue + 360) if currValue - endValue > 180: animation.setStartValue(currValue - 360) for tile in tiles: tile.graphics.setDrawingOrder() self.finished.connect(self.allFinished) scene = Internal.field.centralScene scene.disableFocusRect = True QParallelAnimationGroup.start(self, QAbstractAnimation.DeleteWhenStopped) if self.debug: logDebug('Animation group %d started (%s)' % ( id(self), ','.join('A%d' % (id(x) % 10000) for x in self.animations))) return succeed(None)
def start(self, dummyResults='DIREKT'): """start the animation, returning its deferred""" assert self.state() != QAbstractAnimation.Running tiles = set() for animation in self.animations: tile = animation.targetObject() self.debug |= tile.element in Debug.animation tiles.add(tile) tile.setActiveAnimation(animation) self.addAnimation(animation) propName = animation.pName() animation.setStartValue(tile.getValue(propName)) if propName == 'rotation': # change direction if that makes the difference smaller endValue = animation.unpackEndValue() currValue = tile.rotation if endValue - currValue > 180: animation.setStartValue(currValue + 360) if currValue - endValue > 180: animation.setStartValue(currValue - 360) for tile in tiles: tile.graphics.setDrawingOrder() self.finished.connect(self.allFinished) scene = Internal.field.centralScene scene.disableFocusRect = True QParallelAnimationGroup.start(self, QAbstractAnimation.DeleteWhenStopped) if self.debug: logDebug('Animation group %d started (%s)' % (id(self), ','.join('A%d' % (id(x) % 10000) for x in self.animations))) return succeed(None)
def rollback(self, silent=None): """rollback and log it""" if QSqlDatabase.rollback(self): if not silent and Debug.sql: logDebug('%x rollbacked transaction' % id(self)) else: logWarning('%s cannot rollback: %s' % (self.name, self.lastError()))
def getVideoDirectStreamUrl(self, manager, mediaKey, mediaIndex, partIndex, offset = 0): args = dict() args['path']="http://127.0.0.1:"+str(self.port)+"/library/metadata/" + str(mediaKey) args['mediaIndex']=str(mediaIndex) args['partIndex']=str(partIndex) #args['protocol']="http" args['protocol']="hls" #args['protocol']="dash" args['offset']=str(offset) args['fastSeek']="1" args['directPlay']="0" args['directStream']="1" args['waitForSegments']="1" args['videoQuality']="100" args['subtitleSize']="100" args['audioBoost']="100" args['X-Plex-Product']=manager.xPlexProduct args['X-Plex-Version']=manager.xPlexVersion args['X-Plex-Client-Identifier']=manager.xPlexClientIdentifier args['X-Plex-Platform']=manager.xPlexPlatform args['X-Plex-Platform-Version']=manager.xPlexPlatformVersion args['X-Plex-Device']=manager.xPlexDevice args['Accept-Language']="en" url = self.getUrl(PlexServer.TRANSCODE_URL, args) util.logDebug("-->Setting direct stream: "+url) return url
def transaction(self, silent=None): """commit and log it""" if QSqlDatabase.transaction(self): if not silent and Debug.sql: logDebug('%x started transaction' % id(self)) else: logWarning('%s cannot start transaction: %s' % (self.name, self.lastError()))
def buildSubvoice(self, oggName, side): """side is 'left' or 'right'.""" angleDirectory = os.path.join(cacheDir(), 'angleVoices', self.md5sum, side) stdName = os.path.join(self.directory, oggName) angleName = os.path.join(angleDirectory, oggName) if os.path.exists(stdName) and not os.path.exists(angleName): sox = which('sox') if not sox: return stdName if not os.path.exists(angleDirectory): os.makedirs(angleDirectory) args = [sox, stdName, angleName, 'remix'] if side == 'left': args.extend(['1,2', '0']) elif side == 'right': args.extend(['0', '1,2']) callResult = subprocess.call(args) if callResult: if Debug.sound: logDebug('failed to build subvoice %s: return code=%s' % (angleName, callResult)) return stdName if Debug.sound: logDebug('built subvoice %s' % angleName) return angleName
def hideTableList(result): """hide it only after player says I am ready""" if result == Message.OK and client.tableList: if Debug.table: logDebug('%s hiding table list because game started' % client.name) client.tableList.hide() return result
def deleteFromPlaylist(self, server, playlistId, itemId): #Delete - DELETE http://10.1.3.200:32400/playlists/35339/items/72 url = server.getUrl("/playlists/%s/items/%s" % (playlistId, itemId)) util.logDebug("Deleting playlist item: "+url) http = self.buildPlexHttpRequest() http.Delete(url) PlexManager.handleRequestError(http)
def switchUser(self, userId, pin): if not self.authenticationToken: return False url = MyPlexService.SWITCHUSER_URL % (userId, pin) http = self.plexManager.buildPlexHttpRequest() http.SetHttpHeader('X-Plex-Token',self.authenticationToken) data = http.Post(url) if not data: if http.ResultUnauthorised() and pin != '': util.logDebug("User switch failed PIN invalid"); return PlexManager.ERR_USER_PIN_FAILED util.logDebug("Error failed to access users %s HttpCode: %d" % (url, http.code)); return PlexManager.ERR_USER_OTHER tree = ElementTree.fromstring(data) token = None for child in tree: if child.tag == 'authentication-token': token = child.text break if token is None: return PlexManager.ERR_USER_OTHER #Set usertoken self.userToken = token #reload myplex servers self.loadServers() return PlexManager.SUCCESS
def initDb(): """open the db, create or update it if needed. Returns a dbHandle.""" dbhandle = QSqlDatabase("QSQLITE") if InternalParameters.isServer: name = 'kajonggserver.db' else: name = 'kajongg.db' dbpath = InternalParameters.dbPath or appdataDir() + name dbhandle.setDatabaseName(dbpath) dbExisted = os.path.exists(dbpath) if Debug.sql: logDebug('%s database %s' % \ ('using' if dbExisted else 'creating', dbpath)) # timeout in msec: dbhandle.setConnectOptions("QSQLITE_BUSY_TIMEOUT=2000") if not dbhandle.open(): logError('%s %s' % (str(dbhandle.lastError().text()), dbpath)) sys.exit(1) with Transaction(dbhandle=dbhandle): if not dbExisted: Query.createTables(dbhandle) else: Query.upgradeDb(dbhandle) generateDbIdent(dbhandle) return dbhandle
def __init__(self, hand, meld=None, idx=None, xoffset=None, yoffset=None): if isinstance(hand, Tile): self.element = hand.element self.xoffset = hand.xoffset self.yoffset = hand.yoffset self.dark = hand.dark self.focusable = hand.focusable else: self.element = meld.pairs[idx] if idx is not None else meld self.xoffset = xoffset self.yoffset = yoffset player = hand.player isScoringGame = player.game.isScoringGame() if yoffset == 0: self.dark = self.element.istitle() else: self.dark = self.element == 'Xy' or isScoringGame self.focusable = True if isScoringGame: self.focusable = idx == 0 else: self.focusable = (self.element[0] not in 'fy' and self.element != 'Xy' and player == player.game.activePlayer and player == player.game.myself and (meld.state == CONCEALED and (len(meld) < 4 or meld.meldType == REST))) if self.element in Debug.focusable: logDebug('TileAttr %s:%s' % (self.element, self.focusable))
def commit(self, silent=None): """commit and log it""" result = QSqlDatabase.commit(self) if result: if not silent and Debug.sql: logDebug('%x committed transaction' % id(self)) else: logWarning('%s cannot commit: %s :' % (self.name, self.lastError()))
def setEndValue(self, endValue): """wrapper with debugging code""" tile = self.targetObject() if tile.element in Debug.animation: pName = self.pName() logDebug('%s: change endValue for %s: %s->%s %s' % (self.ident(), pName, self.formatValue(self.endValue()), self.formatValue(endValue), str(tile))) QPropertyAnimation.setEndValue(self, endValue)
def addToPlaylist(self, server, id, key): #PUT http://10.1.3.200:32400/playlists/35339/items?uri=library%3A%2F%2F9dbbfd79-c597-4294-a32d-edf7c2975a41%2Fitem%2F%252Flibrary%252Fmetadata%252F34980 key = urllib.quote(key, '') args = dict() args['uri']="library:///item/%s" % key url = server._getUrl(server._getRootUrl(), "/playlists/%s/items" % id, args) util.logDebug("Adding playlist item: "+url) self.putPlexCommand(url)
def getData(self, url, args = None): if not args is None: url = util.buildUrl(url, args) util.logDebug("Retrieving data from: %s" % url) http = util.Http() data = http.Get(url) PlexManager.handleRequestError(http) return data
def getServers(self): localServers = dict() remoteServers = dict() foundServer = False if self.isAuthenticated(): url = MyPlexService.SERVERS_URL % self.authenticationToken util.logDebug("Finding servers via: "+url) data = util.Http().Get(url) if data: tree = ElementTree.fromstring(data) for child in tree: host = child.attrib.get("address", "") port = child.attrib.get("port", "") localAddresses = child.attrib.get("localAddresses", "") accessToken = child.attrib.get("accessToken", "") machineIdentifier = child.attrib.get("machineIdentifier", "") local = child.attrib.get("owned", "0") sourceTitle = child.attrib.get("sourceTitle", "") util.logInfo("MyPlex found server %s:%s" % (host,port)) foundServer = True server = None if local == "1": #Try the local addresses #TODO: Similiar code exists in the server and this is a bit convoluted.... if localAddresses: localAddresses = localAddresses.split(',') util.logInfo("--> Resolving local addresses") resolved = False for addr in localAddresses: http = util.Http() util.logDebug("--> Trying local address %s:32400" % addr) data = http.Get("http://"+addr+":32400/?X-Plex-Token="+accessToken) if http.GetHttpResponseCode() == -1: data = http.Get("https://"+addr+":32400/?X-Plex-Token="+accessToken) if data: tree = ElementTree.fromstring(data) localMachineIdentifier = tree.attrib.get("machineIdentifier", "") if localMachineIdentifier == machineIdentifier: util.logInfo("--> Using local address %s:32400 instead of remote address" % addr) server = PlexServer(addr, "32400", accessToken) resolved = True break if not resolved: util.logInfo("--> Using remote address %s unable to resolve local address" % host) server = PlexServer(host, port, accessToken) if server is None or not server.isValid(): continue localServers[machineIdentifier] = server else: #Remote server found server = PlexServer(host, port, accessToken, sourceTitle) remoteServers[machineIdentifier] = server return localServers, remoteServers, foundServer
def __init__(self, directory, content=None): """give this name a voice""" self.__md5sum = None if not os.path.split(directory)[0]: if Debug.sound: logDebug('place voice %s in %s' % (directory, cacheDir())) directory = os.path.join(cacheDir(), directory) self.directory = directory self.__setArchiveContent(content)
def getData(self, url, args = None): url = self.getUrl(url, args) util.logDebug("Retrieving data from: " + url) http = util.Http() #TODO: Handle errors data = http.Get(url) if util.Http().GetHttpResponseCode() == 400: pass return data, url
def clientMadeOriginalCall(self, dummyResults, msg): """first tell everybody about original call and then treat the implicit discard""" msg.player.originalCall = True if Debug.originalCall: logDebug('server.clientMadeOriginalCall: %s' % msg.player) block = DeferredBlock(self) block.tellAll(msg.player, Message.OriginalCall) block.callback(self.askForClaims)
def sendLine(self, line=None, isStatusMessage=False): """send line to others. Either the edited line or parameter line.""" if line is None: line = unicode(self.edit.text()) self.edit.clear() if line: if Debug.chat: logDebug('sending line %s to others' % line) msg = ChatMessage(self.table.tableid, self.table.client.name, line, isStatusMessage) self.table.client.sendChat(msg).addErrback(self.chatError)
def addToPlaylist(self, server, id, key): #PUT http://10.1.3.200:32400/playlists/35339/items?uri=library%3A%2F%2F9dbbfd79-c597-4294-a32d-edf7c2975a41%2Fitem%2F%252Flibrary%252Fmetadata%252F34980 key = urllib.quote(key, '') args = dict() args['uri']="library:///item/%s" % key url = server.getUrl("/playlists/%s/items" % id, args) util.logDebug("Adding playlist item: "+url) http = self.buildPlexHttpRequest() http.Put(url) PlexManager.handleRequestError(http)
def remote_chat(self, data): """others chat to me""" chatLine = ChatMessage(data) if Debug.chat: logDebug('got chatLine: %s' % chatLine) table = self._tableById(chatLine.tableid) if not chatLine.isStatusMessage and not table.chatWindow: ChatWindow(table) if table.chatWindow: table.chatWindow.receiveLine(chatLine)
def setMediaUnwatched(self, mediaKey): """ Set media as unwatched """ args = dict() args['key']=mediaKey args['identifier']="com.plexapp.plugins.library" url = self.getUrl(PlexServer.UNWATCHED_URL,args) util.logDebug("Setting media key=[%s] as unwatched" % mediaKey) util.Http().Get(url)
def clientAction(self, client, move): """mirror the original call""" player = move.player if client.thatWasMe(player): player.originalCallingHand = player.hand if Debug.originalCall: logDebug('%s gets originalCallingHand:%s' % (player, player.originalCallingHand)) player.originalCall = True client.game.addCsvTag('originalCall') return client.ask(move, [Message.OK])
def setMediaWatched(self, ratingKey): """ Set media as watched Removes from deck """ args = dict() args['key']=ratingKey args['identifier']="com.plexapp.plugins.library" url = self.getUrl(PlexServer.WATCHED_URL,args) util.logDebug("Setting media key=[%s] as watched" % ratingKey) util.Http().Get(url)
def cancelled(dummy): """the user does not want to start now. Back to table list""" if Debug.table: logDebug('%s: Readyforgamestart returns Message.NoGameStart for table %s' % ( self.name, self._tableById(tableid))) self.table = None self.beginQuestion = None if self.tableList: self.__updateTableList() self.tableList.show() return Message.NoGameStart
def afterCurrentAnimationDo(callback, *args, **kwargs): """a helper, delaying some action until all active animations have finished""" current = ParallelAnimationGroup.current if current: current.deferred.addCallback(callback, *args, **kwargs) if current.debug: logDebug('after current animation %d do %s %s' % \ (id(current), callback, ','.join(args) if args else '')) else: callback(None, *args, **kwargs)
def serverAction(self, dummyTable, msg): """save voice sounds on the server""" voice = msg.player.voice voice.archiveContent = msg.args[0] if Debug.sound: if voice.oggFiles(): logDebug('%s: server got wanted voice data %s' % ( msg.player, voice)) else: logDebug('%s: server got empty voice data %s (arg0=%s)' % ( msg.player, voice, repr(msg.args[0][:100])))
def garbageCollection(): """delete completed blocks. Only to be called before inserting a new block. Assuming that block creation never overlaps.""" for block in DeferredBlock.blocks[:]: if block.callbackMethod is None: block.logBug('DBlock %s has no callback' % str(block)) if block.completed: DeferredBlock.blocks.remove(block) if len(DeferredBlock.blocks) > 100: logDebug('We have %d DeferredBlocks, they must be leaking' % len(DeferredBlock.blocks))
def setMediaPlayedPosition(self, mediaKey, positionMsec): """ Update media played position for onDeck and resuming behaviour An item will be added to the deck by plex based on this call """ args = dict() args['key']=mediaKey args['identifier']="com.plexapp.plugins.library" args['time']=str(positionMsec) url = self.getUrl("/:/progress",args) util.logDebug("Setting media key=[%s] to position=[%s]" % (mediaKey,str(positionMsec))) util.Http().Get(url)
def __setArchiveContent(self, content): """fill the Voice with ogg files""" if not content: return if not os.path.exists(self.directory): os.makedirs(self.directory) filelike = cStringIO.StringIO(content) tarFile = tarfile.open(mode='r|bz2', fileobj=filelike) tarFile.extractall(path=self.directory) if Debug.sound: logDebug('extracted archive into %s' % self.directory) tarFile.close() filelike.close()
def colorizeName(self): """set the color to be used for showing the player name on the wall""" if not isAlive(self.front.nameLabel): # TODO: should never happen logDebug('colirizeName: nameLabel is not alive') return if self == self.game.activePlayer and self.game.client: color = Qt.blue elif Internal.field.tilesetName == 'jade': color = Qt.white else: color = Qt.black self.front.nameLabel.setBrush(QBrush(QColor(color)))
def __generateDbIdent(self): """make sure the database has a unique ident and get it""" self.createTable('general') records = Query('select ident from general').records assert len(records) < 2 if records: Internal.dbIdent = records[0][0] if Debug.sql: logDebug('found dbIdent for %s: %s' % (self.name, Internal.dbIdent)) else: Internal.dbIdent = str(random.randrange(100000000000)) Query("INSERT INTO general(ident) values('%s')" % Internal.dbIdent)
def appquit(): """retry until the reactor really stopped""" if Internal.reactor.running: Internal.quitWaitTime += 10 if Internal.quitWaitTime % 1000 == 0: logDebug('waiting since %d seconds for reactor to stop' % (Internal.quitWaitTime // 1000)) QTimer.singleShot(10, Client.appquit) else: if Internal.quitWaitTime > 1000: logDebug('reactor stopped after %d seconds' % (Internal.quitWaitTime // 1000)) Internal.app.quit() checkMemory()
def __init__(self, target, propName, endValue, parent=None): QPropertyAnimation.__init__(self, target, propName, parent) QPropertyAnimation.setEndValue(self, endValue) duration = Preferences.animationDuration() self.setDuration(duration) self.setEasingCurve(QEasingCurve.InOutQuad) target.queuedAnimations.append(self) Animation.nextAnimations.append(self) if target.element in Debug.animation: oldAnimation = target.activeAnimation.get(propName, None) if isAlive(oldAnimation): logDebug('new animation %s (after %s is done)' % (self, oldAnimation.ident())) else: logDebug('new animation %s' % self)
def gotAnswer(self, rawAnswer): """convert the wired answer into something more useful""" if isinstance(rawAnswer, tuple): answer = rawAnswer[0] if isinstance(rawAnswer[1], tuple): self.args = list(rawAnswer[1]) else: self.args = list([rawAnswer[1]]) else: answer = rawAnswer self.args = None if answer in Message.defined: self.answer = Message.defined[answer] else: if Debug.deferredBlock: logDebug('Request %s ignores %s' % (self, rawAnswer))
def __init__(self, parent=None): QParallelAnimationGroup.__init__(self, parent) assert Animation.nextAnimations self.animations = Animation.nextAnimations Animation.nextAnimations = [] self.deferred = Deferred() self.steps = 0 self.debug = False if ParallelAnimationGroup.current: if self.debug or ParallelAnimationGroup.current.debug: logDebug('Chaining Animation group %d to %d' % \ (id(self), id(ParallelAnimationGroup.current))) ParallelAnimationGroup.current.deferred.addCallback(self.start) else: self.start() ParallelAnimationGroup.running.append(self) ParallelAnimationGroup.current = self
def allFinished(self): """all animations have finished. Cleanup and callback""" self.fixAllBoards() if self == ParallelAnimationGroup.current: ParallelAnimationGroup.current = None ParallelAnimationGroup.running = [] if Debug.animationSpeed and self.duration(): perSecond = self.steps * 1000.0 / self.duration() if perSecond < 50: logDebug('%d steps for %d animations, %.1f/sec' % \ (self.steps, len(self.children()), perSecond)) # if we have a deferred, callback now assert self.deferred if self.debug: logDebug('Animation group %d done' % id(self)) if self.deferred: self.deferred.callback(None)
def remote_serverDisconnects(self, result=None): """we logged out or or lost connection to the server. Remove visual traces depending on that connection.""" if Debug.connections and result: logDebug('server %s disconnects: %s' % (self.connection.url, result)) self.connection = None game = self.game self.game = None # avoid races: messages might still arrive if self.tableList: self.tableList.hide() self.tableList = None if self in HumanClient.humanClients: HumanClient.humanClients.remove(self) if self.beginQuestion: self.beginQuestion.cancel() field = Internal.field if field and game and field.game == game: game.close() # TODO: maybe issue a Sorry first?