예제 #1
0
    def run(self):
        #while xbmc is running
        self._scrobbler = Scrobbler()
        self._scrobbler.start()
        while not (self._abortRequested or xbmc.abortRequested):
            try:
                #try to connect, catch errors and retry every 5 seconds
                telnet = telnetlib.Telnet(self.TELNET_ADDRESS,
                                          self.TELNET_PORT)

                #if connection succeeds
                while not (self._abortRequested or xbmc.abortRequested):
                    try:
                        #read notification data
                        data = self._readNotification(telnet)
                        Debug("[Notification Service] message: " + str(data))
                        self._forward(data)
                    except EOFError:
                        #if we end up here, it means the connection was lost or reset,
                        # so we empty out the buffer, and exit this loop, which retries
                        # the connection in the outer loop
                        self._notificationBuffer = ""
                        break
            except:
                time.sleep(5)
                continue

        telnet.close()
        self._scrobbler.abortRequested = True
        Debug("Notification service stopping")
예제 #2
0
    def run(self):
        startup_delay = utilities.getSettingAsInt('startup_delay')
        if startup_delay:
            utilities.Debug("Delaying startup by %d seconds." % startup_delay)
            xbmc.sleep(startup_delay * 1000)

        utilities.Debug("Service thread starting.")

        # setup event driven classes
        self.Player = traktPlayer(action=self._dispatchQueue)
        self.Monitor = traktMonitor(action=self._dispatchQueue)

        # init traktapi class
        globals.traktapi = traktAPI()

        # init sync thread
        self.syncThread = syncThread()

        # init scrobbler class
        self.scrobbler = Scrobbler(globals.traktapi)

        # init tagging class
        self.tagger = Tagger(globals.traktapi)

        # purge queue
        self.dispatchQueue.purge()

        # start loop for events
        while (not xbmc.abortRequested):
            while len(self.dispatchQueue) and (not xbmc.abortRequested):
                data = self.dispatchQueue.get()
                utilities.Debug("Queued dispatch: %s" % data)
                self._dispatch(data)

            if xbmc.Player().isPlayingVideo():
                self.scrobbler.update()

            xbmc.sleep(500)

        # we are shutting down
        utilities.Debug("Beginning shut down.")

        # check if watcher is set and active, if so, cancel it.
        if self.watcher:
            if self.watcher.isAlive():
                self.watcher.cancel()

        # delete player/monitor
        del self.Player
        del self.Monitor

        # check update tags thread.
        if self.updateTagsThread and self.updateTagsThread.isAlive():
            self.updateTagsThread.join()

        # check if sync thread is running, if so, join it.
        if self.syncThread.isAlive():
            self.syncThread.join()
예제 #3
0
def main():
    register_exception_handler()
    assert get_access_token()
    scrobble_queue = Queue()
    scrobbler = Scrobbler(scrobble_queue)
    scrobbler.start()
    for Mon in get_monitors():
        mon = Mon(scrobble_queue)
        mon.start()
예제 #4
0
    def run(self):
        startup_delay = utilities.getSettingAsInt('startup_delay')
        if startup_delay:
            logger.debug("Delaying startup by %d seconds." % startup_delay)
            xbmc.sleep(startup_delay * 1000)

        logger.debug("Service thread starting.")

        # purge queue before doing anything
        self.dispatchQueue.purge()

        # setup event driven classes
        self.Player = traktPlayer(action=self._dispatchQueue)
        self.Monitor = traktMonitor(action=self._dispatchQueue)

        # init traktapi class
        globals.traktapi = traktAPI()

        # init sync thread
        self.syncThread = syncThread()

        # init scrobbler class
        self.scrobbler = Scrobbler(globals.traktapi)

        # start loop for events
        while not self.Monitor.abortRequested():
            if not utilities.getSetting('authorization'):
                last_reminder = utilities.getSettingAsInt('last_reminder')
                now = int(time.time())
                if last_reminder >= 0 and last_reminder < now - (24 * 60 * 60):
                    gui_utils.get_pin()

            while len(self.dispatchQueue) and (
                    not self.Monitor.abortRequested()):
                data = self.dispatchQueue.get()
                logger.debug("Queued dispatch: %s" % data)
                self._dispatch(data)

            if xbmc.Player().isPlayingVideo():
                self.scrobbler.transitionCheck()

            if self.Monitor.waitForAbort(1):
                # Abort was requested while waiting. We should exit
                break

        # we are shutting down
        logger.debug("Beginning shut down.")

        # delete player/monitor
        del self.Player
        del self.Monitor

        # check if sync thread is running, if so, join it.
        if self.syncThread.isAlive():
            self.syncThread.join()
예제 #5
0
	def run(self):		  
		#while xbmc is running
		scrobbler = Scrobbler()
		scrobbler.start()
		
		while (not (self.abortRequested or xbmc.abortRequested)):
			time.sleep(1)
			try:
				tn = telnetlib.Telnet('localhost', 9090, 10)
			except IOError as (errno, strerror):
				#connection failed, try again soon
				Debug("[Notification Service] Telnet too soon? ("+str(errno)+") "+strerror)
				time.sleep(1)
				continue
			
			Debug("[Notification Service] Waiting~");
			bCount = 0
			
			while (not (self.abortRequested or xbmc.abortRequested)):
				try:
					if bCount == 0:
						notification = ""
						inString = False
					[index, match, raw] = tn.expect(["(\\\\)|(\\\")|[{\"}]"], 0.2) #note, pre-compiled regex might be faster here
					notification += raw
					if index == -1: # Timeout
						continue
					if index == 0: # Found escaped quote
						match = match.group(0)
						if match == "\"":
							inString = not inString
							continue
						if match == "{":
							bCount += 1
						if match == "}":
							bCount -= 1
					if bCount > 0:
						continue
					if bCount < 0:
						bCount = 0
				except EOFError:
					break #go out to the other loop to restart the connection
				
				Debug("[Notification Service] message: " + str(notification))
				
				# Parse recieved notification
				data = json.loads(notification)
				
				# Forward notification to functions
				if 'method' in data and 'params' in data and 'sender' in data['params'] and data['params']['sender'] == 'xbmc':
					if data['method'] == 'Player.OnStop':
						scrobbler.playbackEnded()
					elif data['method'] == 'Player.OnPlay':
						if 'data' in data['params'] and 'item' in data['params']['data'] and 'type' in data['params']['data']['item']:
							scrobbler.playbackStarted(data['params']['data'])
					elif data['method'] == 'Player.OnPause':
						scrobbler.playbackPaused()
					elif data['method'] == 'System.OnQuit':
						self.abortRequested = True
예제 #6
0
class NotificationService:

	_scrobbler = None
	
	def __init__(self):
		self.run()

	def _dispatch(self, data):
		Debug("[Notification] Dispatch: %s" % data)
		xbmc.sleep(500)
		action = data["action"]
		if action == "started":
			p = {"item": {"type": data["type"], "id": data["id"]}}
			self._scrobbler.playbackStarted(p)
		elif action == "ended" or action == "stopped":
			self._scrobbler.playbackEnded()
		elif action == "paused":
			self._scrobbler.playbackPaused()
		elif action == "resumed":
			self._scrobbler.playbackResumed()
		elif action == "databaseUpdated":
			if do_sync('movies'):
				movies = SyncMovies(show_progress=False)
				movies.Run()
			if do_sync('episodes'):
				episodes = SyncEpisodes(show_progress=False)
				episodes.Run()
		elif action == "scanStarted":
			Debug("[Notification] Dispatch: scanStarted")
		else:
			Debug("[Notification] '%s' unknown dispatch action!" % action)

	def run(self):
		Debug("[Notification] Starting")
		
		# setup event driven classes
		self.Player = traktPlayer(action = self._dispatch)
		self.Monitor = traktMonitor(action = self._dispatch)
		
		# initalize scrobbler class
		self._scrobbler = Scrobbler()
		self._scrobbler.start()
		
		# start loop for events
		while (not xbmc.abortRequested):
			xbmc.sleep(500)
			
		# we aborted
		if xbmc.abortRequested:
			Debug("[Notification] abortRequested received, shutting down.")
			# join scrobbler, to wait for termination
			Debug("[Notification] Joining scrobbler thread to wait for exit.")
			self._scrobbler.join()
예제 #7
0
    def run(self):
        startup_delay = kodiUtilities.getSettingAsInt('startup_delay')
        if startup_delay:
            logger.debug("Delaying startup by %d seconds." % startup_delay)
            xbmc.sleep(startup_delay * 1000)

        logger.debug("Service thread starting.")

        # purge queue before doing anything
        self.dispatchQueue.purge()

        # setup event driven classes
        self.Player = traktPlayer(action=self._dispatchQueue)
        self.Monitor = traktMonitor(action=self._dispatchQueue)

        # init traktapi class
        globals.traktapi = traktAPI()

        # init sync thread
        self.syncThread = syncThread()

        # init scrobbler class
        self.scrobbler = Scrobbler(globals.traktapi)

        AddonSignals.registerSlot('service.nextup.notification',
                                  'NEXTUPWATCHEDSIGNAL', self.callback)

        # start loop for events
        while not self.Monitor.abortRequested():
            while len(self.dispatchQueue) and (
                    not self.Monitor.abortRequested()):
                data = self.dispatchQueue.get()
                logger.debug("Queued dispatch: %s" % data)
                self._dispatch(data)

            if xbmc.Player().isPlayingVideo():
                self.scrobbler.transitionCheck()

            if self.Monitor.waitForAbort(1):
                # Abort was requested while waiting. We should exit
                break

        # we are shutting down
        logger.debug("Beginning shut down.")

        # delete player/monitor
        del self.Player
        del self.Monitor

        # check if sync thread is running, if so, join it.
        if self.syncThread.isAlive():
            self.syncThread.join()
예제 #8
0
 def login_lastfm(self):
     '''Last.fm登陆'''
     if self.lastfm and self.last_fm_username and self.last_fm_password:
         self.scrobbler = Scrobbler(self.last_fm_username,
                                    self.last_fm_password)
         r, err = self.scrobbler.handshake()
         if r:
             logger.info("Last.fm login succeeds!")
             print '\033[31m♥\033[0m Last.fm logged in: %s' % self.last_fm_username
         else:
             logger.error("Last.fm login fails: " + err)
             self.lastfm = False
     else:
         self.lastfm = False
예제 #9
0
	def run(self):
		Debug("[Notification] Starting")
		
		# setup event driven classes
		self.Player = traktPlayer(action = self._dispatch)
		self.Monitor = traktMonitor(action = self._dispatch)
		
		# init traktapi class
		globals.traktapi = traktAPI()

		# initalize scrobbler class
		self._scrobbler = Scrobbler(globals.traktapi)

		# start loop for events
		while (not xbmc.abortRequested):
			xbmc.sleep(500)
			
		# we aborted
		if xbmc.abortRequested:
			Debug("[Notification] abortRequested received, shutting down.")
			
			# delete player/monitor
			del self.Player
			del self.Monitor
			
			# join scrobbler, to wait for termination
			Debug("[Notification] Joining scrobbler thread to wait for exit.")
			self._scrobbler.join()
예제 #10
0
	def run(self):
		#while xbmc is running
		self._scrobbler = Scrobbler()
		self._scrobbler.start()
		while not (self._abortRequested or xbmc.abortRequested):
			try:
				#try to connect, catch errors and retry every 5 seconds
				telnet = telnetlib.Telnet(self.TELNET_ADDRESS, self.TELNET_PORT)
				
				#if connection succeeds
				while not (self._abortRequested or xbmc.abortRequested):
					try:
						#read notification data
						data = self._readNotification(telnet)
						Debug("[Notification Service] message: " + str(data))
						self._forward(data)
					except EOFError:
						#if we end up here, it means the connection was lost or reset,
						# so we empty out the buffer, and exit this loop, which retries
						# the connection in the outer loop
						self._notificationBuffer = ""
						break
			except:
				time.sleep(5)
				continue


		telnet.close()
		self._scrobbler.abortRequested = True
		Debug("Notification service stopping")
예제 #11
0
파일: pyfm.py 프로젝트: beanmoon/pyfm
 def __init__(self):
     self._load_config()
     self.douban = Douban(self.email, self.password, self.user_id, self.expire, self.token, self.user_name)
     self.player = Player()
     self.current_channel = 0
     self.current_song = None
     self.current_play_list = None
     self.get_channels()
     
     self.palette = [('selected', 'bold', 'default'),
                     ('title', 'yellow', 'default')]
     self.selected_button = None
     self.main_loop = None
     self.song_change_alarm = None
     
     if self.scrobbling:
         self.scrobbler = Scrobbler(self.last_fm_username, self.last_fm_password)
         r =  self.scrobbler.handshake()
         if r:
             print("Last.FM logged in.")
         else:
             print("Last.FM login failed")
     if self.douban_account:
         r, err = self.douban.do_login()
         if r:
             print("Douban logged in.")
             self._save_cache()
         else:
             print("Douban login failed: " + err)
예제 #12
0
class main():
    ## The Constructor
    # @param self Object pointer
    # @param pyjama Reference to the pyjama object
    def __init__(self, pyjama):
        self.pyjama = pyjama
        self.Events = self.pyjama.Events

        self.Events.connect_event("nowplaying", self.ev_nowplaying)
        self.Events.connect_event('player-status', self.ev_player_status)

        self.pyjama.preferences.register_plugin("LastFM", self.create_preferences, self.save_preferences)

        # login to last.fm
        self.scrobbler = None

        if self.get_session():
            logging.debug('last.fm plugin loaded')
        else:
            logging.debug('last.fm plugin loaded but scrobbling isn\'t available')
        
            #raise

        self.last_scrobbled = None

#    def get_session(self):
#        thr = Thread(target = self.get_session_do, args = ())
#        thr.start()
    @threaded
    def get_session(self):
        if self.pyjama.settings.get_value('LASTFM','SCROBBLING'):

            login=str(self.pyjama.settings.get_value('LASTFM','LOGIN'))
            password=str(self.pyjama.settings.get_value('LASTFM','PASS'))

            try:
                # pyjama has own last.fm clien id 'pyj'
                self.scrobbler=Scrobbler(client=('pyj',VERSION))
                self.scrobbler.login(login, password)
            except Exception, e:
                logging.error(e)
                self.scrobbler=None
                return False
            else:
                #self.logged=True
                return True
        else:
예제 #13
0
파일: pyfm.py 프로젝트: JamesTing/pyfm
    def __init__(self):
        self.email = None
        self.password = None
        self.user_name = None
        self.user_id = None
        self.expire = None
        self.token = None
        self.cookies = None
        
        self.last_fm_username = None
        self.last_fm_password = None
        self.scrobbling = True
        self.douban_account = True
        self.channels = None
        
        # Set up config
        try:
            arg = sys.argv[1]
            self._do_config()
        except IndexError:
            self._load_config()
        
        # Init API tools
        self.douban = Douban(
            self.email, self.password, self.user_id, self.expire, self.token, self.user_name, self.cookies)
        self.player = Player()
        self.current_channel = 0
        self.current_song = None
        self.current_play_list = None

        # Init terminal ui
        self.palette = [('selected', 'bold', 'default'),
                        ('title', 'yellow', 'default')]
        self.selected_button = None
        self.main_loop = None
        self.song_change_alarm = None
        
        # Try to login
        if self.last_fm_username is None or self.last_fm_username == "":
            self.scrobbling = False
        if (self.email is None or self.email == "") and self.cookies == None:
            self.douban_account = False
            
        if self.scrobbling:
            self.scrobbler = Scrobbler(
                self.last_fm_username, self.last_fm_password)
            r, err = self.scrobbler.handshake()
            if r:
                print("Last.FM 已登陆")
            else:
                print("Last.FM 登录失败: " + err)
        if self.douban_account:
            r, err = self.douban.do_login()
            if r:
                print("Douban 已登陆")
            else:
                print("Douban 登录失败: " + err)
        self.get_channels()
        self._save_cache()
예제 #14
0
    def run(self):
        startup_delay = utilities.getSettingAsInt('startup_delay')
        if startup_delay:
            logger.debug("Delaying startup by %d seconds." % startup_delay)
            xbmc.sleep(startup_delay * 1000)

        logger.debug("Service thread starting.")

        # purge queue before doing anything
        self.dispatchQueue.purge()

        # setup event driven classes
        self.Player = traktPlayer(action=self._dispatchQueue)
        self.Monitor = traktMonitor(action=self._dispatchQueue)

        # init traktapi class
        globals.traktapi = traktAPI()

        # init sync thread
        self.syncThread = syncThread()

        # init scrobbler class
        self.scrobbler = Scrobbler(globals.traktapi)

        # start loop for events
        while not xbmc.abortRequested:
            while len(self.dispatchQueue) and (not xbmc.abortRequested):
                data = self.dispatchQueue.get()
                logger.debug("Queued dispatch: %s" % data)
                self._dispatch(data)

            if xbmc.Player().isPlayingVideo():
                self.scrobbler.transitionCheck()

            xbmc.sleep(500)

        # we are shutting down
        logger.debug("Beginning shut down.")

        # delete player/monitor
        del self.Player
        del self.Monitor

        # check if sync thread is running, if so, join it.
        if self.syncThread.isAlive():
            self.syncThread.join()
예제 #15
0
	def run(self):
		startup_delay = utilities.getSettingAsInt('startup_delay')
		if startup_delay:
			utilities.Debug("Delaying startup by %d seconds." % startup_delay)
			xbmc.sleep(startup_delay * 1000)

		utilities.Debug("Service thread starting.")

		# setup event driven classes
		self.Player = traktPlayer(action = self._dispatchQueue)
		self.Monitor = traktMonitor(action = self._dispatchQueue)

		# init traktapi class
		globals.traktapi = traktAPI()

		# init sync thread
		self.syncThread = syncThread()

		# init scrobbler class
		self.scrobbler = Scrobbler(globals.traktapi)

		# init tagging class
		self.tagger = Tagger(globals.traktapi)
		
		# purge queue
		self.dispatchQueue.purge()

		# start loop for events
		while (not xbmc.abortRequested):
			while len(self.dispatchQueue) and (not xbmc.abortRequested):
				data = self.dispatchQueue.get()
				utilities.Debug("Queued dispatch: %s" % data)
				self._dispatch(data)

			if xbmc.Player().isPlayingVideo():
				self.scrobbler.update()

			xbmc.sleep(500)

		# we are shutting down
		utilities.Debug("Beginning shut down.")

		# check if watcher is set and active, if so, cancel it.
		if self.watcher:
			if self.watcher.isAlive():
				self.watcher.cancel()

		# delete player/monitor
		del self.Player
		del self.Monitor

		# check update tags thread.
		if self.updateTagsThread and self.updateTagsThread.isAlive():
			self.updateTagsThread.join()

		# check if sync thread is running, if so, join it.
		if self.syncThread.isAlive():
			self.syncThread.join()
예제 #16
0
	def run(self):
		startup_delay = utilities.getSettingAsInt('startup_delay')
		if startup_delay:
			utilities.Debug("Delaying startup by %d seconds." % startup_delay)
			xbmc.sleep(startup_delay * 1000)

		utilities.Debug("Service thread starting.")
		
		# setup event driven classes
		self.Player = traktPlayer(action = self._dispatchQueue)
		self.Monitor = traktMonitor(action = self._dispatchQueue)

		# init traktapi class
		globals.traktapi = traktAPI()

		# init sync thread
		self.syncThread = syncThread()

		# init scrobbler class
		self.scrobbler = Scrobbler(globals.traktapi)

		# start loop for events
		while (not xbmc.abortRequested):
			while not self.dispatchQueue.empty() and (not xbmc.abortRequested):
				data = self.dispatchQueue.get()
				utilities.Debug("Queued dispatch: %s" % data)
				self._dispatch(data)

			# check if we were tasked to do a manual sync
			if utilities.getPropertyAsBool('traktManualSync'):
				if not self.syncThread.isAlive():
					utilities.Debug("Performing a manual sync.")
					self.doSync(manual=True)
				else:
					utilities.Debug("There already is a sync in progress.")

				utilities.clearProperty('traktManualSync')

			if xbmc.Player().isPlayingVideo():
				self.scrobbler.update()

			xbmc.sleep(500)

		# we are shutting down
		utilities.Debug("Beginning shut down.")

		# check if watcher is set and active, if so, cancel it.
		if self.watcher:
			if self.watcher.isAlive():
				self.watcher.cancel()

		# delete player/monitor
		del self.Player
		del self.Monitor

		# check if sync thread is running, if so, join it.
		if self.syncThread.isAlive():
			self.syncThread.join()
예제 #17
0
    def run(self):
        startup_delay = kodiUtilities.getSettingAsInt('startup_delay')
        if startup_delay:
            logger.debug("Delaying startup by %d seconds." % startup_delay)
            xbmc.sleep(startup_delay * 1000)

        logger.debug("Service thread starting.")

        # purge queue before doing anything
        self.dispatchQueue.purge()

        # setup event driven classes
        self.Player = traktPlayer(action=self._dispatchQueue)
        self.Monitor = traktMonitor(action=self._dispatchQueue)

        # init traktapi class
        globals.traktapi = traktAPI()

        # init sync thread
        self.syncThread = syncThread()

        # init scrobbler class
        self.scrobbler = Scrobbler(globals.traktapi)

        AddonSignals.registerSlot('service.nextup.notification', 'NEXTUPWATCHEDSIGNAL', self.callback)

        # start loop for events
        while not self.Monitor.abortRequested():
            if not kodiUtilities.getSetting('authorization'):
                last_reminder = kodiUtilities.getSettingAsInt('last_reminder')
                now = int(time.time())
                if last_reminder >= 0 and last_reminder < now - (24 * 60 * 60):
                    gui_utils.get_pin()
                
            while len(self.dispatchQueue) and (not self.Monitor.abortRequested()):
                data = self.dispatchQueue.get()
                logger.debug("Queued dispatch: %s" % data)
                self._dispatch(data)

            if xbmc.Player().isPlayingVideo():
                self.scrobbler.transitionCheck()

            if self.Monitor.waitForAbort(1):
                # Abort was requested while waiting. We should exit
                break

        # we are shutting down
        logger.debug("Beginning shut down.")

        # delete player/monitor
        del self.Player
        del self.Monitor

        # check if sync thread is running, if so, join it.
        if self.syncThread.isAlive():
            self.syncThread.join()
예제 #18
0
파일: patsy.py 프로젝트: sral/patsy
    def setup_scrobbler(api_key, shared_secret, username, password,
                        max_retries, max_retry_delay):
        """Returns Last.fm scrobbler.

        Keyword argument(s):
        api_key -- Last.fm API key
        shared_secret -- Last.fm API shared secret
        username -- Last.fm username
        password -- Last.fm password
        max_retries -- Maximum number of retries
        max_delay -- Maximum delay between retries
        """
        scrobbler = Scrobbler(api_key, shared_secret, max_retries,
                              max_retry_delay)
        result = scrobbler.authenticate(username, password)
        if not result:
            log.error("Last.fm authentication failed")
            sys.exit(errno.EACCES)
        return scrobbler
예제 #19
0
class App:
    def __init__(self):
        # Version
        version = "0.1.0"
        with open("version.txt") as f:
            version = f.read()
        os.environ["BUTLER_VERSION"] = version

        # Config
        config = {}
        with open("config.json") as f:
            raw_config = f.read()
            config = json.loads(raw_config)
        config_i = config["interface"]

        # Initialize
        self.sampler = Sampler(
            interface_name=config_i["name"],
            channels=config_i["channels"],
            sample_format=config_i["sample_format"],
            sample_rate=config_i["sample_rate"],
        )
        self.fp = Fingerprinter(FINGERPRINT_API_KEY)
        self.fm = Scrobbler(LASTFM_API_KEY, LASTFM_SECRET, LASTFM_SESSION_KEY)

    def run(self):
        while (True):
            logger.info(f'Recording and fingerprinting sample')
            self.sampler.record()
            self.sampler.save(SAMPLE_FILENAME)
            res = self.fp.run(SAMPLE_FILENAME)

            if (res["status"] != "success"):
                logger.error(f'Failed to fingerprint sample')

            elif (res["result"] == None):
                logger.info('No track detected by fingerprinter')

            else:
                self.fm.run(res["result"])

            sleep(SLEEP_SEC)
예제 #20
0
    def run(self):
        startup_delay = utilities.getSettingAsInt('startup_delay')
        if startup_delay:
            logger.debug("Delaying startup by %d seconds." % startup_delay)
            xbmc.sleep(startup_delay * 1000)

        logger.debug("Service thread starting.")

        # purge queue before doing anything
        self.dispatchQueue.purge()

        # setup event driven classes
        self.Player = traktPlayer(action=self._dispatchQueue)
        self.Monitor = traktMonitor(action=self._dispatchQueue)

        # init traktapi class
        globals.traktapi = traktAPI()

        # init sync thread
        self.syncThread = syncThread()

        # init scrobbler class
        self.scrobbler = Scrobbler(globals.traktapi)

        # start loop for events
        while not xbmc.abortRequested:
            if not utilities.getSetting('authorization'):
                last_reminder = utilities.getSettingAsInt('last_reminder')
                now = int(time.time())
                if last_reminder >= 0 and last_reminder < now - (24 * 60 * 60):
                    gui_utils.get_pin()
                
            while len(self.dispatchQueue) and (not xbmc.abortRequested):
                data = self.dispatchQueue.get()
                logger.debug("Queued dispatch: %s" % data)
                self._dispatch(data)

            if xbmc.Player().isPlayingVideo():
                self.scrobbler.transitionCheck()

            xbmc.sleep(500)

        # we are shutting down
        logger.debug("Beginning shut down.")

        # delete player/monitor
        del self.Player
        del self.Monitor

        # check if sync thread is running, if so, join it.
        if self.syncThread.isAlive():
            self.syncThread.join()
예제 #21
0
    def __init__(self):
        # Version
        version = "0.1.0"
        with open("version.txt") as f:
            version = f.read()
        os.environ["BUTLER_VERSION"] = version

        # Config
        config = {}
        with open("config.json") as f:
            raw_config = f.read()
            config = json.loads(raw_config)
        config_i = config["interface"]

        # Initialize
        self.sampler = Sampler(
            interface_name=config_i["name"],
            channels=config_i["channels"],
            sample_format=config_i["sample_format"],
            sample_rate=config_i["sample_rate"],
        )
        self.fp = Fingerprinter(FINGERPRINT_API_KEY)
        self.fm = Scrobbler(LASTFM_API_KEY, LASTFM_SECRET, LASTFM_SESSION_KEY)
예제 #22
0
 def login_lastfm(self):
     '''Last.fm登陆'''
     if self.lastfm and self.last_fm_username and self.last_fm_password:
         self.scrobbler = Scrobbler(
             self.last_fm_username, self.last_fm_password)
         r, err = self.scrobbler.handshake()
         if r:
             logger.info("Last.fm login succeeds!")
             print '\033[31m♥\033[0m Last.fm logged in: %s' % self.last_fm_username
         else:
             logger.error("Last.fm login fails: " + err)
             self.lastfm = False
     else:
         self.lastfm = False
예제 #23
0
    def lastfm_login(self):
        '''Last.fm登陆'''
        # username & password
        self.last_fm_username = \
            self.login_data['last_fm_username'] if 'last_fm_username' in self.login_data\
            else None
        self.last_fm_password = \
            self.login_data['last_fm_password'] if 'last_fm_password' in self.login_data\
            else None
        if len(sys.argv) > 1 and sys.argv[1] == 'last.fm':
            from hashlib import md5
            username = raw_input('Last.fm username: '******'Last.fm password :'******'r') as f:
                data = pickle.load(f)
            with open(config.PATH_TOKEN, 'w') as f:
                data['last_fm_username'] = username
                data['last_fm_password'] = self.last_fm_password
                pickle.dump(data, f)

        # login
        if self.lastfm and self.last_fm_username and self.last_fm_password:
            self.scrobbler = Scrobbler(
                self.last_fm_username, self.last_fm_password)
            r, err = self.scrobbler.handshake()
            if r:
                logger.info("Last.fm login succeeds!")
                print '\033[31m♥\033[0m Last.fm logged in: %s' % self.last_fm_username
            else:
                logger.error("Last.fm login fails: " + err)
                self.lastfm = False
        else:
            self.lastfm = False
예제 #24
0
    def get_session(self):
        if self.pyjama.settings.get_value("LIBREFM", "SCROBBLING"):

            login = str(self.pyjama.settings.get_value("LIBREFM", "LOGIN"))
            password = str(self.pyjama.settings.get_value("LIBREFM", "PASS"))

            try:
                # pyjama has own libre.fm clien id 'pyj'
                self.scrobbler = Scrobbler(client=("pyj", VERSION))
                self.scrobbler.login(login, password)
            except Exception, e:
                logging.error(e)
                self.scrobbler = None
                return False
            else:
                # self.logged=True
                return True
예제 #25
0
    def get_session(self):
        if self.pyjama.settings.get_value('LASTFM','SCROBBLING'):

            login=str(self.pyjama.settings.get_value('LASTFM','LOGIN'))
            password=str(self.pyjama.settings.get_value('LASTFM','PASS'))

            try:
                # pyjama has own last.fm clien id 'pyj'
                self.scrobbler=Scrobbler(client=('pyj',VERSION))
                self.scrobbler.login(login, password)
            except Exception, e:
                logging.error(e)
                self.scrobbler=None
                return False
            else:
                #self.logged=True
                return True
    def run(self):
        self._scrobbler = Scrobbler()
        self._scrobbler.start()
        telnet = telnetlib.Telnet(self.TELNET_ADDRESS, self.TELNET_PORT)

        while not (self.abort_requested or xbmc.abortRequested):
            try:
                data = self._read_notification(telnet)
            except EOFError:
                telnet = telnetlib.Telnet(self.TELNET_ADDRESS, self.TELNET_PORT)
                self._notification_buffer = ""
                continue

            Debug("[Notification Service] message: " + str(data))
            self._forward(data)

        telnet.close()
        self._scrobbler.abortRequested = True
        Debug("Notification service stopping")
예제 #27
0
class Doubanfm(object):
    def __init__(self):
        self.login_data = {}
        self.lastfm = True  # lastfm 登陆

    def init_login(self):
        print '''
        ──╔╗─────╔╗────────╔═╗
        ──║║─────║║────────║╔╝
        ╔═╝╠══╦╗╔╣╚═╦══╦═╗╔╝╚╦╗╔╗
        ║╔╗║╔╗║║║║╔╗║╔╗║╔╗╬╗╔╣╚╝║
        ║╚╝║╚╝║╚╝║╚╝║╔╗║║║╠╣║║║║║
        ╚══╩══╩══╩══╩╝╚╩╝╚╩╩╝╚╩╩╝

        '''
        self.douban_login()  # 登陆
        self.login_lastfm()  # 登陆 last.fm
        print '\033[31m♥\033[0m Get channels ',
        # self.get_channels()  # 获取频道列表
        print '[\033[32m OK \033[0m]'
        # self.get_channellines()  # 重构列表用以显示
        print '\033[31m♥\033[0m Check PRO ',
        # self.is_pro()
        print '[\033[32m OK \033[0m]'

    def win_login(self):
        '''登陆界面'''
        email = raw_input('Email:')
        password = getpass.getpass('Password:'******'''Last.fm登陆'''
        if self.lastfm and self.last_fm_username and self.last_fm_password:
            self.scrobbler = Scrobbler(
                self.last_fm_username, self.last_fm_password)
            r, err = self.scrobbler.handshake()
            if r:
                logger.info("Last.fm login succeeds!")
                print '\033[31m♥\033[0m Last.fm logged in: %s' % self.last_fm_username
            else:
                logger.error("Last.fm login fails: " + err)
                self.lastfm = False
        else:
            self.lastfm = False

    def last_fm_account_required(fun):
        '''装饰器,用于需要登录Last.fm后才能使用的接口'''
        @wraps(fun)
        def wrapper(self, *args, **kwds):
            if not self.lastfm:
                return
            return fun(self, *args, **kwds)
        return wrapper

    @last_fm_account_required
    def submit_current_song(self):
        '''提交播放过的曲目'''
        # Submit the track if total playback time of the track > 30s
        if self.playingsong['length'] > 30:
            self.scrobbler.submit(
                self.playingsong['artist'],
                self.playingsong['title'],
                self.playingsong['albumtitle'],
                self.playingsong['length']
            )

    @last_fm_account_required
    def scrobble_now_playing(self):
        '''提交当前正在播放曲目'''
        self.scrobbler.now_playing(
            self.playingsong['artist'],
            self.playingsong['title'],
            self.playingsong['albumtitle'],
            self.playingsong['length']
        )

    def douban_login(self):
        '''登陆douban.fm获取token'''
        path_token = os.path.expanduser('~/.douban_token.txt')
        if os.path.exists(path_token):
            # 已登陆
            logger.info("Found existing Douban.fm token.")
            with open(path_token, 'r') as f:
                self.login_data = pickle.load(f)
                self.token = self.login_data['token']
                self.user_name = self.login_data['user_name']
                self.user_id = self.login_data['user_id']
                self.expire = self.login_data['expire']
                self.default_volume = int(self.login_data['volume'])\
                    if 'volume' in self.login_data else 50
                self.default_channel = int(self.login_data['channel'])\
                    if 'channel' in self.login_data else 1

                # 存储的default_channel是行数而不是真正发送数据的channel_id
                # 这里需要进行转化一下
                self.set_channel(self.default_channel)
            print '\033[31m♥\033[0m Get local token - Username: \033[33m%s\033[0m' % self.user_name
        else:
            # 未登陆
            logger.info('First time logging in Douban.fm.')
            while True:
                self.email, self.password = self.win_login()
                login_data = {
                    'app_name': 'radio_desktop_win',
                    'version': '100',
                    'email': self.email,
                    'password': self.password
                }
                s = requests.post('http://www.douban.com/j/app/login', login_data)
                dic = eval(s.text)
                if dic['r'] == 1:
                    logger.debug(dic['err'])
                    continue
                else:
                    self.token = dic['token']
                    self.user_name = dic['user_name']
                    self.user_id = dic['user_id']
                    self.expire = dic['expire']
                    self.default_volume = 50
                    self.default_channel = 1
                    self.login_data = {
                        'app_name': 'radio_desktop_win',
                        'version': '100',
                        'user_id': self.user_id,
                        'expire': self.expire,
                        'token': self.token,
                        'user_name': self.user_name,
                        'volume': '50',
                        'channel': '0'
                    }
                    logger.info('Logged in username: '******'w') as f:
                        pickle.dump(self.login_data, f)
                        logger.debug('Write data to ' + path_token)
                    break

        self.last_fm_username = \
            self.login_data['last_fm_username'] if 'last_fm_username' in self.login_data\
            else None
        self.last_fm_password = \
            self.login_data['last_fm_password'] if 'last_fm_password' in self.login_data\
            else None
        # last.fm登陆
        try:
            if sys.argv[1] == 'last.fm':
                from hashlib import md5
                username = raw_input('last.fm username:'******'last.fm password:'******'r') as f:
                    data = pickle.load(f)
                with open(path_token, 'w') as f:
                    data['last_fm_username'] = username
                    data['last_fm_password'] = self.last_fm_password
                    pickle.dump(data, f)
        except IndexError:
            pass

        # 配置文件
        path_config = os.path.expanduser('~/.doubanfm_config')
        if not os.path.exists(path_config):
            print '\033[31m♥\033[0m Get default config [\033[32m OK \033[0m]'
            config = '''[key]
UP = k
DOWN = j
TOP = g
BOTTOM = G
OPENURL = w
RATE = r
NEXT = n
BYE = b
QUIT = q
PAUSE = p
LOOP = l
MUTE = m
LRC = o
'''  # 这个很丑,怎么办
            with open(path_config, 'w') as F:
                F.write(config)
        else:
            print '\033[31m♥\033[0m Get local config [\033[32m OK \033[0m]'

    @property
    def channels(self):
        '''获取channel,存入self.channels'''
        # 红心兆赫需要手动添加
        channels = [{
            'name': '红心兆赫',
            'channel_id': -3
        }]
        r = requests.get('http://www.douban.com/j/app/radio/channels')
        channels += eval(r.text)['channels']
        # 格式化频道列表,以便display
        lines = []
        for channel in channels:
            lines.append(channel['name'])
        return lines

    def requests_url(self, ptype, **data):
        '''这里包装了一个函数,发送post_data'''
        post_data = self.login_data.copy()
        post_data['type'] = ptype
        for x in data:
            post_data[x] = data[x]
        url = 'http://www.douban.com/j/app/radio/people?' + urllib.urlencode(post_data)
        try:
            s = requests.get(url)
        except requests.exceptions.RequestException:
            logger.error("Error communicating with Douban.fm API.")

        return s.text

    def set_channel(self, channel):
        '''把行数转化成channel_id'''
        self.default_channel = channel
        channel = -3 if channel == 0 else channel - 1
        self.login_data['channel'] = channel

    def get_playlist(self, channel):
        '''获取播放列表,返回一个list'''
        if self.default_channel != channel:
            self.set_channel(channel)
        s = self.requests_url('n')
        return eval(s)['song']

    def skip_song(self, playingsong):
        '''下一首,返回一个list'''
        s = self.requests_url('s', sid=playingsong['sid'])
        return eval(s)['song']

    def bye(self, playingsong):
        '''不再播放,返回一个list'''
        s = self.requests_url('b', sid=playingsong['sid'])
        return eval(s)['song']

    def rate_music(self, playingsong):
        '''标记喜欢歌曲'''
        self.requests_url('r', sid=playingsong['sid'])
        # self.playlist = eval(s)['song']

    def unrate_music(self, playingsong):
        '''取消标记喜欢歌曲'''
        self.requests_url('u', sid=playingsong['sid'])
        # self.playlist = eval(s)['song']

    def submit_music(self, playingsong):
        '''歌曲结束标记'''
        self.requests_url('e', sid=playingsong['sid'])

    def get_pic(self, playingsong, tempfile_path):
        '''获取专辑封面'''
        url = playingsong['picture'].replace('\\', '')
        for i in range(3):
            try:
                urllib.urlretrieve(url, tempfile_path)
                logger.debug('Get cover art success!')
                return True
            except (IOError, urllib.ContentTooShortError):
                pass
        logger.error('Get cover art failed!')
        return False

    def get_lrc(self, playingsong):
        '''获取歌词'''
        try:
            url = "http://api.douban.com/v2/fm/lyric"
            postdata = {
                'sid': playingsong['sid'],
                'ssid': playingsong['ssid'],
            }
            s = requests.session()
            response = s.post(url, data=postdata)
            lyric = eval(response.text)
            logger.debug(response.text)
            lrc_dic = lrc2dic.lrc2dict(lyric['lyric'])
            # 原歌词用的unicode,为了兼容
            for key, value in lrc_dic.iteritems():
                lrc_dic[key] = value.decode('utf-8')
            if lrc_dic:
                logger.debug('Get lyric success!')
            return lrc_dic
        except requests.exceptions.RequestException:
            logger.error('Get lyric failed!')
            return 0
예제 #28
0
class Doubanfm(object):
    def __init__(self):
        self.login_data = {}
        self.lastfm = True  # lastfm 登陆

    def init_login(self):
        print '''
        ──╔╗─────╔╗────────╔═╗
        ──║║─────║║────────║╔╝
        ╔═╝╠══╦╗╔╣╚═╦══╦═╗╔╝╚╦╗╔╗
        ║╔╗║╔╗║║║║╔╗║╔╗║╔╗╬╗╔╣╚╝║
        ║╚╝║╚╝║╚╝║╚╝║╔╗║║║╠╣║║║║║
        ╚══╩══╩══╩══╩╝╚╩╝╚╩╩╝╚╩╩╝

        '''
        self.douban_login()  # 登陆
        self.login_lastfm()  # 登陆 last.fm
        print '\033[31m♥\033[0m Get channels ',
        # self.get_channels()  # 获取频道列表
        print '[\033[32m OK \033[0m]'
        # self.get_channellines()  # 重构列表用以显示
        print '\033[31m♥\033[0m Check PRO ',
        # self.is_pro()
        print '[\033[32m OK \033[0m]'

    def win_login(self):
        '''登陆界面'''
        email = raw_input('Email:')
        password = getpass.getpass('Password:'******'''Last.fm登陆'''
        if self.lastfm and self.last_fm_username and self.last_fm_password:
            self.scrobbler = Scrobbler(self.last_fm_username,
                                       self.last_fm_password)
            r, err = self.scrobbler.handshake()
            if r:
                logger.info("Last.fm login succeeds!")
                print '\033[31m♥\033[0m Last.fm logged in: %s' % self.last_fm_username
            else:
                logger.error("Last.fm login fails: " + err)
                self.lastfm = False
        else:
            self.lastfm = False

    def last_fm_account_required(fun):
        '''装饰器,用于需要登录Last.fm后才能使用的接口'''
        @wraps(fun)
        def wrapper(self, *args, **kwds):
            if not self.lastfm:
                return
            return fun(self, *args, **kwds)

        return wrapper

    @last_fm_account_required
    def submit_current_song(self):
        '''提交播放过的曲目'''
        # Submit the track if total playback time of the track > 30s
        if self.playingsong['length'] > 30:
            self.scrobbler.submit(self.playingsong['artist'],
                                  self.playingsong['title'],
                                  self.playingsong['albumtitle'],
                                  self.playingsong['length'])

    @last_fm_account_required
    def scrobble_now_playing(self):
        '''提交当前正在播放曲目'''
        self.scrobbler.now_playing(self.playingsong['artist'],
                                   self.playingsong['title'],
                                   self.playingsong['albumtitle'],
                                   self.playingsong['length'])

    def douban_login(self):
        '''登陆douban.fm获取token'''
        path_token = os.path.expanduser('~/.douban_token.txt')
        if os.path.exists(path_token):
            # 已登陆
            logger.info("Found existing Douban.fm token.")
            with open(path_token, 'r') as f:
                self.login_data = pickle.load(f)
                self.token = self.login_data['token']
                self.user_name = self.login_data['user_name']
                self.user_id = self.login_data['user_id']
                self.expire = self.login_data['expire']
                self.default_volume = int(self.login_data['volume'])\
                    if 'volume' in self.login_data else 50
                self.default_channel = int(self.login_data['channel'])\
                    if 'channel' in self.login_data else 1

                # 存储的default_channel是行数而不是真正发送数据的channel_id
                # 这里需要进行转化一下
                self.set_channel(self.default_channel)
            print '\033[31m♥\033[0m Get local token - Username: \033[33m%s\033[0m' % self.user_name
        else:
            # 未登陆
            logger.info('First time logging in Douban.fm.')
            while True:
                self.email, self.password = self.win_login()
                login_data = {
                    'app_name': 'radio_desktop_win',
                    'version': '100',
                    'email': self.email,
                    'password': self.password
                }
                s = requests.post('http://www.douban.com/j/app/login',
                                  login_data)
                dic = eval(s.text)
                if dic['r'] == 1:
                    logger.debug(dic['err'])
                    continue
                else:
                    self.token = dic['token']
                    self.user_name = dic['user_name']
                    self.user_id = dic['user_id']
                    self.expire = dic['expire']
                    self.default_volume = 50
                    self.default_channel = 1
                    self.login_data = {
                        'app_name': 'radio_desktop_win',
                        'version': '100',
                        'user_id': self.user_id,
                        'expire': self.expire,
                        'token': self.token,
                        'user_name': self.user_name,
                        'volume': '50',
                        'channel': '0'
                    }
                    logger.info('Logged in username: '******'w') as f:
                        pickle.dump(self.login_data, f)
                        logger.debug('Write data to ' + path_token)
                    break

        self.last_fm_username = \
            self.login_data['last_fm_username'] if 'last_fm_username' in self.login_data\
            else None
        self.last_fm_password = \
            self.login_data['last_fm_password'] if 'last_fm_password' in self.login_data\
            else None
        # last.fm登陆
        try:
            if sys.argv[1] == 'last.fm':
                from hashlib import md5
                username = raw_input('last.fm username:'******'last.fm password:'******'r') as f:
                    data = pickle.load(f)
                with open(path_token, 'w') as f:
                    data['last_fm_username'] = username
                    data['last_fm_password'] = self.last_fm_password
                    pickle.dump(data, f)
        except IndexError:
            pass

        # 配置文件
        path_config = os.path.expanduser('~/.doubanfm_config')
        if not os.path.exists(path_config):
            print '\033[31m♥\033[0m Get default config [\033[32m OK \033[0m]'
            config = '''[key]
UP = k
DOWN = j
TOP = g
BOTTOM = G
OPENURL = w
RATE = r
NEXT = n
BYE = b
QUIT = q
PAUSE = p
LOOP = l
MUTE = m
LRC = o
'''  # 这个很丑,怎么办
            with open(path_config, 'w') as F:
                F.write(config)
        else:
            print '\033[31m♥\033[0m Get local config [\033[32m OK \033[0m]'

    @property
    def channels(self):
        '''获取channel,存入self.channels'''
        # 红心兆赫需要手动添加
        channels = [{'name': '红心兆赫', 'channel_id': -3}]
        r = requests.get('http://www.douban.com/j/app/radio/channels')
        channels += eval(r.text)['channels']
        # 格式化频道列表,以便display
        lines = []
        for channel in channels:
            lines.append(channel['name'])
        return lines

    def requests_url(self, ptype, **data):
        '''这里包装了一个函数,发送post_data'''
        post_data = self.login_data.copy()
        post_data['type'] = ptype
        for x in data:
            post_data[x] = data[x]
        url = 'http://www.douban.com/j/app/radio/people?' + urllib.urlencode(
            post_data)
        try:
            s = requests.get(url)
        except requests.exceptions.RequestException:
            logger.error("Error communicating with Douban.fm API.")

        return s.text

    def set_channel(self, channel):
        '''把行数转化成channel_id'''
        self.default_channel = channel
        channel = -3 if channel == 0 else channel - 1
        self.login_data['channel'] = channel

    def get_playlist(self, channel):
        '''获取播放列表,返回一个list'''
        if self.default_channel != channel:
            self.set_channel(channel)
        s = self.requests_url('n')
        return eval(s)['song']

    def skip_song(self, playingsong):
        '''下一首,返回一个list'''
        s = self.requests_url('s', sid=playingsong['sid'])
        return eval(s)['song']

    def bye(self, playingsong):
        '''不再播放,返回一个list'''
        s = self.requests_url('b', sid=playingsong['sid'])
        return eval(s)['song']

    def rate_music(self, playingsong):
        '''标记喜欢歌曲'''
        self.requests_url('r', sid=playingsong['sid'])
        # self.playlist = eval(s)['song']

    def unrate_music(self, playingsong):
        '''取消标记喜欢歌曲'''
        self.requests_url('u', sid=playingsong['sid'])
        # self.playlist = eval(s)['song']

    def submit_music(self, playingsong):
        '''歌曲结束标记'''
        self.requests_url('e', sid=playingsong['sid'])

    def get_pic(self, playingsong, tempfile_path):
        '''获取专辑封面'''
        url = playingsong['picture'].replace('\\', '')
        for i in range(3):
            try:
                urllib.urlretrieve(url, tempfile_path)
                logger.debug('Get cover art success!')
                return True
            except (IOError, urllib.ContentTooShortError):
                pass
        logger.error('Get cover art failed!')
        return False

    def get_lrc(self, playingsong):
        '''获取歌词'''
        try:
            url = "http://api.douban.com/v2/fm/lyric"
            postdata = {
                'sid': playingsong['sid'],
                'ssid': playingsong['ssid'],
            }
            s = requests.session()
            response = s.post(url, data=postdata)
            lyric = eval(response.text)
            logger.debug(response.text)
            lrc_dic = lrc2dic.lrc2dict(lyric['lyric'])
            # 原歌词用的unicode,为了兼容
            for key, value in lrc_dic.iteritems():
                lrc_dic[key] = value.decode('utf-8')
            if lrc_dic:
                logger.debug('Get lyric success!')
            return lrc_dic
        except requests.exceptions.RequestException:
            logger.error('Get lyric failed!')
            return 0
class NotificationService(threading.Thread):
    """ Receives XBMC notifications and passes them off as needed """
    TELNET_ADDRESS = 'localhost'
    TELNET_PORT = 9090

    abort_requested = False
    _scrobbler = None
    _notification_buffer = ""


    def _forward(self, notification):
        """ Fowards the notification recieved to a function on the scrobbler """
        if not ('method' in notification and 'params' in notification and 'sender' in notification['params'] and notification['params']['sender'] == 'xbmc'):
            return

        if notification['method'] == 'Player.OnStop':
            self._scrobbler.playback_ended()
        elif notification['method'] == 'Player.OnPlay':
            if 'data' in notification['params'] and 'item' in notification['params']['data'] and 'id' in notification['params']['data']['item'] and 'type' in notification['params']['data']['item']:
                self._scrobbler.playback_started(notification['params']['data'])
        elif notification['method'] == 'Player.OnPause':
            self._scrobbler.playback_paused()
        elif notification['method'] == 'System.OnQuit':
            self.abort_requested = True


    def _read_notification(self, telnet):
        """ Read a notification from the telnet connection, blocks until the data is available, or else raises an EOFError if the connection is lost """
        while True:
            try:
                addbuffer = telnet.read_some()
            except socket.timeout:
                continue

            if addbuffer == "":
                raise EOFError

            self._notification_buffer += addbuffer
            try:
                data, offset = json.JSONDecoder().raw_decode(self._notification_buffer)
                self._notification_buffer = self._notification_buffer[offset:]
            except ValueError:
                continue

            return data


    def run(self):
        self._scrobbler = Scrobbler()
        self._scrobbler.start()
        telnet = telnetlib.Telnet(self.TELNET_ADDRESS, self.TELNET_PORT)

        while not (self.abort_requested or xbmc.abortRequested):
            try:
                data = self._read_notification(telnet)
            except EOFError:
                telnet = telnetlib.Telnet(self.TELNET_ADDRESS, self.TELNET_PORT)
                self._notification_buffer = ""
                continue

            Debug("[Notification Service] message: " + str(data))
            self._forward(data)

        telnet.close()
        self._scrobbler.abortRequested = True
        Debug("Notification service stopping")
예제 #30
0
    def run(self):
        #while xbmc is running
        scrobbler = Scrobbler()
        scrobbler.start()

        while (not (self.abortRequested or xbmc.abortRequested)):
            time.sleep(1)
            try:
                tn = telnetlib.Telnet('localhost', 9090, 10)
            except IOError as (errno, strerror):
                #connection failed, try again soon
                Debug("[Notification Service] Telnet too soon? (" +
                      str(errno) + ") " + strerror)
                time.sleep(1)
                continue

            Debug("[Notification Service] Waiting~")
            bCount = 0

            while (not (self.abortRequested or xbmc.abortRequested)):
                try:
                    if bCount == 0:
                        notification = ""
                        inString = False
                    [index, match, raw] = tn.expect(
                        ["(\\\\)|(\\\")|[{\"}]"],
                        0.2)  #note, pre-compiled regex might be faster here
                    notification += raw
                    if index == -1:  # Timeout
                        continue
                    if index == 0:  # Found escaped quote
                        match = match.group(0)
                        if match == "\"":
                            inString = not inString
                            continue
                        if match == "{":
                            bCount += 1
                        if match == "}":
                            bCount -= 1
                    if bCount > 0:
                        continue
                    if bCount < 0:
                        bCount = 0
                except EOFError:
                    break  #go out to the other loop to restart the connection

                Debug("[Notification Service] message: " + str(notification))

                # Parse recieved notification
                data = json.loads(notification)

                # Forward notification to functions
                if 'method' in data and 'params' in data and 'sender' in data[
                        'params'] and data['params']['sender'] == 'xbmc':
                    if data['method'] == 'Player.OnStop':
                        scrobbler.playbackEnded()
                    elif data['method'] == 'Player.OnPlay':
                        if 'data' in data['params'] and 'item' in data[
                                'params']['data'] and 'id' in data['params'][
                                    'data']['item'] and 'type' in data[
                                        'params']['data']['item']:
                            scrobbler.playbackStarted(data['params']['data'])
                    elif data['method'] == 'Player.OnPause':
                        scrobbler.playbackPaused()
                    elif data['method'] == 'VideoLibrary.OnUpdate':
                        if 'data' in data['params'] and 'playcount' in data[
                                'params']['data']:
                            instantSyncPlayCount(data)
                    elif data['method'] == 'System.OnQuit':
                        self.abortRequested = True
예제 #31
0
headers = {
    'User-Agent':
    'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:27.0) Gecko/20100101 Firefox/27.0',
    'Accept':
    'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
    'Accept-Language': 'zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3',
    'Accept-Encoding': 'gzip, deflate',
    'DNT': '1',
    'Connection': 'keep-alive'
}

# 虾米个人首页地址
xiami_url = 'http://www.xiami.com/space/charts-recent/u/41714420/'
# 用户名和MD5的密码
scrobbler = Scrobbler('skyline75489', '989f9717dce59b6c2f40a6ee940fa95c')


def get_tracks():
    r = requests.get(xiami_url, headers=headers)
    soup = BeautifulSoup(r.content)
    minutes = 5
    track_times = soup.findAll('td', class_='track_time')
    track_times = [
        re.search(u'\d+', track_time.text).group()
        for track_time in track_times if re.search(u'分钟前', track_time.text)
    ]
    second_html = soup.find('td', class_='track_time')
    if second_html:
        second_exist = re.search(u'秒前|刚刚', second_html.text)
    else:
예제 #32
0
파일: pyfm.py 프로젝트: JamesTing/pyfm
class Doubanfm:

    def __init__(self):
        self.email = None
        self.password = None
        self.user_name = None
        self.user_id = None
        self.expire = None
        self.token = None
        self.cookies = None
        
        self.last_fm_username = None
        self.last_fm_password = None
        self.scrobbling = True
        self.douban_account = True
        self.channels = None
        
        # Set up config
        try:
            arg = sys.argv[1]
            self._do_config()
        except IndexError:
            self._load_config()
        
        # Init API tools
        self.douban = Douban(
            self.email, self.password, self.user_id, self.expire, self.token, self.user_name, self.cookies)
        self.player = Player()
        self.current_channel = 0
        self.current_song = None
        self.current_play_list = None

        # Init terminal ui
        self.palette = [('selected', 'bold', 'default'),
                        ('title', 'yellow', 'default')]
        self.selected_button = None
        self.main_loop = None
        self.song_change_alarm = None
        
        # Try to login
        if self.last_fm_username is None or self.last_fm_username == "":
            self.scrobbling = False
        if (self.email is None or self.email == "") and self.cookies == None:
            self.douban_account = False
            
        if self.scrobbling:
            self.scrobbler = Scrobbler(
                self.last_fm_username, self.last_fm_password)
            r, err = self.scrobbler.handshake()
            if r:
                print("Last.FM 已登陆")
            else:
                print("Last.FM 登录失败: " + err)
        if self.douban_account:
            r, err = self.douban.do_login()
            if r:
                print("Douban 已登陆")
            else:
                print("Douban 登录失败: " + err)
        self.get_channels()
        self._save_cache()

    def _do_config(self):
        self.email = input('豆瓣账户 (Email地址): ') or None
        self.password = getpass('豆瓣密码: ') or None
        self.last_fm_username = input('Last.fm 用户名: ') or None
        password = getpass('Last.fm 密码: ') or None
        self.last_fm_password = md5(password.encode('utf-8')).hexdigest() 
                
    def _load_config(self):
        try:
            f = open('channels.json', 'r')
            self.channels = deque(json.load(f))
            logger.debug("Load channel file.")
        except FileNotFoundError:
            logger.debug("Channels file not found.")
            
        try: 
            f = open('cache.json', 'r')
            cache = json.load(f)
            try:
                self.user_name = cache['user_name']
                self.user_id = cache['user_id']
                self.expire = cache['expire']
                self.token = cache['token']
                self.cookies = cache['cookies']
            except (KeyError, ValueError):
                self.douban_account = False
            try:
                self.last_fm_username = cache['last_fm_username']
                self.last_fm_password = cache['last_fm_password']
            except (KeyError, ValueError):
                self.scrobbling = False
    
        except FileNotFoundError:
            logger.debug("Cache file not found.")

    def _save_cache(self):
        f = None
        try:
            f = open('cache.json', 'w')
            f2 = open('channels.json', 'w')
            json.dump({
                'user_name': self.douban.user_name,
                'user_id': self.douban.user_id,
                'expire': self.douban.expire,
                'token': self.douban.token,
                'cookies': self.douban.cookies,
                'last_fm_username': self.last_fm_username,
                'last_fm_password': self.last_fm_password
            }, f)
            json.dump(list(self.channels), f2)
        except IOError:
            raise Exception("Unable to write cache file")

    def get_channels(self):
        if self.channels is None:
            self.channels = deque(self.douban.get_channels())

    def _choose_channel(self, channel):
        self.current_channel = channel
        self.current_play_list = deque(
            self.douban.get_new_play_list(self.current_channel))

    def _play_track(self):
        _song = self.current_play_list.popleft()
        self.current_song = Song(_song)
        logger.debug('Playing Track')
        logger.debug('Artist: ' + self.current_song.artist)
        logger.debug('Title: ' + self.current_song.song_title)
        logger.debug('Album: ' + self.current_song.album_title)
        logger.debug('Length: ' + self.current_song.length_in_str)
        logger.debug('Sid: ' + self.current_song.sid)

        logger.debug(
            '{0} tracks remaining in the playlist'.format(len(self.current_play_list)))

        self.song_change_alarm = self.main_loop.set_alarm_in(self.current_song.length_in_sec,
                                                             self.next_song, None)
        self.selected_button.set_text(self.selected_button.text[0:11].strip())
        heart = u'\N{WHITE HEART SUIT}'
        if self.current_song.like:
            heart = u'\N{BLACK HEART SUIT}'
        if not self.douban_account:
            heart = ' '
        self.selected_button.set_text(self.selected_button.text + '                 ' + heart + '  ' +
                                      self.current_song.artist + ' - ' +
                                      self.current_song.song_title)
        if self.scrobbling:
            self.scrobbler.now_playing(self.current_song.artist, self.current_song.song_title,
                                       self.current_song.album_title, self.current_song.length_in_sec)

        self.player.stop()
        self.player.play(self.current_song)
        # Currently playing the second last song in queue
        if len(self.current_play_list) == 1:
            # Extend the playing list
            playing_list = self.douban.get_playing_list(
                self.current_song.sid, self.current_channel)
            logger.debug('Got {0} more tracks'.format(len(playing_list)))
            self.current_play_list.extend(deque(playing_list))

    def next_song(self, loop, user_data):
        # Scrobble the track if scrobbling is enabled
        # and total playback time of the track > 30s
        if self.scrobbling and self.current_song.length_in_sec > 30:
            self.scrobbler.submit(self.current_song.artist, self.current_song.song_title,
                                  self.current_song.album_title, self.current_song.length_in_sec)

        if self.douban_account:
            r, err = self.douban.end_song(
                self.current_song.sid, self.current_channel)
            if r:
                logger.debug('End song OK')
            else:
                logger.error(err)
        if self.song_change_alarm:
            self.main_loop.remove_alarm(self.song_change_alarm)
        self._play_track()

    def skip_current_song(self):
        if self.douban_account:
            r, err = self.douban.skip_song(
                self.current_song.sid, self.current_channel)
            if r:
                logger.debug('Skip song OK')
            else:
                logger.error(err)
        if self.song_change_alarm:
            self.main_loop.remove_alarm(self.song_change_alarm)
        self._play_track()

    def rate_current_song(self):
        if not self.douban_account:
            return
        r, err = self.douban.rate_song(
            self.current_song.sid, self.current_channel)
        if r:
            self.current_song.like = True
            self.selected_button.set_text(self.selected_button.text.replace(
                u'\N{WHITE HEART SUIT}', u'\N{BLACK HEART SUIT}'))
            logger.debug('Rate song OK')
        else:
            logger.error(err)

    def unrate_current_song(self):
        if not self.douban_account:
            return
        r, err = self.douban.unrate_song(
            self.current_song.sid, self.current_channel)
        if r:
            self.current_song.like = False
            self.selected_button.set_text(self.selected_button.text.replace(
                u'\N{BLACK HEART SUIT}', u'\N{WHITE HEART SUIT}'))
            logger.debug('Unrate song OK')
        else:
            logger.error(err)

    def trash_current_song(self):
        if not self.douban_account:
            return
        r, err = self.douban.bye_song(
            self.current_song.sid, self.current_channel)
        if r:
            # play next song
            if self.song_change_alarm:
                self.main_loop.remove_alarm(self.song_change_alarm)
            self._play_track()
            logger.debug('Trash song OK')
        else:
            logger.error(err)

    def quit(self):
        logger.debug('Quit')
        self.player.stop()

    def start(self):
        title = urwid.AttrMap(urwid.Text('豆瓣FM'), 'title')
        divider = urwid.Divider()
        pile = urwid.Padding(
            urwid.Pile([divider, title, divider]), left=4, right=4)
        box = urwid.Padding(self.ChannelListBox(), left=2, right=4)

        frame = urwid.Frame(box, header=pile, footer=divider)

        self.main_loop = urwid.MainLoop(
            frame, self.palette, handle_mouse=False)
        self.main_loop.run()

    def ChannelListBox(self):
        body = []
        for c in self.channels:
            _channel = ChannelButton(c['name'])
            urwid.connect_signal(
                _channel, 'click', self.channel_chosen, c['channel_id'])
            body.append(urwid.AttrMap(_channel, None, focus_map="channel"))
        return MyListBox(urwid.SimpleFocusListWalker(body), self)

    def channel_chosen(self, button, choice):
        # Choose the channel which is playing right now
        # ignore this
        if self.selected_button == button:
            return
        # Choose a different channel
        if self.player.is_playing:
            self.player.stop()
        self._choose_channel(choice)
        if self.selected_button != None and button != self.selected_button:
            self.selected_button.set_text(
                self.selected_button.text[0:11].strip())
        self.selected_button = button
        if self.song_change_alarm:
            self.main_loop.remove_alarm(self.song_change_alarm)
        self._play_track()
예제 #33
0
class traktService:

    scrobbler = None
    tagger = None
    updateTagsThread = None
    watcher = None
    syncThread = None
    dispatchQueue = queue.SqliteQueue()
    _interval = 10 * 60  # how often to send watching call

    def __init__(self):
        threading.Thread.name = 'trakt'

    def _dispatchQueue(self, data):
        utilities.Debug("Queuing for dispatch: %s" % data)
        self.dispatchQueue.append(data)

    def _dispatch(self, data):
        utilities.Debug("Dispatch: %s" % data)
        action = data['action']
        if action == 'started':
            del data['action']
            self.scrobbler.playbackStarted(data)
            self.watcher = threading.Timer(self._interval, self.doWatching)
            self.watcher.name = "trakt-watching"
            self.watcher.start()
        elif action == 'ended' or action == 'stopped':
            self.scrobbler.playbackEnded()
            if self.watcher:
                if self.watcher.isAlive():
                    self.watcher.cancel()
                    self.watcher = None
        elif action == 'paused':
            self.scrobbler.playbackPaused()
        elif action == 'resumed':
            self.scrobbler.playbackResumed()
        elif action == 'seek' or action == 'seekchapter':
            self.scrobbler.playbackSeek()
        elif action == 'databaseUpdated':
            self.doSync()
        elif action == 'scanStarted':
            pass
        elif action == 'settingsChanged':
            utilities.Debug("Settings changed, reloading.")
            globals.traktapi.updateSettings()
            self.tagger.updateSettings()
        elif action == 'markWatched':
            del data['action']
            self.doMarkWatched(data)
        elif action == 'manualRating':
            ratingData = data['ratingData']
            self.doManualRating(ratingData)
        elif action == 'manualSync':
            if not self.syncThread.isAlive():
                utilities.Debug("Performing a manual sync.")
                self.doSync(manual=True)
            else:
                utilities.Debug("There already is a sync in progress.")
        elif action == 'updatetags':
            if self.updateTagsThread and self.updateTagsThread.isAlive():
                utilities.Debug("Currently updating tags already.")
            else:
                self.updateTagsThread = threading.Thread(
                    target=self.tagger.updateTagsFromTrakt,
                    name="trakt-updatetags")
                self.updateTagsThread.start()
        elif action == 'managelists':
            self.tagger.manageLists()
        elif action == 'itemlists':
            del data['action']
            self.tagger.itemLists(data)
        elif action == 'addtolist':
            del data['action']
            list = data['list']
            del data['list']
            self.tagger.manualAddToList(list, data)
        elif action == 'removefromlist':
            del data['action']
            list = data['list']
            del data['list']
            self.tagger.manualRemoveFromList(list, data)
        else:
            utilities.Debug("Unknown dispatch action, '%s'." % action)

    def run(self):
        startup_delay = utilities.getSettingAsInt('startup_delay')
        if startup_delay:
            utilities.Debug("Delaying startup by %d seconds." % startup_delay)
            xbmc.sleep(startup_delay * 1000)

        utilities.Debug("Service thread starting.")

        # setup event driven classes
        self.Player = traktPlayer(action=self._dispatchQueue)
        self.Monitor = traktMonitor(action=self._dispatchQueue)

        # init traktapi class
        globals.traktapi = traktAPI()

        # init sync thread
        self.syncThread = syncThread()

        # init scrobbler class
        self.scrobbler = Scrobbler(globals.traktapi)

        # init tagging class
        self.tagger = Tagger(globals.traktapi)

        # purge queue
        self.dispatchQueue.purge()

        # start loop for events
        while (not xbmc.abortRequested):
            while len(self.dispatchQueue) and (not xbmc.abortRequested):
                data = self.dispatchQueue.get()
                utilities.Debug("Queued dispatch: %s" % data)
                self._dispatch(data)

            if xbmc.Player().isPlayingVideo():
                self.scrobbler.update()

            xbmc.sleep(500)

        # we are shutting down
        utilities.Debug("Beginning shut down.")

        # check if watcher is set and active, if so, cancel it.
        if self.watcher:
            if self.watcher.isAlive():
                self.watcher.cancel()

        # delete player/monitor
        del self.Player
        del self.Monitor

        # check update tags thread.
        if self.updateTagsThread and self.updateTagsThread.isAlive():
            self.updateTagsThread.join()

        # check if sync thread is running, if so, join it.
        if self.syncThread.isAlive():
            self.syncThread.join()

    def doWatching(self):
        # check if we're still playing a video
        if not xbmc.Player().isPlayingVideo():
            self.watcher = None
            return

        # call watching method
        self.scrobbler.watching()

        # start a new timer thread
        self.watcher = threading.Timer(self._interval, self.doWatching)
        self.watcher.name = "trakt-watching"
        self.watcher.start()

    def doManualRating(self, data):

        action = data['action']
        media_type = data['media_type']
        summaryInfo = None

        if not utilities.isValidMediaType(media_type):
            utilities.Debug(
                "doManualRating(): Invalid media type '%s' passed for manual %s."
                % (media_type, action))
            return

        if not data['action'] in ['rate', 'unrate']:
            utilities.Debug("doManualRating(): Unknown action passed.")
            return

        if 'dbid' in data:
            utilities.Debug(
                "Getting data for manual %s of library '%s' with ID of '%s'" %
                (action, media_type, data['dbid']))
        elif 'remoteitd' in data:
            if 'season' in data:
                utilities.Debug(
                    "Getting data for manual %s of non-library '%s' S%02dE%02d, with ID of '%s'."
                    % (action, media_type, data['season'], data['episode'],
                       data['remoteid']))
            else:
                utilities.Debug(
                    "Getting data for manual %s of non-library '%s' with ID of '%s'"
                    % (action, media_type, data['remoteid']))

        if utilities.isEpisode(media_type):
            summaryInfo = globals.traktapi.getEpisodeSummary(
                data['tvdb_id'], data['season'], data['episode'])
        elif utilities.isShow(media_type):
            summaryInfo = globals.traktapi.getShowSummary(data['imdbnumber'])
        elif utilities.isMovie(media_type):
            summaryInfo = globals.traktapi.getMovieSummary(data['imdbnumber'])

        if not summaryInfo is None:
            if utilities.isMovie(media_type) or utilities.isShow(media_type):
                summaryInfo['xbmc_id'] = data['dbid']

            if action == 'rate':
                if not 'rating' in data:
                    rateMedia(media_type, summaryInfo)
                else:
                    rateMedia(media_type, summaryInfo, rating=data['rating'])
            elif action == 'unrate':
                rateMedia(media_type, summaryInfo, unrate=True)
        else:
            utilities.Debug(
                "doManualRating(): Summary info was empty, possible problem retrieving data from trakt.tv"
            )

    def doMarkWatched(self, data):

        media_type = data['media_type']
        simulate = utilities.getSettingAsBool('simulate_sync')
        markedNotification = utilities.getSettingAsBool(
            'show_marked_notification')

        if utilities.isMovie(media_type):
            summaryInfo = globals.traktapi.getMovieSummary(data['id'])
            if summaryInfo:
                if not summaryInfo['watched']:
                    s = utilities.getFormattedItemName(media_type, summaryInfo)
                    utilities.Debug(
                        "doMarkWatched(): '%s' is not watched on trakt, marking it as watched."
                        % s)
                    movie = {}
                    movie['imdb_id'] = data['id']
                    movie['title'] = summaryInfo['title']
                    movie['year'] = summaryInfo['year']
                    movie['plays'] = 1
                    movie['last_played'] = int(time())
                    params = {'movies': [movie]}
                    utilities.Debug("doMarkWatched(): %s" % str(params))

                    if not simulate:
                        result = globals.traktapi.updateSeenMovie(params)
                        if result:
                            if markedNotification:
                                utilities.notification(
                                    utilities.getString(1550), s)
                        else:
                            utilities.notification(utilities.getString(1551),
                                                   s)
                    else:
                        if markedNotification:
                            utilities.notification(utilities.getString(1550),
                                                   s)

        elif utilities.isEpisode(media_type):
            summaryInfo = globals.traktapi.getEpisodeSummary(
                data['id'], data['season'], data['episode'])
            if summaryInfo:
                if not summaryInfo['episode']['watched']:
                    s = utilities.getFormattedItemName(media_type, summaryInfo)
                    utilities.Debug(
                        "doMarkWathced(): '%s' is not watched on trakt, marking it as watched."
                        % s)
                    params = {}
                    params['imdb_id'] = summaryInfo['show']['imdb_id']
                    params['tvdb_id'] = summaryInfo['show']['tvdb_id']
                    params['title'] = summaryInfo['show']['title']
                    params['year'] = summaryInfo['show']['year']
                    params['episodes'] = [{
                        'season': data['season'],
                        'episode': data['episode']
                    }]
                    utilities.Debug("doMarkWatched(): %s" % str(params))

                    if not simulate:
                        result = globals.traktapi.updateSeenEpisode(params)
                        if result:
                            if markedNotification:
                                utilities.notification(
                                    utilities.getString(1550), s)
                        else:
                            utilities.notification(utilities.getString(1551),
                                                   s)
                    else:
                        if markedNotification:
                            utilities.notification(utilities.getString(1550),
                                                   s)

        elif utilities.isSeason(media_type):
            showInfo = globals.traktapi.getShowSummary(data['id'])
            if not showInfo:
                return
            summaryInfo = globals.traktapi.getSeasonInfo(
                data['id'], data['season'])
            if summaryInfo:
                showInfo['season'] = data['season']
                s = utilities.getFormattedItemName(media_type, showInfo)
                params = {}
                params['imdb_id'] = showInfo['imdb_id']
                params['tvdb_id'] = showInfo['tvdb_id']
                params['title'] = showInfo['title']
                params['year'] = showInfo['year']
                params['episodes'] = []
                for ep in summaryInfo:
                    if ep['episode'] in data['episodes']:
                        if not ep['watched']:
                            params['episodes'].append({
                                'season': ep['season'],
                                'episode': ep['episode']
                            })

                utilities.Debug(
                    "doMarkWatched(): '%s - Season %d' has %d episode(s) that are going to be marked as watched."
                    % (showInfo['title'], data['season'],
                       len(params['episodes'])))

                if len(params['episodes']) > 0:
                    utilities.Debug("doMarkWatched(): %s" % str(params))
                    if not simulate:
                        result = globals.traktapi.updateSeenEpisode(params)
                        if result:
                            if markedNotification:
                                utilities.notification(
                                    utilities.getString(1550),
                                    utilities.getString(1552) %
                                    (len(params['episodes']), s))
                        else:
                            utilities.notification(
                                utilities.getString(1551),
                                utilities.getString(1552) %
                                (len(params['episodes']), s))
                    else:
                        if markedNotification:
                            utilities.notification(
                                utilities.getString(1550),
                                utilities.getString(1552) %
                                (len(params['episodes']), s))

        elif utilities.isShow(media_type):
            summaryInfo = globals.traktapi.getShowSummary(data['id'],
                                                          extended=True)
            if summaryInfo:
                s = utilities.getFormattedItemName(media_type, summaryInfo)
                params = {}
                params['imdb_id'] = summaryInfo['imdb_id']
                params['tvdb_id'] = summaryInfo['tvdb_id']
                params['title'] = summaryInfo['title']
                params['year'] = summaryInfo['year']
                params['episodes'] = []
                for season in summaryInfo['seasons']:
                    for ep in season['episodes']:
                        if str(season['season']) in data['seasons']:
                            if ep['episode'] in data['seasons'][str(
                                    season['season'])]:
                                if not ep['watched']:
                                    params['episodes'].append({
                                        'season':
                                        ep['season'],
                                        'episode':
                                        ep['episode']
                                    })
                utilities.Debug(
                    "doMarkWatched(): '%s' has %d episode(s) that are going to be marked as watched."
                    % (summaryInfo['title'], len(params['episodes'])))

                if len(params['episodes']) > 0:
                    utilities.Debug("doMarkWatched(): %s" % str(params))
                    if not simulate:
                        result = globals.traktapi.updateSeenEpisode(params)
                        if result:
                            if markedNotification:
                                utilities.notification(
                                    utilities.getString(1550),
                                    utilities.getString(1552) %
                                    (len(params['episodes']), s))
                        else:
                            utilities.notification(
                                utilities.getString(1551),
                                utilities.getString(1552) %
                                (len(params['episodes']), s))
                    else:
                        if markedNotification:
                            utilities.notification(
                                utilities.getString(1550),
                                utilities.getString(1552) %
                                (len(params['episodes']), s))

    def doSync(self, manual=False):
        self.syncThread = syncThread(manual)
        self.syncThread.start()
예제 #34
0
class NotificationService(threading.Thread):
    """ Receives XBMC notifications and passes them off as needed """

    TELNET_ADDRESS = 'localhost'
    TELNET_PORT = 9090

    _abortRequested = False
    _scrobbler = None
    _notificationBuffer = ""

    def _forward(self, notification):
        """ Fowards the notification recieved to a function on the scrobbler """
        if not ('method' in notification and 'params' in notification
                and 'sender' in notification['params']
                and notification['params']['sender'] == 'xbmc'):
            return

        if notification['method'] == 'Player.OnStop':
            self._scrobbler.playbackEnded()
        elif notification['method'] == 'Player.OnPlay':
            if 'data' in notification['params'] and 'item' in notification[
                    'params']['data'] and 'type' in notification['params'][
                        'data']['item']:
                self._scrobbler.playbackStarted(notification['params']['data'])
        elif notification['method'] == 'Player.OnPause':
            self._scrobbler.playbackPaused()
        elif notification['method'] == 'VideoLibrary.OnScanFinished':
            if do_sync('movies'):
                movies = SyncMovies(show_progress=False)
                movies.Run()
            if do_sync('episodes'):
                episodes = SyncEpisodes(show_progress=False)
                episodes.Run()
        elif notification['method'] == 'System.OnQuit':
            self._abortRequested = True

    def _readNotification(self, telnet):
        """ Read a notification from the telnet connection, blocks until the data is available, or else raises an EOFError if the connection is lost """
        while True:
            try:
                addbuffer = telnet.read_some()
            except socket.timeout:
                continue

            if addbuffer == "":
                raise EOFError

            self._notificationBuffer += addbuffer
            try:
                data, offset = json.JSONDecoder().raw_decode(
                    self._notificationBuffer)
                self._notificationBuffer = self._notificationBuffer[offset:]
            except ValueError:
                continue

            return data

    def run(self):
        #while xbmc is running
        self._scrobbler = Scrobbler()
        self._scrobbler.start()
        while not (self._abortRequested or xbmc.abortRequested):
            try:
                #try to connect, catch errors and retry every 5 seconds
                telnet = telnetlib.Telnet(self.TELNET_ADDRESS,
                                          self.TELNET_PORT)

                #if connection succeeds
                while not (self._abortRequested or xbmc.abortRequested):
                    try:
                        #read notification data
                        data = self._readNotification(telnet)
                        Debug("[Notification Service] message: " + str(data))
                        self._forward(data)
                    except EOFError:
                        #if we end up here, it means the connection was lost or reset,
                        # so we empty out the buffer, and exit this loop, which retries
                        # the connection in the outer loop
                        self._notificationBuffer = ""
                        break
            except:
                time.sleep(5)
                continue

        telnet.close()
        self._scrobbler.abortRequested = True
        Debug("Notification service stopping")
예제 #35
0
class traktService:

	scrobbler = None
	watcher = None
	syncThread = None
	dispatchQueue = Queue.Queue()
	_interval = 10 * 60 # how often to send watching call
	
	def __init__(self):
		threading.Thread.name = 'trakt'

	def _dispatchQueue(self, data):
		utilities.Debug("Queuing for dispatch: %s" % data)
		self.dispatchQueue.put(data)
	
	def _dispatch(self, data):
		utilities.Debug("Dispatch: %s" % data)
		action = data['action']
		if action == 'started':
			del data['action']
			self.scrobbler.playbackStarted(data)
			self.watcher = threading.Timer(self._interval, self.doWatching)
			self.watcher.name = "trakt-watching"
			self.watcher.start()
		elif action == 'ended' or action == 'stopped':
			self.scrobbler.playbackEnded()
			if self.watcher:
				if self.watcher.isAlive():
					self.watcher.cancel()
					self.watcher = None
		elif action == 'paused':
			self.scrobbler.playbackPaused()
		elif action == 'resumed':
			self.scrobbler.playbackResumed()
		elif action == 'seek' or action == 'seekchapter':
			self.scrobbler.playbackSeek()
		elif action == 'databaseUpdated':
			self.doSync()
		elif action == 'scanStarted':
			pass
		elif action == 'settingsChanged':
			utilities.Debug("Settings changed, reloading.")
			globals.traktapi.updateSettings()
		else:
			utilities.Debug("Unknown dispatch action, '%s'." % action)

	def run(self):
		startup_delay = utilities.getSettingAsInt('startup_delay')
		if startup_delay:
			utilities.Debug("Delaying startup by %d seconds." % startup_delay)
			xbmc.sleep(startup_delay * 1000)

		utilities.Debug("Service thread starting.")
		
		# setup event driven classes
		self.Player = traktPlayer(action = self._dispatchQueue)
		self.Monitor = traktMonitor(action = self._dispatchQueue)

		# init traktapi class
		globals.traktapi = traktAPI()

		# init sync thread
		self.syncThread = syncThread()

		# init scrobbler class
		self.scrobbler = Scrobbler(globals.traktapi)

		# start loop for events
		while (not xbmc.abortRequested):
			while not self.dispatchQueue.empty() and (not xbmc.abortRequested):
				data = self.dispatchQueue.get()
				utilities.Debug("Queued dispatch: %s" % data)
				self._dispatch(data)

			# check if we were tasked to do a manual sync
			if utilities.getPropertyAsBool('traktManualSync'):
				if not self.syncThread.isAlive():
					utilities.Debug("Performing a manual sync.")
					self.doSync(manual=True)
				else:
					utilities.Debug("There already is a sync in progress.")

				utilities.clearProperty('traktManualSync')

			if xbmc.Player().isPlayingVideo():
				self.scrobbler.update()

			xbmc.sleep(500)

		# we are shutting down
		utilities.Debug("Beginning shut down.")

		# check if watcher is set and active, if so, cancel it.
		if self.watcher:
			if self.watcher.isAlive():
				self.watcher.cancel()

		# delete player/monitor
		del self.Player
		del self.Monitor

		# check if sync thread is running, if so, join it.
		if self.syncThread.isAlive():
			self.syncThread.join()

	def doWatching(self):
		# check if we're still playing a video
		if not xbmc.Player().isPlayingVideo():
			self.watcher = None
			return

		# call watching method
		self.scrobbler.watching()

		# start a new timer thread
		self.watcher = threading.Timer(self._interval, self.doWatching)
		self.watcher.name = "trakt-watching"
		self.watcher.start()

	def doSync(self, manual=False):
		self.syncThread = syncThread(manual)
		self.syncThread.start()
예제 #36
0
class traktService:

	scrobbler = None
	tagger = None
	updateTagsThread = None
	watcher = None
	syncThread = None
	dispatchQueue = queue.SqliteQueue()
	_interval = 10 * 60 # how often to send watching call
	
	def __init__(self):
		threading.Thread.name = 'trakt'

	def _dispatchQueue(self, data):
		utilities.Debug("Queuing for dispatch: %s" % data)
		self.dispatchQueue.append(data)
	
	def _dispatch(self, data):
		utilities.Debug("Dispatch: %s" % data)
		action = data['action']
		if action == 'started':
			del data['action']
			self.scrobbler.playbackStarted(data)
			self.watcher = threading.Timer(self._interval, self.doWatching)
			self.watcher.name = "trakt-watching"
			self.watcher.start()
		elif action == 'ended' or action == 'stopped':
			self.scrobbler.playbackEnded()
			if self.watcher:
				if self.watcher.isAlive():
					self.watcher.cancel()
					self.watcher = None
		elif action == 'paused':
			self.scrobbler.playbackPaused()
		elif action == 'resumed':
			self.scrobbler.playbackResumed()
		elif action == 'seek' or action == 'seekchapter':
			self.scrobbler.playbackSeek()
		elif action == 'databaseUpdated':
			self.doSync()
		elif action == 'scanStarted':
			pass
		elif action == 'settingsChanged':
			utilities.Debug("Settings changed, reloading.")
			globals.traktapi.updateSettings()
			self.tagger.updateSettings()
		elif action == 'markWatched':
			del data['action']
			self.doMarkWatched(data)
		elif action == 'manualRating':
			ratingData = data['ratingData']
			self.doManualRating(ratingData)
		elif action == 'manualSync':
			if not self.syncThread.isAlive():
				utilities.Debug("Performing a manual sync.")
				self.doSync(manual=True, silent=data['silent'])
			else:
				utilities.Debug("There already is a sync in progress.")
		elif action == 'updatetags':
			if self.updateTagsThread and self.updateTagsThread.isAlive():
				utilities.Debug("Currently updating tags already.")
			else:
				self.updateTagsThread = threading.Thread(target=self.tagger.updateTagsFromTrakt, name="trakt-updatetags")
				self.updateTagsThread.start()
		elif action == 'managelists':
			self.tagger.manageLists()
		elif action == 'itemlists':
			del data['action']
			self.tagger.itemLists(data)
		elif action == 'addtolist':
			del data['action']
			list = data['list']
			del data['list']
			self.tagger.manualAddToList(list, data)
		elif action == 'removefromlist':
			del data['action']
			list = data['list']
			del data['list']
			self.tagger.manualRemoveFromList(list, data)
		elif action == 'loadsettings':
			force = False
			if 'force' in data:
				force = data['force']
			globals.traktapi.getAccountSettings(force)
		else:
			utilities.Debug("Unknown dispatch action, '%s'." % action)

	def run(self):
		startup_delay = utilities.getSettingAsInt('startup_delay')
		if startup_delay:
			utilities.Debug("Delaying startup by %d seconds." % startup_delay)
			xbmc.sleep(startup_delay * 1000)

		utilities.Debug("Service thread starting.")

		# purge queue before doing anything
		self.dispatchQueue.purge()

		# queue a loadsettings action
		self.dispatchQueue.append({'action': 'loadsettings'})

		# setup event driven classes
		self.Player = traktPlayer(action = self._dispatchQueue)
		self.Monitor = traktMonitor(action = self._dispatchQueue)

		# init traktapi class
		globals.traktapi = traktAPI()

		# init sync thread
		self.syncThread = syncThread()

		# init scrobbler class
		self.scrobbler = Scrobbler(globals.traktapi)

		# init tagging class
		self.tagger = Tagger(globals.traktapi)
		
		# start loop for events
		while (not xbmc.abortRequested):
			while len(self.dispatchQueue) and (not xbmc.abortRequested):
				data = self.dispatchQueue.get()
				utilities.Debug("Queued dispatch: %s" % data)
				self._dispatch(data)

			if xbmc.Player().isPlayingVideo():
				self.scrobbler.update()

			xbmc.sleep(500)

		# we are shutting down
		utilities.Debug("Beginning shut down.")

		# check if watcher is set and active, if so, cancel it.
		if self.watcher:
			if self.watcher.isAlive():
				self.watcher.cancel()

		# delete player/monitor
		del self.Player
		del self.Monitor

		# check update tags thread.
		if self.updateTagsThread and self.updateTagsThread.isAlive():
			self.updateTagsThread.join()

		# check if sync thread is running, if so, join it.
		if self.syncThread.isAlive():
			self.syncThread.join()

	def doWatching(self):
		# check if we're still playing a video
		if not xbmc.Player().isPlayingVideo():
			self.watcher = None
			return

		# call watching method
		self.scrobbler.watching()

		# start a new timer thread
		self.watcher = threading.Timer(self._interval, self.doWatching)
		self.watcher.name = "trakt-watching"
		self.watcher.start()

	def doManualRating(self, data):

		action = data['action']
		media_type = data['media_type']
		summaryInfo = None

		if not utilities.isValidMediaType(media_type):
			utilities.Debug("doManualRating(): Invalid media type '%s' passed for manual %s." % (media_type, action))
			return

		if not data['action'] in ['rate', 'unrate']:
			utilities.Debug("doManualRating(): Unknown action passed.")
			return
			
		if 'dbid' in data:
			utilities.Debug("Getting data for manual %s of library '%s' with ID of '%s'" % (action, media_type, data['dbid']))
		elif 'remoteitd' in data:
			if 'season' in data:
				utilities.Debug("Getting data for manual %s of non-library '%s' S%02dE%02d, with ID of '%s'." % (action, media_type, data['season'], data['episode'], data['remoteid']))
			else:
				utilities.Debug("Getting data for manual %s of non-library '%s' with ID of '%s'" % (action, media_type, data['remoteid']))

		if utilities.isEpisode(media_type):
			summaryInfo = globals.traktapi.getEpisodeSummary(data['tvdb_id'], data['season'], data['episode'])
		elif utilities.isShow(media_type):
			summaryInfo = globals.traktapi.getShowSummary(data['imdbnumber'])
		elif utilities.isMovie(media_type):
			summaryInfo = globals.traktapi.getMovieSummary(data['imdbnumber'])
		
		if not summaryInfo is None:
			if utilities.isMovie(media_type) or utilities.isShow(media_type):
				summaryInfo['xbmc_id'] = data['dbid']

			if action == 'rate':
				if not 'rating' in data:
					rateMedia(media_type, summaryInfo)
				else:
					rateMedia(media_type, summaryInfo, rating=data['rating'])
			elif action == 'unrate':
				rateMedia(media_type, summaryInfo, unrate=True)
		else:
			utilities.Debug("doManualRating(): Summary info was empty, possible problem retrieving data from trakt.tv")

	def doMarkWatched(self, data):

		media_type = data['media_type']
		simulate = utilities.getSettingAsBool('simulate_sync')
		markedNotification = utilities.getSettingAsBool('show_marked_notification')
		
		if utilities.isMovie(media_type):
			summaryInfo = globals.traktapi.getMovieSummary(data['id'])
			if summaryInfo:
				if not summaryInfo['watched']:
					s = utilities.getFormattedItemName(media_type, summaryInfo)
					utilities.Debug("doMarkWatched(): '%s' is not watched on trakt, marking it as watched." % s)
					movie = {}
					movie['imdb_id'] = data['id']
					movie['title'] = summaryInfo['title']
					movie['year'] = summaryInfo['year']
					movie['plays'] = 1
					movie['last_played'] = int(time())
					params = {'movies': [movie]}
					utilities.Debug("doMarkWatched(): %s" % str(params))
					
					if not simulate:
						result = globals.traktapi.updateSeenMovie(params)
						if result:
							if markedNotification:
								utilities.notification(utilities.getString(1550), s)
						else:
							utilities.notification(utilities.getString(1551), s)
					else:
						if markedNotification:
							utilities.notification(utilities.getString(1550), s)
					
		elif utilities.isEpisode(media_type):
			summaryInfo = globals.traktapi.getEpisodeSummary(data['id'], data['season'], data['episode'])
			if summaryInfo:
				if not summaryInfo['episode']['watched']:
					s = utilities.getFormattedItemName(media_type, summaryInfo)
					utilities.Debug("doMarkWathced(): '%s' is not watched on trakt, marking it as watched." % s)
					params = {}
					params['imdb_id'] = summaryInfo['show']['imdb_id']
					params['tvdb_id'] = summaryInfo['show']['tvdb_id']
					params['title'] = summaryInfo['show']['title']
					params['year'] = summaryInfo['show']['year']
					params['episodes'] = [{'season': data['season'], 'episode': data['episode']}]
					utilities.Debug("doMarkWatched(): %s" % str(params))
					
					if not simulate:
						result = globals.traktapi.updateSeenEpisode(params)
						if result:
							if markedNotification:
								utilities.notification(utilities.getString(1550), s)
						else:
							utilities.notification(utilities.getString(1551), s)
					else:
						if markedNotification:
							utilities.notification(utilities.getString(1550), s)

		elif utilities.isSeason(media_type):
			showInfo = globals.traktapi.getShowSummary(data['id'])
			if not showInfo:
				return
			summaryInfo = globals.traktapi.getSeasonInfo(data['id'], data['season'])
			if summaryInfo:
				showInfo['season'] = data['season']
				s = utilities.getFormattedItemName(media_type, showInfo)
				params = {}
				params['imdb_id'] = showInfo['imdb_id']
				params['tvdb_id'] = showInfo['tvdb_id']
				params['title'] = showInfo['title']
				params['year'] = showInfo['year']
				params['episodes'] = []
				for ep in summaryInfo:
					if ep['episode'] in data['episodes']:
						if not ep['watched']:
							params['episodes'].append({'season': ep['season'], 'episode': ep['episode']})

				utilities.Debug("doMarkWatched(): '%s - Season %d' has %d episode(s) that are going to be marked as watched." % (showInfo['title'], data['season'], len(params['episodes'])))
				
				if len(params['episodes']) > 0:
					utilities.Debug("doMarkWatched(): %s" % str(params))
					if not simulate:
						result = globals.traktapi.updateSeenEpisode(params)
						if result:
							if markedNotification:
								utilities.notification(utilities.getString(1550), utilities.getString(1552) % (len(params['episodes']), s))
						else:
							utilities.notification(utilities.getString(1551), utilities.getString(1552) % (len(params['episodes']), s))
					else:
						if markedNotification:
							utilities.notification(utilities.getString(1550), utilities.getString(1552) % (len(params['episodes']), s))

		elif utilities.isShow(media_type):
			summaryInfo = globals.traktapi.getShowSummary(data['id'], extended=True)
			if summaryInfo:
				s = utilities.getFormattedItemName(media_type, summaryInfo)
				params = {}
				params['imdb_id'] = summaryInfo['imdb_id']
				params['tvdb_id'] = summaryInfo['tvdb_id']
				params['title'] = summaryInfo['title']
				params['year'] = summaryInfo['year']
				params['episodes'] = []
				for season in summaryInfo['seasons']:
					for ep in season['episodes']:
						if str(season['season']) in data['seasons']:
							if ep['episode'] in data['seasons'][str(season['season'])]:
								if not ep['watched']:
									params['episodes'].append({'season': ep['season'], 'episode': ep['episode']})
				utilities.Debug("doMarkWatched(): '%s' has %d episode(s) that are going to be marked as watched." % (summaryInfo['title'], len(params['episodes'])))

				if len(params['episodes']) > 0:
					utilities.Debug("doMarkWatched(): %s" % str(params))
					if not simulate:
						result = globals.traktapi.updateSeenEpisode(params)
						if result:
							if markedNotification:
								utilities.notification(utilities.getString(1550), utilities.getString(1552) % (len(params['episodes']), s))
						else:
							utilities.notification(utilities.getString(1551), utilities.getString(1552) % (len(params['episodes']), s))
					else:
						if markedNotification:
							utilities.notification(utilities.getString(1550), utilities.getString(1552) % (len(params['episodes']), s))

	def doSync(self, manual=False, silent=False):
		self.syncThread = syncThread(manual, silent)
		self.syncThread.start()
예제 #37
0
파일: pyfm.py 프로젝트: beanmoon/pyfm
class Doubanfm:
    def __init__(self):
        self._load_config()
        self.douban = Douban(self.email, self.password, self.user_id, self.expire, self.token, self.user_name)
        self.player = Player()
        self.current_channel = 0
        self.current_song = None
        self.current_play_list = None
        self.get_channels()
        
        self.palette = [('selected', 'bold', 'default'),
                        ('title', 'yellow', 'default')]
        self.selected_button = None
        self.main_loop = None
        self.song_change_alarm = None
        
        if self.scrobbling:
            self.scrobbler = Scrobbler(self.last_fm_username, self.last_fm_password)
            r =  self.scrobbler.handshake()
            if r:
                print("Last.FM logged in.")
            else:
                print("Last.FM login failed")
        if self.douban_account:
            r, err = self.douban.do_login()
            if r:
                print("Douban logged in.")
                self._save_cache()
            else:
                print("Douban login failed: " + err)
        
    def _load_config(self):
        self.email = None
        self.password = None
        self.user_id = None
        self.expire = None
        self.token = None
        self.user_name = None
        self.lasf_fm_username = None
        self.last_fm_password = None
        self.scrobbling = True
        self.douban_account = True
        self.channels = None
        
        config = None
        token = None
        try:
            f = open('config.json', 'r')
            config = json.load(f)
            
            self.email = config['email']
            self.password = config['password']
            
        except (KeyError,ValueError):
            self.douban_account = False
            print("Douban account not found. Personal FM disabled.")
        
        try:
            if config == None:
                raise ValueError 
            self.last_fm_username = config['last_fm_username']
            self.last_fm_password = config['last_fm_password']
        except (KeyError,ValueError):
            self.scrobbling = False
            print("Last.fm account not found. Scrobbling disabled.")
            
        try:
            f = open('channels.json', 'r')
            self.channels = json.load(f)
            print("Load channel file.")
        except FileNotFoundError:
            print("Channels file not found.")
         
    def _save_cache(self):
        f = None
        try:
            f = open('cache.json', 'w')
            f2 = open('channels.json', 'w')
            json.dump({
                'user_name': self.douban.user_name,
                'user_id': self.douban.user_id,
                'expire': self.douban.expire,
                'token': self.douban.token
            }, f)
            json.dump(self.channels, f2)
        except IOError:
            raise Exception("Unable to write cache file")
            
    def get_channels(self):
        if self.channels is None:
            self.channels = self.douban.get_channels()
        return self.channels
    
    def _choose_channel(self, channel):
        self.current_channel = channel
        self.current_play_list = deque(self.douban.get_new_play_list(self.current_channel))
        
    def _play_track(self):
        _song = self.current_play_list.popleft()                
        self.current_song = Song(_song)
        self.song_change_alarm = self.main_loop.set_alarm_in(self.current_song.length_in_sec,
                                   self.next_song, None);
        self.selected_button.set_text(self.selected_button.text[0:7].strip())
        heart = u'\N{WHITE HEART SUIT}';
        if self.current_song.like:
            heart = u'\N{BLACK HEART SUIT}'
        self.selected_button.set_text(self.selected_button.text + '                 ' + heart + '  ' +
                                        self.current_song.artist + ' - ' + 
                                        self.current_song.title)
        if self.scrobbling:
            self.scrobbler.now_playing(self.current_song.artist, self.current_song.title,
                                       self.current_song.album_title, self.current_song.length_in_sec)
        
        self.player.stop()
        self.player.play(self.current_song)
        # Currently playing the second last song in queue
        if len(self.current_play_list) == 1:
            playing_list = self.douban.get_playing_list(self.current_song.sid, self.current_channel)
            self.current_play_list.extend(deque(playing_list))
    
    def next_song(self, loop, user_data):
        # Scrobble the track if scrobbling is enabled 
        # and total playback time of the track > 30s
        if self.scrobbling and self.current_song.length_in_sec > 30:
            self.scrobbler.submit(self.current_song.artist, self.current_song.title,
                                  self.current_song.album_title, self.current_song.length_in_sec)
        
        self.douban.end_song(self.current_song.sid, self.current_channel)
        if self.song_change_alarm:
            self.main_loop.remove_alarm(self.song_change_alarm)
        self._play_track()
    
    def skip_current_song(self):
        self.douban.skip_song(self.current_song.sid, self.current_channel)
        if self.song_change_alarm:
            self.main_loop.remove_alarm(self.song_change_alarm)
        self._play_track()
          
    def rate_current_song(self):
        self.douban.rate_song(self.current_song.sid, self.current_channel)
        self.selected_button.set_text(self.selected_button.text.replace(u'\N{WHITE HEART SUIT}', u'\N{BLACK HEART SUIT}'))
        
        
    def unrate_current_song(self):
        self.douban.unrate_song(self.current_song.sid, self.current_channel)
        self.selected_button.set_text(self.selected_button.text.replace(u'\N{BLACK HEART SUIT}', u'\N{WHITE HEART SUIT}'))
        
    def quit(self):
        self.player.stop()
        
    def start(self):
        title = urwid.AttrMap(urwid.Text('豆瓣FM'), 'title')
        divider = urwid.Divider()
        pile = urwid.Padding(urwid.Pile([divider, title, divider]), left=4, right=4)
        box = urwid.Padding(self.ChannelListBox(), left=2, right=4)
        
        frame = urwid.Frame(box, header=pile, footer=divider)
        
        self.main_loop = urwid.MainLoop(frame, self.palette, handle_mouse=False)
        self.main_loop.run()

    def ChannelListBox(self):
        body = []
        for c in self.channels:
                _channel = ChannelButton(c['name'])
                urwid.connect_signal(_channel, 'click', self.channel_chosen, c['channel_id'])
                body.append(urwid.AttrMap(_channel, None, focus_map="channel"))
        return MyListBox(urwid.SimpleFocusListWalker(body), self)

    def channel_chosen(self, button, choice):
        # Choose the channel which is playing right now
        # ignore this
        if self.selected_button == button:
            return
        # Choose a different channel
        if self.player.is_playing:
            self.player.stop()
        self._choose_channel(choice)
        if self.selected_button != None and button != self.selected_button:
            self.selected_button.set_text(self.selected_button.text[0:7].strip())
        self.selected_button = button
        self._play_track()
예제 #38
0
class traktService:

	scrobbler = None
	watcher = None
	syncThread = None
	dispatchQueue = Queue.Queue()
	_interval = 10 * 60 # how often to send watching call
	
	def __init__(self):
		threading.Thread.name = 'trakt'

	def _dispatchQueue(self, data):
		utilities.Debug("Queuing for dispatch: %s" % data)
		self.dispatchQueue.put(data)
	
	def _dispatch(self, data):
		utilities.Debug("Dispatch: %s" % data)
		action = data['action']
		if action == 'started':
			del data['action']
			self.scrobbler.playbackStarted(data)
			self.watcher = threading.Timer(self._interval, self.doWatching)
			self.watcher.name = "trakt-watching"
			self.watcher.start()
		elif action == 'ended' or action == 'stopped':
			self.scrobbler.playbackEnded()
			if self.watcher:
				if self.watcher.isAlive():
					self.watcher.cancel()
					self.watcher = None
		elif action == 'paused':
			self.scrobbler.playbackPaused()
		elif action == 'resumed':
			self.scrobbler.playbackResumed()
		elif action == 'seek' or action == 'seekchapter':
			self.scrobbler.playbackSeek()
		elif action == 'databaseUpdated':
			self.doSync()
		elif action == 'scanStarted':
			pass
		elif action == 'settingsChanged':
			utilities.Debug("Settings changed, reloading.")
			globals.traktapi.updateSettings()
		else:
			utilities.Debug("Unknown dispatch action, '%s'." % action)

	def run(self):
		startup_delay = utilities.getSettingAsInt('startup_delay')
		if startup_delay:
			utilities.Debug("Delaying startup by %d seconds." % startup_delay)
			xbmc.sleep(startup_delay * 1000)

		utilities.Debug("Service thread starting.")

		# clear any left over properties
		utilities.clearProperty('traktManualSync')
		utilities.clearProperty('traktManualRateData')
		utilities.clearProperty('traktManualRate')
		
		# setup event driven classes
		self.Player = traktPlayer(action = self._dispatchQueue)
		self.Monitor = traktMonitor(action = self._dispatchQueue)

		# init traktapi class
		globals.traktapi = traktAPI()

		# init sync thread
		self.syncThread = syncThread()

		# init scrobbler class
		self.scrobbler = Scrobbler(globals.traktapi)

		# start loop for events
		while (not xbmc.abortRequested):
			while not self.dispatchQueue.empty() and (not xbmc.abortRequested):
				data = self.dispatchQueue.get()
				utilities.Debug("Queued dispatch: %s" % data)
				self._dispatch(data)

			# check if we were tasked to do a manual sync
			if utilities.getPropertyAsBool('traktManualSync'):
				if not self.syncThread.isAlive():
					utilities.Debug("Performing a manual sync.")
					self.doSync(manual=True)
				else:
					utilities.Debug("There already is a sync in progress.")

				utilities.clearProperty('traktManualSync')

			# check if we were tasked to do a manual rating
			if utilities.getPropertyAsBool('traktManualRate'):
				self.doManualRating()
				utilities.clearProperty('traktManualRateData')
				utilities.clearProperty('traktManualRate')
			
			if xbmc.Player().isPlayingVideo():
				self.scrobbler.update()

			xbmc.sleep(500)

		# we are shutting down
		utilities.Debug("Beginning shut down.")

		# check if watcher is set and active, if so, cancel it.
		if self.watcher:
			if self.watcher.isAlive():
				self.watcher.cancel()

		# delete player/monitor
		del self.Player
		del self.Monitor

		# check if sync thread is running, if so, join it.
		if self.syncThread.isAlive():
			self.syncThread.join()

	def doWatching(self):
		# check if we're still playing a video
		if not xbmc.Player().isPlayingVideo():
			self.watcher = None
			return

		# call watching method
		self.scrobbler.watching()

		# start a new timer thread
		self.watcher = threading.Timer(self._interval, self.doWatching)
		self.watcher.name = "trakt-watching"
		self.watcher.start()

	def doManualRating(self):
		data = json.loads(utilities.getProperty('traktManualRateData'))

		action = data['action']
		media_type = data['media_type']
		summaryInfo = None

		if not utilities.isValidMediaType(media_type):
			utilities.Debug("doManualRating(): Invalid media type '%s' passed for manual %s." % (media_type, action))
			return

		if not data['action'] in ['rate', 'unrate']:
			utilities.Debug("doManualRating(): Unknown action passed.")
			return
			
		if 'dbid' in data:
			utilities.Debug("Getting data for manual %s of library '%s' with ID of '%s'" % (action, media_type, data['dbid']))
		elif 'remoteitd' in data:
			if 'season' in data:
				utilities.Debug("Getting data for manual %s of non-library '%s' S%02dE%02d, with ID of '%s'." % (action, media_type, data['season'], data['episode'], data['remoteid']))
			else:
				utilities.Debug("Getting data for manual %s of non-library '%s' with ID of '%s'" % (action, media_type, data['remoteid']))

		if utilities.isEpisode(media_type):
			result = {}
			if 'dbid' in data:
				result = utilities.getEpisodeDetailsFromXbmc(data['dbid'], ['showtitle', 'season', 'episode', 'tvshowid'])
				if not result:
					utilities.Debug("doManualRating(): No data was returned from XBMC, aborting manual %s." % action)
					return
			else:
				result['tvdb_id'] = data['remoteid']
				result['season'] = data['season']
				result['episode'] = data['episode']

			summaryInfo = globals.traktapi.getEpisodeSummary(result['tvdb_id'], result['season'], result['episode'])
		elif utilities.isShow(media_type):
			result = {}
			if 'dbid' in data:
				result = utilities.getShowDetailsFromXBMC(data['dbid'], ['imdbnumber'])
				if not result:
					utilities.Debug("doManualRating(): No data was returned from XBMC, aborting manual %s." % action)
					return
			else:
				result['imdbnumber'] = data['remoteid']

			summaryInfo = globals.traktapi.getShowSummary(result['imdbnumber'])
		elif utilities.isMovie(media_type):
			result = {}
			if 'dbid' in data:
				result = utilities.getMovieDetailsFromXbmc(data['dbid'], ['imdbnumber', 'title', 'year'])
				if not result:
					utilities.Debug("doManualRating(): No data was returned from XBMC, aborting manual %s." % action)
					return
			else:
				result['imdbnumber'] = data['remoteid']

			summaryInfo = globals.traktapi.getMovieSummary(result['imdbnumber'])
		
		if not summaryInfo is None:
			if action == 'rate':
				if not 'rating' in data:
					rateMedia(media_type, summaryInfo)
				else:
					rateMedia(media_type, summaryInfo, rating=data['rating'])
			elif action == 'unrate':
				rateMedia(media_type, summaryInfo, unrate=True)
		else:
			utilities.Debug("doManualRating(): Summary info was empty, possible problem retrieving data from trakt.tv")

	def doSync(self, manual=False):
		self.syncThread = syncThread(manual)
		self.syncThread.start()
예제 #39
0
파일: graph.py 프로젝트: nicwest/famepoints
from pylab import *


if __name__ == "__main__":
    limits = {
        'NA': (3000, 'orange', 'North America'),
        'EU': (10000, 'blue', 'Europe'),
        'RU': (30000, 'red', 'Russia'),
        'ASIA': (1000, 'green', 'Asia'),
        'KR': (500, 'purple', 'Korea'),
    }
    rc('font', **{'family':'serif'})
    for server in ['EU', 'NA', 'RU', 'ASIA', 'KR']:
        print server
        # scrob = Scrobbler(min_points=5000, max_pages=90, max_rank=90000, max_players=90000)
        scrob = Scrobbler(min_points=5000, max_pages=90, max_rank=90000, max_players=90000)
        scrob.page_size = 1000
        scrob.build_headers(server)
        try:
            data = scrob.scrobble()

            x = []
            y = []

            for player in scrob.ranking:
                x.append(scrob.players[player[0]]['real_position'])
                y.append(player[1])

                if scrob.players[player[0]]['real_position'] == limits[server][0]:
                    cutoffx = [limits[server][0], limits[server][0]]
                    cutoffy = [0, player[1]]
예제 #40
0
class Doubanfm(object):
    def __init__(self):
        self.login_data = {}
        self.lastfm = True  # lastfm 登陆

    def init_login(self):
        print LOGO
        self.douban_login()  # 登陆
        self.lastfm_login()  # 登陆 last.fm
        print '\033[31m♥\033[0m Get channels ',
        self.get_channels()  # 获取频道列表
        print '[\033[32m OK \033[0m]'
        # 存储的default_channel是行数而不是真正发送数据的channel_id
        # 这里需要进行转化一下
        self.set_channel(self.default_channel)
        print '\033[31m♥\033[0m Check PRO ',
        # self.is_pro()
        print '[\033[32m OK \033[0m]'

    def win_login(self):
        '''登陆界面'''
        email = raw_input('Email: ')
        password = getpass.getpass('Password: '******'''Last.fm登陆'''
        # username & password
        self.last_fm_username = \
            self.login_data['last_fm_username'] if 'last_fm_username' in self.login_data\
            else None
        self.last_fm_password = \
            self.login_data['last_fm_password'] if 'last_fm_password' in self.login_data\
            else None
        if len(sys.argv) > 1 and sys.argv[1] == 'last.fm':
            from hashlib import md5
            username = raw_input('Last.fm username: '******'Last.fm password :'******'r') as f:
                data = pickle.load(f)
            with open(config.PATH_TOKEN, 'w') as f:
                data['last_fm_username'] = username
                data['last_fm_password'] = self.last_fm_password
                pickle.dump(data, f)

        # login
        if self.lastfm and self.last_fm_username and self.last_fm_password:
            self.scrobbler = Scrobbler(
                self.last_fm_username, self.last_fm_password)
            r, err = self.scrobbler.handshake()
            if r:
                logger.info("Last.fm login succeeds!")
                print '\033[31m♥\033[0m Last.fm logged in: %s' % self.last_fm_username
            else:
                logger.error("Last.fm login fails: " + err)
                self.lastfm = False
        else:
            self.lastfm = False

    def __last_fm_account_required(func):
        '''装饰器,用于需要登录Last.fm后才能使用的接口'''
        @wraps(func)
        def wrapper(self, *args, **kwds):
            if not self.lastfm:
                return
            # Disable pylint callable check due to pylint's incompability
            # with using a class method as decorator.
            # Pylint will consider func as "self"
            return func(self, *args, **kwds)    # pylint: disable=not-callable
        return wrapper

    @__last_fm_account_required
    def submit_current_song(self):
        '''提交播放过的曲目'''
        # Submit the track if total playback time of the track > 30s
        if self.playingsong['length'] > 30:
            self.scrobbler.submit(
                self.playingsong['artist'],
                self.playingsong['title'],
                self.playingsong['albumtitle'],
                self.playingsong['length']
            )

    @__last_fm_account_required
    def scrobble_now_playing(self):
        '''提交当前正在播放曲目'''
        self.scrobbler.now_playing(
            self.playingsong['artist'],
            self.playingsong['title'],
            self.playingsong['albumtitle'],
            self.playingsong['length']
        )

    def douban_login(self):
        '''登陆douban.fm获取token'''
        if os.path.exists(config.PATH_TOKEN):
            # 已登陆
            logger.info("Found existing Douban.fm token.")
            with open(config.PATH_TOKEN, 'r') as f:
                self.login_data = pickle.load(f)
                self.token = self.login_data['token']
                self.user_name = self.login_data['user_name']
                self.user_id = self.login_data['user_id']
                self.expire = self.login_data['expire']
                self.default_volume = int(self.login_data['volume'])\
                    if 'volume' in self.login_data else 50
                # Value stored in login_data in token file is lien number
                # instead of channel_id! Will do set_channel later.
                self.default_channel = int(self.login_data['channel'])\
                    if 'channel' in self.login_data else 0
            print '\033[31m♥\033[0m Get local token - Username: \033[33m%s\033[0m' %\
                self.user_name
        else:
            # 未登陆
            logger.info('First time logging in Douban.fm.')
            while True:
                self.email, self.password = self.win_login()
                login_data = {
                    'app_name': 'radio_desktop_win',
                    'version': '100',
                    'email': self.email,
                    'password': self.password
                }
                s = requests.post('http://www.douban.com/j/app/login', login_data)
                dic = json.loads(s.text, object_hook=_decode_dict)
                if dic['r'] == 1:
                    logger.debug(dic['err'])
                    continue
                else:
                    self.token = dic['token']
                    self.user_name = dic['user_name']
                    self.user_id = dic['user_id']
                    self.expire = dic['expire']
                    self.default_volume = 50
                    self.default_channel = 1
                    self.login_data = {
                        'app_name': 'radio_desktop_win',
                        'version': '100',
                        'user_id': self.user_id,
                        'expire': self.expire,
                        'token': self.token,
                        'user_name': self.user_name,
                        'volume': '50',
                        'channel': '0'
                    }
                    logger.info('Logged in username: '******'w') as f:
                        pickle.dump(self.login_data, f)
                        logger.debug('Write data to ' + config.PATH_TOKEN)
                    break
        # set config
        config.init_config()

    def get_channels(self):
        '''获取channel列表,将channel name/id存入self._channel_list'''
        # 红心兆赫需要手动添加
        self._channel_list = [{
            'name': '红心兆赫',
            'channel_id': -3
        }]
        r = requests.get('http://www.douban.com/j/app/radio/channels')
        self._channel_list += json.loads(r.text, object_hook=_decode_dict)['channels']

    @property
    def channels(self):
        '''返回channel名称列表(一个list,不包括id)'''
        # 格式化频道列表,以便display
        lines = [ch['name'] for ch in self._channel_list]
        return lines

    def requests_url(self, ptype, **data):
        '''这里包装了一个函数,发送post_data'''
        post_data = self.login_data.copy()
        post_data['type'] = ptype
        for x in data:
            post_data[x] = data[x]
        url = 'http://www.douban.com/j/app/radio/people?' + urllib.urlencode(post_data)
        try:
            s = requests.get(url)
        except requests.exceptions.RequestException:
            logger.error("Error communicating with Douban.fm API.")

        return s.text

    def set_channel(self, line):
        '''把行数转化成channel_id'''
        self.default_channel = line
        self.login_data['channel'] = self._channel_list[line]['channel_id']

    def get_playlist(self):
        '''获取播放列表,返回一个list'''
        s = self.requests_url('n')
        return json.loads(s, object_hook=_decode_dict)['song']

    def skip_song(self, playingsong):
        '''下一首,返回一个list'''
        s = self.requests_url('s', sid=playingsong['sid'])
        return json.loads(s, object_hook=_decode_dict)['song']

    def bye(self, playingsong):
        '''不再播放,返回一个list'''
        s = self.requests_url('b', sid=playingsong['sid'])
        return json.loads(s, object_hook=_decode_dict)['song']

    def rate_music(self, playingsong):
        '''标记喜欢歌曲'''
        self.requests_url('r', sid=playingsong['sid'])

    def unrate_music(self, playingsong):
        '''取消标记喜欢歌曲'''
        self.requests_url('u', sid=playingsong['sid'])

    def submit_music(self, playingsong):
        '''歌曲结束标记'''
        self.requests_url('e', sid=playingsong['sid'])

    def get_lrc(self, playingsong):
        '''获取歌词'''
        try:
            url = "http://api.douban.com/v2/fm/lyric"
            postdata = {
                'sid': playingsong['sid'],
                'ssid': playingsong['ssid'],
            }
            s = requests.session()
            response = s.post(url, data=postdata)
            lyric = json.loads(response.text, object_hook=_decode_dict)
            logger.debug(response.text)
            lrc_dic = lrc2dic.lrc2dict(lyric['lyric'])
            # 原歌词用的unicode,为了兼容
            for key, value in lrc_dic.iteritems():
                lrc_dic[key] = value.decode('utf-8')
            if lrc_dic:
                logger.debug('Get lyric success!')
            return lrc_dic
        except requests.exceptions.RequestException:
            logger.error('Get lyric failed!')
            return {}
예제 #41
0
class traktService:
    scrobbler = None
    updateTagsThread = None
    syncThread = None
    dispatchQueue = sqlitequeue.SqliteQueue()

    def __init__(self):
        threading.Thread.name = 'trakt'

    def _dispatchQueue(self, data):
        logger.debug("Queuing for dispatch: %s" % data)
        self.dispatchQueue.append(data)

    def _dispatch(self, data):
        try:
            logger.debug("Dispatch: %s" % data)
            action = data['action']
            if action == 'started':
                del data['action']
                self.scrobbler.playbackStarted(data)
            elif action == 'ended' or action == 'stopped':
                self.scrobbler.playbackEnded()
            elif action == 'paused':
                self.scrobbler.playbackPaused()
            elif action == 'resumed':
                self.scrobbler.playbackResumed()
            elif action == 'seek' or action == 'seekchapter':
                self.scrobbler.playbackSeek()
            elif action == 'scanFinished':
                if utilities.getSettingAsBool('sync_on_update'):
                    logger.debug("Performing sync after library update.")
                    self.doSync()
            elif action == 'databaseCleaned':
                if utilities.getSettingAsBool('sync_on_update') and (
                        utilities.getSettingAsBool('clean_trakt_movies')
                        or utilities.getSettingAsBool('clean_trakt_episodes')):
                    logger.debug("Performing sync after library clean.")
                    self.doSync()
            elif action == 'settingsChanged':
                logger.debug("Settings changed, reloading.")
                globals.traktapi.updateSettings()
            elif action == 'markWatched':
                del data['action']
                self.doMarkWatched(data)
            elif action == 'manualRating':
                ratingData = data['ratingData']
                self.doManualRating(ratingData)
            elif action == 'addtowatchlist':  # add to watchlist
                del data['action']
                self.doAddToWatchlist(data)
            elif action == 'manualSync':
                if not self.syncThread.isAlive():
                    logger.debug("Performing a manual sync.")
                    self.doSync(manual=True,
                                silent=data['silent'],
                                library=data['library'])
                else:
                    logger.debug("There already is a sync in progress.")
            elif action == 'settings':
                utilities.showSettings()
            else:
                logger.debug("Unknown dispatch action, '%s'." % action)
        except Exception as ex:
            message = utilities.createError(ex)
            logger.fatal(message)

    def run(self):
        startup_delay = utilities.getSettingAsInt('startup_delay')
        if startup_delay:
            logger.debug("Delaying startup by %d seconds." % startup_delay)
            xbmc.sleep(startup_delay * 1000)

        logger.debug("Service thread starting.")

        # purge queue before doing anything
        self.dispatchQueue.purge()

        # setup event driven classes
        self.Player = traktPlayer(action=self._dispatchQueue)
        self.Monitor = traktMonitor(action=self._dispatchQueue)

        # init traktapi class
        globals.traktapi = traktAPI()

        # init sync thread
        self.syncThread = syncThread()

        # init scrobbler class
        self.scrobbler = Scrobbler(globals.traktapi)

        # start loop for events
        while not self.Monitor.abortRequested():
            if not utilities.getSetting('authorization'):
                last_reminder = utilities.getSettingAsInt('last_reminder')
                now = int(time.time())
                if last_reminder >= 0 and last_reminder < now - (24 * 60 * 60):
                    gui_utils.get_pin()

            while len(self.dispatchQueue) and (
                    not self.Monitor.abortRequested()):
                data = self.dispatchQueue.get()
                logger.debug("Queued dispatch: %s" % data)
                self._dispatch(data)

            if xbmc.Player().isPlayingVideo():
                self.scrobbler.transitionCheck()

            if self.Monitor.waitForAbort(1):
                # Abort was requested while waiting. We should exit
                break

        # we are shutting down
        logger.debug("Beginning shut down.")

        # delete player/monitor
        del self.Player
        del self.Monitor

        # check if sync thread is running, if so, join it.
        if self.syncThread.isAlive():
            self.syncThread.join()

    def doManualRating(self, data):
        action = data['action']
        media_type = data['media_type']
        summaryInfo = None

        if not utilities.isValidMediaType(media_type):
            logger.debug(
                "doManualRating(): Invalid media type '%s' passed for manual %s."
                % (media_type, action))
            return

        if not data['action'] in ['rate', 'unrate']:
            logger.debug("doManualRating(): Unknown action passed.")
            return

        logger.debug(
            "Getting data for manual %s of %s: video_id: |%s| dbid: |%s|" %
            (action, media_type, data.get('video_id'), data.get('dbid')))

        id_type = utilities.parseIdToTraktIds(str(data['video_id']),
                                              media_type)[1]

        if not id_type:
            logger.debug("doManualRating(): Unrecognized id_type: |%s|-|%s|." %
                         (media_type, data['video_id']))
            return

        ids = globals.traktapi.getIdLookup(data['video_id'], id_type)

        if not ids:
            logger.debug("doManualRating(): No Results for: |%s|-|%s|." %
                         (media_type, data['video_id']))
            return

        trakt_id = dict(ids[0].keys)['trakt']
        if utilities.isEpisode(media_type):
            summaryInfo = globals.traktapi.getEpisodeSummary(
                trakt_id, data['season'], data['episode'])
            userInfo = globals.traktapi.getEpisodeRatingForUser(
                trakt_id, data['season'], data['episode'], 'trakt')
        elif utilities.isSeason(media_type):
            summaryInfo = globals.traktapi.getShowSummary(trakt_id)
            userInfo = globals.traktapi.getSeasonRatingForUser(
                trakt_id, data['season'], 'trakt')
        elif utilities.isShow(media_type):
            summaryInfo = globals.traktapi.getShowSummary(trakt_id)
            userInfo = globals.traktapi.getShowRatingForUser(trakt_id, 'trakt')
        elif utilities.isMovie(media_type):
            summaryInfo = globals.traktapi.getMovieSummary(trakt_id)
            userInfo = globals.traktapi.getMovieRatingForUser(
                trakt_id, 'trakt')

        if summaryInfo is not None:
            summaryInfo = summaryInfo.to_dict()
            summaryInfo['user'] = {'ratings': userInfo}
            if utilities.isEpisode(media_type):
                summaryInfo['season'] = data['season']
                summaryInfo['number'] = data['episode']
                summaryInfo['episodeid'] = data.get('dbid')
            elif utilities.isSeason(media_type):
                summaryInfo['season'] = data['season']
            elif utilities.isMovie(media_type):
                summaryInfo['movieid'] = data.get('dbid')
            elif utilities.isShow(media_type):
                summaryInfo['tvshowid'] = data.get('dbid')

            if action == 'rate':
                if not 'rating' in data:
                    rateMedia(media_type, [summaryInfo])
                else:
                    rateMedia(media_type, [summaryInfo], rating=data['rating'])
        else:
            logger.debug(
                "doManualRating(): Summary info was empty, possible problem retrieving data from Trakt.tv"
            )

    def doAddToWatchlist(self, data):
        media_type = data['media_type']

        if utilities.isMovie(media_type):
            summaryInfo = globals.traktapi.getMovieSummary(
                data['id']).to_dict()
            if summaryInfo:
                s = utilities.getFormattedItemName(media_type, summaryInfo)
                logger.debug(
                    "doAddToWatchlist(): '%s' trying to add to users watchlist."
                    % s)
                params = {'movies': [summaryInfo]}
                logger.debug("doAddToWatchlist(): %s" % str(params))

                result = globals.traktapi.addToWatchlist(params)
                if result:
                    utilities.notification(utilities.getString(32165), s)
                else:
                    utilities.notification(utilities.getString(32166), s)
        elif utilities.isEpisode(media_type):
            summaryInfo = {
                'shows': [{
                    'ids':
                    utilities.parseIdToTraktIds(data['id'], media_type)[0],
                    'seasons': [{
                        'number': data['season'],
                        'episodes': [{
                            'number': data['number']
                        }]
                    }]
                }]
            }
            logger.debug("doAddToWatchlist(): %s" % str(summaryInfo))
            s = utilities.getFormattedItemName(media_type, data)

            result = globals.traktapi.addToWatchlist(summaryInfo)
            if result:
                utilities.notification(utilities.getString(32165), s)
            else:
                utilities.notification(utilities.getString(32166), s)
        elif utilities.isSeason(media_type):
            summaryInfo = {
                'shows': [{
                    'ids':
                    utilities.parseIdToTraktIds(data['id'], media_type)[0],
                    'seasons': [{
                        'number': data['season']
                    }]
                }]
            }
            s = utilities.getFormattedItemName(media_type, data)

            logger.debug(
                "doAddToWatchlist(): '%s - Season %d' trying to add to users watchlist."
                % (data['id'], data['season']))

            result = globals.traktapi.addToWatchlist(summaryInfo)
            if result:
                utilities.notification(utilities.getString(32165), s)
            else:
                utilities.notification(utilities.getString(32166), s)
        elif utilities.isShow(media_type):
            summaryInfo = {
                'shows': [{
                    'ids':
                    utilities.parseIdToTraktIds(data['id'], media_type)[0]
                }]
            }
            s = utilities.getFormattedItemName(media_type, data)
            logger.debug("doAddToWatchlist(): %s" % str(summaryInfo))

            result = globals.traktapi.addToWatchlist(summaryInfo)
            if result:
                utilities.notification(utilities.getString(32165), s)
            else:
                utilities.notification(utilities.getString(32166), s)

    def doMarkWatched(self, data):

        media_type = data['media_type']

        if utilities.isMovie(media_type):
            summaryInfo = globals.traktapi.getMovieSummary(
                data['id']).to_dict()
            if summaryInfo:
                if not summaryInfo['watched']:
                    s = utilities.getFormattedItemName(media_type, summaryInfo)
                    logger.debug(
                        "doMarkWatched(): '%s' is not watched on Trakt, marking it as watched."
                        % s)
                    params = {'movies': [summaryInfo]}
                    logger.debug("doMarkWatched(): %s" % str(params))

                    result = globals.traktapi.addToHistory(params)
                    if result:
                        utilities.notification(utilities.getString(32113), s)
                    else:
                        utilities.notification(utilities.getString(32114), s)
        elif utilities.isEpisode(media_type):
            summaryInfo = {
                'shows': [{
                    'ids':
                    utilities.parseIdToTraktIds(data['id'], media_type)[0],
                    'seasons': [{
                        'number': data['season'],
                        'episodes': [{
                            'number': data['number']
                        }]
                    }]
                }]
            }
            logger.debug("doMarkWatched(): %s" % str(summaryInfo))
            s = utilities.getFormattedItemName(media_type, data)

            result = globals.traktapi.addToHistory(summaryInfo)
            if result:
                utilities.notification(utilities.getString(32113), s)
            else:
                utilities.notification(utilities.getString(32114), s)
        elif utilities.isSeason(media_type):
            summaryInfo = {
                'shows': [{
                    'ids':
                    utilities.parseIdToTraktIds(data['id'], media_type)[0],
                    'seasons': [{
                        'number': data['season'],
                        'episodes': []
                    }]
                }]
            }
            s = utilities.getFormattedItemName(media_type, data)
            for ep in data['episodes']:
                summaryInfo['shows'][0]['seasons'][0]['episodes'].append(
                    {'number': ep})

            logger.debug(
                "doMarkWatched(): '%s - Season %d' has %d episode(s) that are going to be marked as watched."
                % (data['id'], data['season'],
                   len(summaryInfo['shows'][0]['seasons'][0]['episodes'])))

            if len(summaryInfo['shows'][0]['seasons'][0]['episodes']) > 0:
                logger.debug("doMarkWatched(): %s" % str(summaryInfo))

                result = globals.traktapi.addToHistory(summaryInfo)
                if result:
                    utilities.notification(
                        utilities.getString(32113),
                        utilities.getString(32115) %
                        (result['added']['episodes'], s))
                else:
                    utilities.notification(utilities.getString(32114), s)
        elif utilities.isShow(media_type):
            summaryInfo = {
                'shows': [{
                    'ids':
                    utilities.parseIdToTraktIds(data['id'], media_type)[0],
                    'seasons': []
                }]
            }
            if summaryInfo:
                s = utilities.getFormattedItemName(media_type, data)
                logger.debug('data: %s' % data)
                for season in data['seasons']:
                    episodeJson = []
                    for episode in data['seasons'][season]:
                        episodeJson.append({'number': episode})
                    summaryInfo['shows'][0]['seasons'].append({
                        'number':
                        season,
                        'episodes':
                        episodeJson
                    })

                if len(summaryInfo['shows'][0]['seasons'][0]['episodes']) > 0:
                    logger.debug("doMarkWatched(): %s" % str(summaryInfo))

                    result = globals.traktapi.addToHistory(summaryInfo)
                    if result:
                        utilities.notification(
                            utilities.getString(32113),
                            utilities.getString(32115) %
                            (result['added']['episodes'], s))
                    else:
                        utilities.notification(utilities.getString(32114), s)

    def doSync(self, manual=False, silent=False, library="all"):
        self.syncThread = syncThread(manual, silent, library)
        self.syncThread.start()
예제 #42
0
class NotificationService:

	_scrobbler = None
	
	def __init__(self):
		self.run()

	def _dispatch(self, data):
		Debug("[Notification] Dispatch: %s" % data)
		xbmc.sleep(500)
		
		# check if scrobbler thread is still alive
		if not self._scrobbler.isAlive():

			if self.Player._playing and not self._scrobbler.pinging:
				# make sure pinging is set
				self._scrobbler.pinging = True

			Debug("[Notification] Scrobler thread died, restarting.")
			self._scrobbler.start()
		
		action = data["action"]
		if action == "started":
			del data["action"]
			p = {"item": data}
			self._scrobbler.playbackStarted(p)
		elif action == "ended" or action == "stopped":
			self._scrobbler.playbackEnded()
		elif action == "paused":
			self._scrobbler.playbackPaused()
		elif action == "resumed":
			self._scrobbler.playbackResumed()
		elif action == "seek" or action == "seekchapter":
			self._scrobbler.playbackSeek()
		elif action == "databaseUpdated":
			if do_sync('movies'):
				movies = SyncMovies(show_progress=False, api=globals.traktapi)
				movies.Run()
			if do_sync('episodes'):
				episodes = SyncEpisodes(show_progress=False, api=globals.traktapi)
				episodes.Run()
		elif action == "scanStarted":
			pass
		elif action == "settingsChanged":
			Debug("[Notification] Settings changed, reloading.")
			globals.traktapi.updateSettings()
		else:
			Debug("[Notification] '%s' unknown dispatch action!" % action)

	def run(self):
		Debug("[Notification] Starting")
		
		# setup event driven classes
		self.Player = traktPlayer(action = self._dispatch)
		self.Monitor = traktMonitor(action = self._dispatch)
		
		# init traktapi class
		globals.traktapi = traktAPI()

		# initalize scrobbler class
		self._scrobbler = Scrobbler(globals.traktapi)

		# start loop for events
		while (not xbmc.abortRequested):
			xbmc.sleep(500)
			
		# we aborted
		if xbmc.abortRequested:
			Debug("[Notification] abortRequested received, shutting down.")
			
			# delete player/monitor
			del self.Player
			del self.Monitor
			
			# join scrobbler, to wait for termination
			Debug("[Notification] Joining scrobbler thread to wait for exit.")
			self._scrobbler.join()
예제 #43
0
class NotificationService(threading.Thread):
	""" Receives XBMC notifications and passes them off as needed """

	TELNET_ADDRESS = 'localhost'
	TELNET_PORT = 9090

	_abortRequested = False
	_scrobbler = None
	_notificationBuffer = ""


	def _forward(self, notification):
		""" Fowards the notification recieved to a function on the scrobbler """
		if not ('method' in notification and 'params' in notification and 'sender' in notification['params'] and notification['params']['sender'] == 'xbmc'):
			return

		if notification['method'] == 'Player.OnStop':
			self._scrobbler.playbackEnded()
		elif notification['method'] == 'Player.OnPlay':
			if 'data' in notification['params'] and 'item' in notification['params']['data'] and 'type' in notification['params']['data']['item']:
				self._scrobbler.playbackStarted(notification['params']['data'])
		elif notification['method'] == 'Player.OnPause':
			self._scrobbler.playbackPaused()
		elif notification['method'] == 'VideoLibrary.OnScanFinished':
			if do_sync('movies'):
				movies = SyncMovies(show_progress=False)
				movies.Run()
			if do_sync('episodes'):
				episodes = SyncEpisodes(show_progress=False)
				episodes.Run()
		elif notification['method'] == 'System.OnQuit':
			self._abortRequested = True


	def _readNotification(self, telnet):
		""" Read a notification from the telnet connection, blocks until the data is available, or else raises an EOFError if the connection is lost """
		while True:
			try:
				addbuffer = telnet.read_some()
			except socket.timeout:
				continue

			if addbuffer == "":
				raise EOFError

			self._notificationBuffer += addbuffer
			try:
				data, offset = json.JSONDecoder().raw_decode(self._notificationBuffer)
				self._notificationBuffer = self._notificationBuffer[offset:]
			except ValueError:
				continue

			return data


	def run(self):
		#while xbmc is running
		self._scrobbler = Scrobbler()
		self._scrobbler.start()
		while not (self._abortRequested or xbmc.abortRequested):
			try:
				#try to connect, catch errors and retry every 5 seconds
				telnet = telnetlib.Telnet(self.TELNET_ADDRESS, self.TELNET_PORT)
				
				#if connection succeeds
				while not (self._abortRequested or xbmc.abortRequested):
					try:
						#read notification data
						data = self._readNotification(telnet)
						Debug("[Notification Service] message: " + str(data))
						self._forward(data)
					except EOFError:
						#if we end up here, it means the connection was lost or reset,
						# so we empty out the buffer, and exit this loop, which retries
						# the connection in the outer loop
						self._notificationBuffer = ""
						break
			except:
				time.sleep(5)
				continue


		telnet.close()
		self._scrobbler.abortRequested = True
		Debug("Notification service stopping")
예제 #44
0
    def run(self):        
        #while xbmc is running
        scrobbler = Scrobbler()
        scrobbler.start()
        
        while (not (self.abortRequested or xbmc.abortRequested)):
            time.sleep(1)
            try:
                tn = telnetlib.Telnet('localhost', 9090, 10)
            except IOError as (errno, strerror):
                #connection failed, try again soon
                Debug("[Notification Service] Telnet too soon? ("+str(errno)+") "+strerror)
                time.sleep(1)
                continue
            
            Debug("[Notification Service] Waiting~");
            bCount = 0
            
            while (not (self.abortRequested or xbmc.abortRequested)):
                try:
                    if bCount == 0:
                        notification = ""
                        inString = False
                    [index, match, raw] = tn.expect(["(\\\\)|(\\\")|[{\"}]"], 0.2) #note, pre-compiled regex might be faster here
                    notification += raw
                    if index == -1: # Timeout
                        continue
                    if index == 0: # Found escaped quote
                        match = match.group(0)
                        if match == "\"":
                            inString = not inString
                            continue
                        if match == "{":
                            bCount += 1
                        if match == "}":
                            bCount -= 1
                    if bCount > 0:
                        continue
                    if bCount < 0:
                        bCount = 0
                except EOFError:
                    break #go out to the other loop to restart the connection
                
                Debug("[Notification Service] message: " + str(notification))
                
                # Parse recieved notification
                data = json.loads(notification)

                # Forward notification to functions
                if 'method' in data and 'params' in data and 'sender' in data['params'] and data['params']['sender'] == 'xbmc':
                    if data['method'] == 'Player.OnStop':
                        Debug("pb ended, %s" % getSync_after_x())
                        scrobbler.playbackEnded(data=data) # this is using syncIncreasePlayCount already

                    elif data['method'] == 'Player.OnPlay':
                        if 'data' in data['params'] and 'item' in data['params']['data'] and 'id' in data['params']['data']['item'] and 'type' in data['params']['data']['item']:
                            #fixme: look here for current position?
                            scrobbler.playbackStarted(data['params']['data'])
                    elif data['method'] == 'Player.OnPause':
                        scrobbler.playbackPaused()
                    elif data['method'] == 'VideoLibrary.OnUpdate':
                        Debug("OnUpdate %s" % data)
                        if 'data' in data['params'] and 'playcount' in data['params']['data']:
                            noBugging = getNoBugging()
                            # 'playcount' in data indicates that playcount has changed. so we received a seen status on the item
                            if getSync_after_x() and data['params']['data']["playcount"] >= 1:
                                # we've played a file and consider it seen
                                syncIncreasePlayCount()
                                Debug("syncing, playcount: %s" % data['params']['data']["playcount"])
                                syncAfterX(daemon=noBugging)

                            onlyOnUnwatchMark = getInstantOnlyOnUnwatchMark()
                            Debug("instantUpdateOnWatchMark: %s, %s" % (getInstantUpdateOnWatchMark(), onlyOnUnwatchMark))
                            if (getInstantUpdateOnWatchMark() and not onlyOnUnwatchMark) or (data['params']['data']["playcount"] == 0 and onlyOnUnwatchMark):
                                instantSyncPlayCount(data)

                    elif data['method'] == 'System.OnQuit':
                        self.abortRequested = True
예제 #45
0
class traktService:
    scrobbler = None
    updateTagsThread = None
    syncThread = None
    dispatchQueue = sqlitequeue.SqliteQueue()

    def __init__(self):
        threading.Thread.name = 'trakt'

    def _dispatchQueue(self, data):
        logger.debug("Queuing for dispatch: %s" % data)
        self.dispatchQueue.append(data)

    def _dispatch(self, data):
        try:
            logger.debug("Dispatch: %s" % data)
            action = data['action']
            if action == 'started':
                del data['action']
                self.scrobbler.playbackStarted(data)
            elif action == 'ended' or action == 'stopped':
                self.scrobbler.playbackEnded()
            elif action == 'paused':
                self.scrobbler.playbackPaused()
            elif action == 'resumed':
                self.scrobbler.playbackResumed()
            elif action == 'seek' or action == 'seekchapter':
                self.scrobbler.playbackSeek()
            elif action == 'scanFinished':
                if kodiUtilities.getSettingAsBool('sync_on_update'):
                    logger.debug("Performing sync after library update.")
                    self.doSync()
            elif action == 'databaseCleaned':
                if kodiUtilities.getSettingAsBool('sync_on_update') and (kodiUtilities.getSettingAsBool('clean_trakt_movies') or kodiUtilities.getSettingAsBool('clean_trakt_episodes')):
                    logger.debug("Performing sync after library clean.")
                    self.doSync()
            elif action == 'markWatched':
                del data['action']
                self.doMarkWatched(data)
            elif action == 'manualRating':
                ratingData = data['ratingData']
                self.doManualRating(ratingData)
            elif action == 'addtowatchlist':  # add to watchlist
                del data['action']
                self.doAddToWatchlist(data)
            elif action == 'manualSync':
                if not self.syncThread.isAlive():
                    logger.debug("Performing a manual sync.")
                    self.doSync(manual=True, silent=data['silent'], library=data['library'])
                else:
                    logger.debug("There already is a sync in progress.")
            elif action == 'settings':
                kodiUtilities.showSettings()
            elif action == 'auth_info':
                xbmc.executebuiltin('Dialog.Close(all, true)')
                # init traktapi class
                globals.traktapi = traktAPI(True)
            else:
                logger.debug("Unknown dispatch action, '%s'." % action)
        except Exception as ex:
            message = utilities.createError(ex)
            logger.fatal(message)

    def run(self):
        startup_delay = kodiUtilities.getSettingAsInt('startup_delay')
        if startup_delay:
            logger.debug("Delaying startup by %d seconds." % startup_delay)
            xbmc.sleep(startup_delay * 1000)

        logger.debug("Service thread starting.")

        # purge queue before doing anything
        self.dispatchQueue.purge()

        # setup event driven classes
        self.Player = traktPlayer(action=self._dispatchQueue)
        self.Monitor = traktMonitor(action=self._dispatchQueue)

        # init traktapi class
        globals.traktapi = traktAPI()

        # init sync thread
        self.syncThread = syncThread()

        # init scrobbler class
        self.scrobbler = Scrobbler(globals.traktapi)

        AddonSignals.registerSlot('service.nextup.notification', 'NEXTUPWATCHEDSIGNAL', self.callback)

        # start loop for events
        while not self.Monitor.abortRequested():
            while len(self.dispatchQueue) and (not self.Monitor.abortRequested()):
                data = self.dispatchQueue.get()
                logger.debug("Queued dispatch: %s" % data)
                self._dispatch(data)

            if xbmc.Player().isPlayingVideo():
                self.scrobbler.transitionCheck()

            if self.Monitor.waitForAbort(1):
                # Abort was requested while waiting. We should exit
                break

        # we are shutting down
        logger.debug("Beginning shut down.")

        # delete player/monitor
        del self.Player
        del self.Monitor

        # check if sync thread is running, if so, join it.
        if self.syncThread.isAlive():
            self.syncThread.join()

    def doManualRating(self, data):
        action = data['action']
        media_type = data['media_type']
        summaryInfo = None

        if not utilities.isValidMediaType(media_type):
            logger.debug("doManualRating(): Invalid media type '%s' passed for manual %s." % (media_type, action))
            return

        if not data['action'] in ['rate', 'unrate']:
            logger.debug("doManualRating(): Unknown action passed.")
            return

        logger.debug("Getting data for manual %s of %s: video_id: |%s| dbid: |%s|" % (action, media_type, data.get('video_id'), data.get('dbid')))

        id_type = utilities.parseIdToTraktIds(str(data['video_id']), media_type)[1]

        if not id_type:
            logger.debug("doManualRating(): Unrecognized id_type: |%s|-|%s|." % (media_type, data['video_id']))
            return

        ids = globals.traktapi.getIdLookup(data['video_id'], id_type)

        if not ids:
            logger.debug("doManualRating(): No Results for: |%s|-|%s|." % (media_type, data['video_id']))
            return

        trakt_id = dict(ids[0].keys)['trakt']
        if utilities.isEpisode(media_type):
            summaryInfo = globals.traktapi.getEpisodeSummary(trakt_id, data['season'], data['episode'])
            userInfo = globals.traktapi.getEpisodeRatingForUser(trakt_id, data['season'], data['episode'], 'trakt')
        elif utilities.isSeason(media_type):
            summaryInfo = globals.traktapi.getShowSummary(trakt_id)
            userInfo = globals.traktapi.getSeasonRatingForUser(trakt_id, data['season'], 'trakt')
        elif utilities.isShow(media_type):
            summaryInfo = globals.traktapi.getShowSummary(trakt_id)
            userInfo = globals.traktapi.getShowRatingForUser(trakt_id, 'trakt')
        elif utilities.isMovie(media_type):
            summaryInfo = globals.traktapi.getMovieSummary(trakt_id)
            userInfo = globals.traktapi.getMovieRatingForUser(trakt_id, 'trakt')

        if summaryInfo is not None:
            summaryInfo = summaryInfo.to_dict()
            summaryInfo['user'] = {'ratings': userInfo}
            if utilities.isEpisode(media_type):
                summaryInfo['season'] = data['season']
                summaryInfo['number'] = data['episode']
                summaryInfo['episodeid'] = data.get('dbid')
            elif utilities.isSeason(media_type):
                summaryInfo['season'] = data['season']
            elif utilities.isMovie(media_type):
                summaryInfo['movieid'] = data.get('dbid')
            elif utilities.isShow(media_type):
                summaryInfo['tvshowid'] = data.get('dbid')

            if action == 'rate':
                if not 'rating' in data:
                    rateMedia(media_type, [summaryInfo])
                else:
                    rateMedia(media_type, [summaryInfo], rating=data['rating'])
        else:
            logger.debug("doManualRating(): Summary info was empty, possible problem retrieving data from Trakt.tv")

    def doAddToWatchlist(self, data):
        media_type = data['media_type']

        if utilities.isMovie(media_type):
            summaryInfo = globals.traktapi.getMovieSummary(data['id']).to_dict()
            if summaryInfo:
                s = utilities.getFormattedItemName(media_type, summaryInfo)
                logger.debug("doAddToWatchlist(): '%s' trying to add to users watchlist." % s)
                params = {'movies': [summaryInfo]}
                logger.debug("doAddToWatchlist(): %s" % str(params))

                result = globals.traktapi.addToWatchlist(params)
                if result:
                    kodiUtilities.notification(kodiUtilities.getString(32165), s)
                else:
                    kodiUtilities.notification(kodiUtilities.getString(32166), s)
        elif utilities.isEpisode(media_type):
            summaryInfo = {'shows': [{'ids': utilities.parseIdToTraktIds(data['id'], media_type)[0],
                                      'seasons': [{'number': data['season'], 'episodes': [{'number':data['number']}]}]}]}
            logger.debug("doAddToWatchlist(): %s" % str(summaryInfo))
            s = utilities.getFormattedItemName(media_type, data)

            result = globals.traktapi.addToWatchlist(summaryInfo)
            if result:
                kodiUtilities.notification(kodiUtilities.getString(32165), s)
            else:
                kodiUtilities.notification(kodiUtilities.getString(32166), s)
        elif utilities.isSeason(media_type):
            summaryInfo = {'shows': [{'ids': utilities.parseIdToTraktIds(data['id'], media_type)[0],
                                      'seasons': [{'number': data['season']}]}]}
            s = utilities.getFormattedItemName(media_type, data)

            logger.debug("doAddToWatchlist(): '%s - Season %d' trying to add to users watchlist."
                         % (data['id'], data['season']))

            result = globals.traktapi.addToWatchlist(summaryInfo)
            if result:
                kodiUtilities.notification(kodiUtilities.getString(32165), s)
            else:
                kodiUtilities.notification(kodiUtilities.getString(32166), s)
        elif utilities.isShow(media_type):
            summaryInfo = {'shows': [{'ids': utilities.parseIdToTraktIds(data['id'], media_type)[0]}]}
            s = utilities.getFormattedItemName(media_type, data)
            logger.debug("doAddToWatchlist(): %s" % str(summaryInfo))

            result = globals.traktapi.addToWatchlist(summaryInfo)
            if result:
                kodiUtilities.notification(kodiUtilities.getString(32165), s)
            else:
                kodiUtilities.notification(kodiUtilities.getString(32166), s)

    def doMarkWatched(self, data):

        media_type = data['media_type']

        if utilities.isMovie(media_type):
            summaryInfo = globals.traktapi.getMovieSummary(data['id']).to_dict()
            if summaryInfo:
                if not summaryInfo['watched']:
                    s = utilities.getFormattedItemName(media_type, summaryInfo)
                    logger.debug("doMarkWatched(): '%s' is not watched on Trakt, marking it as watched." % s)
                    params = {'movies': [summaryInfo]}
                    logger.debug("doMarkWatched(): %s" % str(params))

                    result = globals.traktapi.addToHistory(params)
                    if result:
                        kodiUtilities.notification(kodiUtilities.getString(32113), s)
                    else:
                        kodiUtilities.notification(kodiUtilities.getString(32114), s)
        elif utilities.isEpisode(media_type):
            summaryInfo = {'shows': [{'ids':utilities.parseIdToTraktIds(data['id'],media_type)[0], 'seasons': [{'number': data['season'], 'episodes': [{'number':data['number']}]}]}]}
            logger.debug("doMarkWatched(): %s" % str(summaryInfo))
            s = utilities.getFormattedItemName(media_type, data)

            result = globals.traktapi.addToHistory(summaryInfo)
            if result:
                kodiUtilities.notification(kodiUtilities.getString(32113), s)
            else:
                kodiUtilities.notification(kodiUtilities.getString(32114), s)
        elif utilities.isSeason(media_type):
            summaryInfo = {'shows': [{'ids':utilities.parseIdToTraktIds(data['id'],media_type)[0], 'seasons': [{'number': data['season'], 'episodes': []}]}]}
            s = utilities.getFormattedItemName(media_type, data)
            for ep in data['episodes']:
                summaryInfo['shows'][0]['seasons'][0]['episodes'].append({'number': ep})

            logger.debug("doMarkWatched(): '%s - Season %d' has %d episode(s) that are going to be marked as watched." % (data['id'], data['season'], len(summaryInfo['shows'][0]['seasons'][0]['episodes'])))

            self.addEpisodesToHistory(summaryInfo, s)

        elif utilities.isShow(media_type):
            summaryInfo = {'shows': [{'ids':utilities.parseIdToTraktIds(data['id'],media_type)[0], 'seasons': []}]}
            if summaryInfo:
                s = utilities.getFormattedItemName(media_type, data)
                logger.debug('data: %s' % data)
                for season in data['seasons']:
                    episodeJson = []
                    for episode in data['seasons'][season]:
                        episodeJson.append({'number': episode})
                    summaryInfo['shows'][0]['seasons'].append({'number': season, 'episodes': episodeJson})

                self.addEpisodesToHistory(summaryInfo, s)

    def addEpisodesToHistory(self, summaryInfo, s):
        if len(summaryInfo['shows'][0]['seasons'][0]['episodes']) > 0:
            logger.debug("doMarkWatched(): %s" % str(summaryInfo))

            result = globals.traktapi.addToHistory(summaryInfo)
            if result:
                kodiUtilities.notification(kodiUtilities.getString(32113), kodiUtilities.getString(32115) % (result['added']['episodes'], s))
            else:
                kodiUtilities.notification(kodiUtilities.getString(32114), s)

    def doSync(self, manual=False, silent=False, library="all"):
        self.syncThread = syncThread(manual, silent, library)
        self.syncThread.start()

    def callback(self, data):
        logger.debug('Callback received - Nextup skipped to the next episode')
        self.scrobbler.playbackEnded()
예제 #46
0
class traktService:
    scrobbler = None
    updateTagsThread = None
    syncThread = None
    dispatchQueue = sqlitequeue.SqliteQueue()

    def __init__(self):
        threading.Thread.name = 'trakt'

    def _dispatchQueue(self, data):
        logger.debug("Queuing for dispatch: %s" % data)
        self.dispatchQueue.append(data)

    def _dispatch(self, data):
        try:
            logger.debug("Dispatch: %s" % data)
            action = data['action']
            if action == 'started':
                del data['action']
                self.scrobbler.playbackStarted(data)
            elif action == 'ended' or action == 'stopped':
                self.scrobbler.playbackEnded()
            elif action == 'paused':
                self.scrobbler.playbackPaused()
            elif action == 'resumed':
                self.scrobbler.playbackResumed()
            elif action == 'seek' or action == 'seekchapter':
                self.scrobbler.playbackSeek()
            elif action == 'databaseUpdated':
                if utilities.getSettingAsBool('sync_on_update'):
                    logger.debug("Performing sync after library update.")
                    self.doSync()
            elif action == 'databaseCleaned':
                if utilities.getSettingAsBool('sync_on_update') and (
                        utilities.getSettingAsBool('clean_trakt_movies')
                        or utilities.getSettingAsBool('clean_trakt_episodes')):
                    logger.debug("Performing sync after library clean.")
                    self.doSync()
            elif action == 'settingsChanged':
                logger.debug("Settings changed, reloading.")
                globals.traktapi.updateSettings()
            elif action == 'markWatched':
                del data['action']
                self.doMarkWatched(data)
            elif action == 'manualRating':
                ratingData = data['ratingData']
                self.doManualRating(ratingData)
            elif action == 'manualSync':
                if not self.syncThread.isAlive():
                    logger.debug("Performing a manual sync.")
                    self.doSync(manual=True,
                                silent=data['silent'],
                                library=data['library'])
                else:
                    logger.debug("There already is a sync in progress.")
            elif action == 'settings':
                utilities.showSettings()
            elif action == 'scanStarted':
                pass
            else:
                logger.debug("Unknown dispatch action, '%s'." % action)
        except Exception as ex:
            message = utilities.createError(ex)
            logger.fatal(message)

    def run(self):
        startup_delay = utilities.getSettingAsInt('startup_delay')
        if startup_delay:
            logger.debug("Delaying startup by %d seconds." % startup_delay)
            xbmc.sleep(startup_delay * 1000)

        logger.debug("Service thread starting.")

        # purge queue before doing anything
        self.dispatchQueue.purge()

        # setup event driven classes
        self.Player = traktPlayer(action=self._dispatchQueue)
        self.Monitor = traktMonitor(action=self._dispatchQueue)

        # init traktapi class
        globals.traktapi = traktAPI()

        # init sync thread
        self.syncThread = syncThread()

        # init scrobbler class
        self.scrobbler = Scrobbler(globals.traktapi)

        # start loop for events
        while not xbmc.abortRequested:
            while len(self.dispatchQueue) and (not xbmc.abortRequested):
                data = self.dispatchQueue.get()
                logger.debug("Queued dispatch: %s" % data)
                self._dispatch(data)

            if xbmc.Player().isPlayingVideo():
                self.scrobbler.update()

            xbmc.sleep(500)

        # we are shutting down
        logger.debug("Beginning shut down.")

        # delete player/monitor
        del self.Player
        del self.Monitor

        # check if sync thread is running, if so, join it.
        if self.syncThread.isAlive():
            self.syncThread.join()

    def doManualRating(self, data):

        action = data['action']
        media_type = data['media_type']
        summaryInfo = None

        if not utilities.isValidMediaType(media_type):
            logger.debug(
                "doManualRating(): Invalid media type '%s' passed for manual %s."
                % (media_type, action))
            return

        if not data['action'] in ['rate', 'unrate']:
            logger.debug("doManualRating(): Unknown action passed.")
            return

        if 'dbid' in data:
            logger.debug(
                "Getting data for manual %s of library '%s' with ID of '%s'" %
                (action, media_type, data['dbid']))
        elif 'remoteitd' in data:
            if 'season' in data:
                logger.debug(
                    "Getting data for manual %s of non-library '%s' S%02dE%02d, with ID of '%s'."
                    % (action, media_type, data['season'], data['episode'],
                       data['remoteid']))
            else:
                logger.debug(
                    "Getting data for manual %s of non-library '%s' with ID of '%s'"
                    % (action, media_type, data['remoteid']))

        if utilities.isEpisode(media_type):
            summaryInfo = globals.traktapi.getEpisodeSummary(
                data['trakt'], data['season'], data['episode'])
        elif utilities.isShow(media_type):
            summaryInfo = globals.traktapi.getShowSummary(data['imdbnumber'])
        elif utilities.isMovie(media_type):
            summaryInfo = globals.traktapi.getMovieSummary(data['imdbnumber'])

        if not summaryInfo is None:
            if utilities.isMovie(media_type) or utilities.isShow(media_type):
                summaryInfo['xbmc_id'] = data['dbid']

            if action == 'rate':
                if not 'rating' in data:
                    rateMedia(media_type, summaryInfo)
                else:
                    rateMedia(media_type, summaryInfo, rating=data['rating'])
        else:
            logger.debug(
                "doManualRating(): Summary info was empty, possible problem retrieving data from Trakt.tv"
            )

    def doMarkWatched(self, data):

        media_type = data['media_type']
        markedNotification = utilities.getSettingAsBool(
            'show_marked_notification')

        if utilities.isMovie(media_type):
            summaryInfo = globals.traktapi.getMovieSummary(data['id'])
            if summaryInfo:
                if not summaryInfo['watched']:
                    s = utilities.getFormattedItemName(media_type, summaryInfo)
                    logger.debug(
                        "doMarkWatched(): '%s' is not watched on Trakt, marking it as watched."
                        % s)
                    movie = {
                        'imdb_id': data['id'],
                        'title': summaryInfo['title'],
                        'year': summaryInfo['year'],
                        'plays': 1,
                        'last_played': int(time())
                    }
                    params = {'movies': [movie]}
                    logger.debug("doMarkWatched(): %s" % str(params))

                    result = globals.traktapi.updateSeenMovie(params)
                    if result:
                        if markedNotification:
                            utilities.notification(utilities.getString(32113),
                                                   s)
                    else:
                        utilities.notification(utilities.getString(32114), s)

        elif utilities.isEpisode(media_type):
            summaryInfo = globals.traktapi.getEpisodeSummary(
                data['id'], data['season'], data['episode'])
            if summaryInfo:
                if not summaryInfo['episode']['watched']:
                    s = utilities.getFormattedItemName(media_type, summaryInfo)
                    logger.debug(
                        "doMarkWathced(): '%s' is not watched on Trakt, marking it as watched."
                        % s)
                    params = {
                        'imdb_id':
                        summaryInfo['ids']['imdb_id'],
                        'tvdb_id':
                        summaryInfo['ids']['tvdb_id'],
                        'title':
                        summaryInfo['title'],
                        'year':
                        summaryInfo['year'],
                        'episodes': [{
                            'season': data['season'],
                            'episode': data['episode']
                        }]
                    }
                    logger.debug("doMarkWatched(): %s" % str(params))

                    result = globals.traktapi.updateSeenEpisode(params)
                    if result:
                        if markedNotification:
                            utilities.notification(utilities.getString(32113),
                                                   s)
                    else:
                        utilities.notification(utilities.getString(32114), s)

        elif utilities.isSeason(media_type):
            showInfo = globals.traktapi.getShowSummary(data['id'])
            if not showInfo:
                return
            summaryInfo = globals.traktapi.getSeasonInfo(
                data['id'], data['season'])
            if summaryInfo:
                showInfo['season'] = data['season']
                s = utilities.getFormattedItemName(media_type, showInfo)
                params = {
                    'imdb_id': summaryInfo['ids']['imdb'],
                    'tvdb_id': summaryInfo['ids']['tvdb'],
                    'title': showInfo['title'],
                    'year': showInfo['year'],
                    'episodes': []
                }
                for ep in summaryInfo:
                    if ep['episode'] in data['episodes']:
                        if not ep['watched']:
                            params['episodes'].append({
                                'season': ep['season'],
                                'episode': ep['episode']
                            })

                logger.debug(
                    "doMarkWatched(): '%s - Season %d' has %d episode(s) that are going to be marked as watched."
                    % (showInfo['title'], data['season'],
                       len(params['episodes'])))

                if len(params['episodes']) > 0:
                    logger.debug("doMarkWatched(): %s" % str(params))

                    result = globals.traktapi.updateSeenEpisode(params)
                    if result:
                        if markedNotification:
                            utilities.notification(
                                utilities.getString(32113),
                                utilities.getString(32115) %
                                (len(params['episodes']), s))
                    else:
                        utilities.notification(
                            utilities.getString(32114),
                            utilities.getString(32115) %
                            (len(params['episodes']), s))

        elif utilities.isShow(media_type):
            summaryInfo = globals.traktapi.getShowSummary(data['id'],
                                                          extended=True)
            if summaryInfo:
                s = utilities.getFormattedItemName(media_type, summaryInfo)
                params = {
                    'imdb_id': summaryInfo['ids']['imdb'],
                    'tvdb_id': summaryInfo['ids']['tvdb'],
                    'title': summaryInfo['title'],
                    'year': summaryInfo['year'],
                    'episodes': []
                }
                for season in summaryInfo['seasons']:
                    for ep in season['episodes']:
                        if str(season['season']) in data['seasons']:
                            if ep['episode'] in data['seasons'][str(
                                    season['season'])]:
                                if not ep['watched']:
                                    params['episodes'].append({
                                        'season':
                                        ep['season'],
                                        'episode':
                                        ep['episode']
                                    })
                logger.debug(
                    "doMarkWatched(): '%s' has %d episode(s) that are going to be marked as watched."
                    % (summaryInfo['title'], len(params['episodes'])))

                if len(params['episodes']) > 0:
                    logger.debug("doMarkWatched(): %s" % str(params))

                    result = globals.traktapi.updateSeenEpisode(params)
                    if result:
                        if markedNotification:
                            utilities.notification(
                                utilities.getString(32113),
                                utilities.getString(32115) %
                                (len(params['episodes']), s))
                    else:
                        utilities.notification(
                            utilities.getString(32114),
                            utilities.getString(32115) %
                            (len(params['episodes']), s))

    def doSync(self, manual=False, silent=False, library="all"):
        self.syncThread = syncThread(manual, silent, library)
        self.syncThread.start()