Esempio n. 1
0
class serienRecCheckForRecording:

	instance = None
	epgrefresh_instance = None

	def __init__(self, session, manuell, tvplaner_manuell=False):
		assert not serienRecCheckForRecording.instance, "Go is a singleton class!"
		serienRecCheckForRecording.instance = self
		self.session = session
		self.database = None
		self.manuell = manuell
		self.tvplaner_manuell = tvplaner_manuell
		print "[SerienRecorder] 1__init__ tvplaner_manuell: ", tvplaner_manuell
		self.newSeriesOrEpisodesFound = False
		self.senderListe = {}
		self.markers = []
		self.messageList = []
		self.speedStartTime = 0
		self.speedEndTime = 0
		self.konflikt = ""
		self.count_url = 0
		self.countSerien = 0
		self.countActivatedSeries = 0
		self.noOfRecords = int(config.plugins.serienRec.NoOfRecords.value)
		self.emailData = None

		SRLogger.checkFileAccess()

		lt = time.localtime()
		self.uhrzeit = time.strftime("%d.%m.%Y - %H:%M:%S", lt)
		SRLogger.writeLog("\n---------' %s '---------" % self.uhrzeit, True)
		self.daypage = 0

		global refreshTimer
		if refreshTimer:
			refreshTimer.stop()
			refreshTimer = None

		global refreshTimerConnection
		if refreshTimerConnection:
			refreshTimerConnection = None

		self.tempDB = None

		if config.plugins.serienRec.autochecktype.value == "0":
			SRLogger.writeLog("Auto-Check ist deaktiviert - nur manuelle Timersuche", True)
		elif config.plugins.serienRec.autochecktype.value == "1":
			SRLogger.writeLog("Auto-Check ist aktiviert - er wird zur gewählten Uhrzeit gestartet", True)
		elif config.plugins.serienRec.autochecktype.value == "2":
			SRLogger.writeLog("Auto-Check ist aktiviert - er wird nach dem EPGRefresh ausgeführt", True)

		if not self.manuell and config.plugins.serienRec.autochecktype.value == "1" and config.plugins.serienRec.timeUpdate.value:
			deltatime = self.getNextAutoCheckTimer(lt)
			refreshTimer = eTimer()
			if isDreamOS():
				refreshTimerConnection = refreshTimer.timeout.connect(self.startCheck)
			else:
				refreshTimer.callback.append(self.startCheck)
			refreshTimer.start(((deltatime * 60) + random.randint(0, int(config.plugins.serienRec.maxDelayForAutocheck.value)*60)) * 1000, True)
			print "[SerienRecorder] Auto-Check Uhrzeit-Timer gestartet."
			print "[SerienRecorder] Verbleibende Zeit: %s Stunden" % (TimeHelpers.td2HHMMstr(datetime.timedelta(minutes=deltatime+int(config.plugins.serienRec.maxDelayForAutocheck.value))))
			SRLogger.writeLog("Verbleibende Zeit bis zum nächsten Auto-Check: %s Stunden\n" % TimeHelpers.td2HHMMstr(datetime.timedelta(minutes=deltatime+int(config.plugins.serienRec.maxDelayForAutocheck.value))), True)

		if self.manuell:
			print "[SerienRecorder] checkRecTimer manuell."
			self.startCheck()
			self.manuell = False
			self.tvplaner_manuell = False
		else:
			try:
				from Plugins.Extensions.EPGRefresh.EPGRefresh import epgrefresh
				self.epgrefresh_instance = epgrefresh
				config.plugins.serienRec.autochecktype.addNotifier(self.setEPGRefreshCallback)
			except Exception as e:
				SRLogger.writeLog("EPGRefresh plugin nicht installiert! " + str(e), True)

	@staticmethod
	def getNextAutoCheckTimer(lt):
		acttime = (lt.tm_hour * 60 + lt.tm_min)
		deltime = (config.plugins.serienRec.deltime.value[0] * 60 + config.plugins.serienRec.deltime.value[1])
		if acttime < deltime:
			deltatime = deltime - acttime
		else:
			deltatime = abs(1440 - acttime + deltime)
		return deltatime

	def setEPGRefreshCallback(self, configentry = None):
		try:
			if self.epgrefresh_instance:
				if config.plugins.serienRec.autochecktype.value == "2":
					self.epgrefresh_instance.addFinishNotifier(self.startCheck)
				else:
					self.epgrefresh_instance.removeFinishNotifier(self.startCheck)
		except Exception as e:
			try:
				from Tools.HardwareInfoVu import HardwareInfoVu
				pass
			except:
				SRLogger.writeLog("Um die EPGRefresh Optionen nutzen zu können, muss mindestens die EPGRefresh Version 2.1.1 installiert sein. " + str(e), True)

	def getMarkerCover(self):
		self.database = SRDatabase(serienRecDataBaseFilePath)
		markers = self.database.getAllMarkers(False)
		for marker in markers:
			(ID, Serie, Info, Url, AufnahmeVerzeichnis, AlleStaffelnAb, alleSender, Vorlaufzeit, Nachlaufzeit, AnzahlAufnahmen, preferredChannel, useAlternativeChannel, AbEpisode, TimerForSpecials, ErlaubteSTB, ErlaubteStaffelCount) = marker
			getCover(None, Serie, ID, True)

	def startCheck(self):
		self.database = SRDatabase(serienRecDataBaseFilePath)
		global autoCheckFinished
		autoCheckFinished = False

		print "[SerienRecorder] settings:"
		print "[SerienRecorder] manuell:", self.manuell
		print "[SerienRecorder] tvplaner_manuell:", self.tvplaner_manuell
		print "[SerienRecorder] uhrzeit check:", config.plugins.serienRec.timeUpdate.value

		lt = time.localtime()
		self.uhrzeit = time.strftime("%d.%m.%Y - %H:%M:%S", lt)

		global refreshTimer
		global refreshTimerConnection

		SRLogger.checkFileAccess()

		SRLogger.writeLog("\n---------' %s '---------" % self.uhrzeit, True)

		if not self.manuell and not initDB():
			self.askForDSB()
			return

		if not self.database.hasMarkers() and not config.plugins.serienRec.tvplaner and not config.plugins.serienRec.tvplaner_create_marker:
			SRLogger.writeLog("\n---------' Starte Auto-Check um %s '---------" % self.uhrzeit, True)
			print "[SerienRecorder] check: Tabelle SerienMarker leer."
			SRLogger.writeLog("Es sind keine Serien-Marker vorhanden - Auto-Check kann nicht ausgeführt werden.", True)
			SRLogger.writeLog("---------' Auto-Check beendet '---------", True)
			self.askForDSB()
			return

		if not self.database.hasChannels():
			SRLogger.writeLog("\n---------' Starte Auto-Check um %s '---------" % self.uhrzeit, True)
			print "[SerienRecorder] check: Tabelle Channels leer."
			SRLogger.writeLog("Es wurden keine Sender zugeordnet - Auto-Check kann nicht ausgeführt werden.", True)
			SRLogger.writeLog("---------' Auto-Check beendet '---------", True)
			self.askForDSB()
			return

		if refreshTimer:
			refreshTimer.stop()
			refreshTimer = None

			if refreshTimerConnection:
				refreshTimerConnection = None

			print "[SerienRecorder] Auto-Check Timer stop."
			SRLogger.writeLog("Auto-Check stop.", True)

		if config.plugins.serienRec.autochecktype.value == "1" and config.plugins.serienRec.timeUpdate.value:
			deltatime = self.getNextAutoCheckTimer(lt)
			refreshTimer = eTimer()
			if isDreamOS():
				refreshTimerConnection = refreshTimer.timeout.connect(self.startCheck)
			else:
				refreshTimer.callback.append(self.startCheck)
			refreshTimer.start(((deltatime * 60) + random.randint(0, int(config.plugins.serienRec.maxDelayForAutocheck.value)*60)) * 1000, True)

			print "[SerienRecorder] Auto-Check Uhrzeit-Timer gestartet."
			print "[SerienRecorder] Verbleibende Zeit: %s Stunden" % (TimeHelpers.td2HHMMstr(datetime.timedelta(minutes=deltatime+int(config.plugins.serienRec.maxDelayForAutocheck.value))))
			SRLogger.writeLog("Auto-Check Uhrzeit-Timer gestartet.", True)
			SRLogger.writeLog("Verbleibende Zeit: %s Stunden" % TimeHelpers.td2HHMMstr(datetime.timedelta(minutes=deltatime+int(config.plugins.serienRec.maxDelayForAutocheck.value))), True)

		if config.plugins.serienRec.AutoBackup.value == "before":
			createBackup()

		SRLogger.reset()
		from SerienRecorderTVPlaner import resetTVPlanerHTMLBackup
		resetTVPlanerHTMLBackup()
		self.database.removeExpiredTimerConflicts()

		if self.tvplaner_manuell and config.plugins.serienRec.tvplaner.value:
			print "\n---------' Starte Check um %s (TV-Planer manuell) '---------" % self.uhrzeit
			SRLogger.writeLog("\n---------' Starte Check um %s (TV-Planer manuell) '---------\n" % self.uhrzeit, True)
		elif self.manuell:
			print "\n---------' Starte Check um %s (manuell) '---------" % self.uhrzeit
			SRLogger.writeLog("\n---------' Starte Check um %s (manuell) '---------\n" % self.uhrzeit, True)
		elif config.plugins.serienRec.tvplaner.value:
			print "\n---------' Starte Auto-Check um %s (TV-Planer auto) '---------" % self.uhrzeit
			SRLogger.writeLog("\n---------' Starte Auto-Check um %s (TV-Planer auto) '---------\n" % self.uhrzeit, True)
		else:
			print "\n---------' Starte Auto-Check um %s (auto)'---------" % self.uhrzeit
			SRLogger.writeLog("\n---------' Starte Auto-Check um %s (auto)'---------\n" % self.uhrzeit, True)
			if config.plugins.serienRec.showNotification.value in ("1", "3"):
				Notifications.AddPopup("SerienRecorder Suchlauf nach neuen Timern wurde gestartet.", MessageBox.TYPE_INFO, timeout=3, id="Suchlauf wurde gestartet")

		if config.plugins.serienRec.writeLogVersion.value:
			SRLogger.writeLog("STB Type: %s\nImage: %s" % (STBHelpers.getSTBType(), STBHelpers.getImageVersionString()), True)
			SRLogger.writeLog("SR Version: %s\nDatenbank Version: %s" % (config.plugins.serienRec.showversion.value, str(self.database.getVersion())), True)
			SRLogger.writeLog("Skin Auflösung: %s x %s" % (str(getDesktop(0).size().width()), str(getDesktop(0).size().height())), True)

		sMsg = "\nDEBUG Filter: "
		if config.plugins.serienRec.writeLogChannels.value:
			sMsg += "Senderliste "
		if config.plugins.serienRec.writeLogAllowedEpisodes.value:
			sMsg += "Episoden "
		if config.plugins.serienRec.writeLogAdded.value:
			sMsg += "Added "
		if config.plugins.serienRec.writeLogDisk.value:
			sMsg += "Disk "
		if config.plugins.serienRec.writeLogTimeRange.value:
			sMsg += "Tageszeit "
		if config.plugins.serienRec.writeLogTimeLimit.value:
			sMsg += "Zeitlimit "
		if config.plugins.serienRec.writeLogTimerDebug.value:
			sMsg += "Timer "
			SRLogger.writeLog(sMsg, True)

		self.markers = []
		self.messageList = []
		self.speedStartTime = time.clock()

		# teste Verbindung ins Internet
		if not testWebConnection():
			SRLogger.writeLog("\nKeine Verbindung ins Internet. Check wurde abgebrochen!!\n", True)

			# Statistik
			self.speedEndTime = time.clock()
			speedTime = (self.speedEndTime - self.speedStartTime)
			SRLogger.writeLog("---------' Auto-Check beendet ( Ausführungsdauer: %3.2f Sek.)'---------" % speedTime, True)
			print "[SerienRecorder] ---------' Auto-Check beendet ( Ausführungsdauer: %3.2f Sek.)'---------" % speedTime

			from SerienRecorderTVPlaner import backupTVPlanerHTML
			backupTVPlanerHTML()

			global autoCheckFinished
			autoCheckFinished = True

			if config.plugins.serienRec.AutoBackup.value == "after":
				createBackup()

			# in den deep-standby fahren.
			self.askForDSB()
			return

		# Versuche Verzeichnisse zu erreichen
		try:
			SRLogger.writeLog("\nPrüfe konfigurierte Aufnahmeverzeichnisse:", True)
			recordDirectories = self.database.getRecordDirectories(config.plugins.serienRec.savetopath.value)
			for directory in recordDirectories:
				SRLogger.writeLog("   %s" % directory, True)
				os.path.exists(directory)
		except:
			SRLogger.writeLog("Es konnten nicht alle Aufnahmeverzeichnisse gefunden werden", True)

		# suche nach neuen Serien, Covern und Planer-Cache
		from twisted.internet import reactor
		from SerienRecorderSeriesPlanner import serienRecSeriesPlanner
		seriesPlanner = serienRecSeriesPlanner(self.manuell)
		reactor.callFromThread(seriesPlanner.updatePlanerData())

		#if config.plugins.serienRec.downloadCover.value:
		#	reactor.callFromThread(self.getMarkerCover())

		self.startCheckTransmissions()

	def startCheckTransmissions(self):
		self.database = SRDatabase(serienRecDataBaseFilePath)
		self.tempDB = SRTempDatabase()
		self.tempDB.initialize()

		# read channels
		self.senderListe = {}
		for s in self.database.getChannels():
			self.senderListe[s[0].lower()] = s[:]

		webChannels = self.database.getActiveChannels()
		SRLogger.writeLog("\nAnzahl aktiver Websender: %d" % len(webChannels), True)
			
		# get reference times
		current_time = int(time.time())
		future_time = int(config.plugins.serienRec.checkfordays.value) * 86400
		future_time += int(current_time)
		search_start = time.strftime("%d.%m.%Y - %H:%M", time.localtime(int(current_time)))
		search_end = time.strftime("%d.%m.%Y - %H:%M", time.localtime(int(future_time)))
		search_rerun_end = time.strftime("%d.%m.%Y - %H:%M", time.localtime(future_time + (int(config.plugins.serienRec.TimeSpanForRegularTimer.value) - int(config.plugins.serienRec.checkfordays.value)) * 86400))
		SRLogger.writeLog("Berücksichtige Ausstrahlungstermine zwischen %s und %s" % (search_start, search_end), True)
		SRLogger.writeLog("Berücksichtige Wiederholungen zwischen %s und %s" % (search_start, search_rerun_end), True)
		
		# hier werden die wunschliste markers eingelesen
		self.emailData = None
		if config.plugins.serienRec.tvplaner.value and (not self.manuell or self.tvplaner_manuell):
			# When TV-Planer processing is enabled then regular autocheck
			# is only running for the transmissions received by email.
			try:
				from SerienRecorderTVPlaner import getEmailData
				emailParserThread = backgroundThread(getEmailData)
				emailParserThread.start()
				emailParserThread.join()
				self.emailData = emailParserThread.result
			except:
				SRLogger.writeLog("TV-Planer Verarbeitung fehlgeschlagen!", True)
				print "[SerienRecorder] TV-Planer exception!"
				self.emailData = None
		print "[SerienRecorder] lastFullCheckTime %s" % time.strftime("%d.%m.%Y - %H:%M", time.localtime(int(config.plugins.serienRec.tvplaner_last_full_check.value)))
		if self.emailData is None:
			self.markers = self.database.getMarkers(config.plugins.serienRec.BoxID.value, config.plugins.serienRec.NoOfRecords.value)
			config.plugins.serienRec.tvplaner_last_full_check.value = int(time.time())
			config.plugins.serienRec.tvplaner_last_full_check.save()
			configfile.save()
			if config.plugins.serienRec.tvplaner.value:
				fullCheck = "- keine TV-Planer Daten - voller Suchlauf'"
			else:
				fullCheck = "- voller Suchlauf'"
		elif config.plugins.serienRec.tvplaner_full_check.value and (int(config.plugins.serienRec.tvplaner_last_full_check.value) + (int(config.plugins.serienRec.checkfordays.value) - 1) * 86400) < int(time.time()):
			self.markers = self.database.getMarkers(config.plugins.serienRec.BoxID.value, config.plugins.serienRec.NoOfRecords.value)
			config.plugins.serienRec.tvplaner_last_full_check.value = int(time.time())
			config.plugins.serienRec.tvplaner_last_full_check.save()
			configfile.save()
			fullCheck = "- Zeit abgelaufen - voller Suchlauf'"
		else:
			self.markers = self.database.getMarkers(config.plugins.serienRec.BoxID.value, config.plugins.serienRec.NoOfRecords.value, self.emailData.keys())
			fullCheck = "- nur Serien der TV-Planer E-Mail'"
		self.count_url = 0
		self.countSerien = 0
		self.countActivatedSeries = 0
		self.noOfRecords = int(config.plugins.serienRec.NoOfRecords.value)

		# regular processing through serienrecorder server
		# TODO: save all transmissions in files to protect from temporary SerienServer fails
		#       data will be read by the file reader below and used for timer programming
		if len(self.markers) > 0:
			while True:
				#if config.plugins.serienRec.tvplaner.value and config.plugins.serienRec.tvplaner_skipSerienServer.value:
					# Skip serien server processing
				#	break

				global transmissionFailed
				transmissionFailed = False
				self.tempDB.cleanUp()
				if not (config.plugins.serienRec.tvplaner.value and config.plugins.serienRec.tvplaner_skipSerienServer.value):
					SRLogger.writeLog("\n---------' Verarbeite Daten vom Server %s ---------\n" % fullCheck, True)
					print "[SerienRecorder] Verarbeite Daten vom Server"

				# Create a job queue to keep the jobs processed by the threads
				# Create a result queue to keep the results of the job threads
				jobQueue = Queue.Queue()
				resultQueue = Queue.Queue()

				#SRLogger.writeLog("Active threads: %d" % threading.active_count(), True)
				# Create the threads
				for i in range(2):
					worker = downloadTransmissionsThread(jobQueue, resultQueue)
					worker.setDaemon(True)
					worker.start()

				for serienTitle,SerieUrl,SerieStaffel,SerieSender,AbEpisode,AnzahlAufnahmen,SerieEnabled,excludedWeekdays,skipSeriesServer,markerType in self.markers:
					if config.plugins.serienRec.tvplaner.value and (config.plugins.serienRec.tvplaner_skipSerienServer.value or (skipSeriesServer is not None and skipSeriesServer)):
						# Skip serien server processing
						SRLogger.writeLog("' %s ' - Für diesen Serien-Marker sollen nur Timer aus der E-Mail angelegt werden." % serienTitle, True)
						continue

					if markerType == 1:
						# temporary marker for movie recording
						print "[SerienRecorder] ' %s - TV-Planer Film wird ignoriert '" % serienTitle
						continue
					self.countSerien += 1
					if SerieEnabled:
						# Download only if series is enabled
						if 'Alle' in SerieSender:
							markerChannels = webChannels
						else:
							markerChannels = SerieSender

						self.countActivatedSeries += 1
						seriesID = SerieUrl

						jobQueue.put((seriesID, (int(config.plugins.serienRec.TimeSpanForRegularTimer.value)), markerChannels, serienTitle, SerieStaffel, AbEpisode, AnzahlAufnahmen, current_time, future_time, excludedWeekdays))

				jobQueue.join()
				while not resultQueue.empty():
					(transmissionFailed, transmissions, seriesID, serienTitle, SerieStaffel, AbEpisode, AnzahlAufnahmen, current_time, future_time, excludedWeekdays) = resultQueue.get()
					self.processTransmission(transmissions, seriesID, serienTitle, SerieStaffel, AbEpisode, AnzahlAufnahmen, current_time, future_time, excludedWeekdays)
					resultQueue.task_done()

				break
		# 
		# In order to provide an emergency recording service when serien server is down or
		# because Wunschliste isn't accessable, it is now possible to use the TV Wunschliste
		# TV-Planer Infomails.
		# 
		# With an account at www.wunschliste.de it is possible to mark series to appear at
		# "TV-Planer" screen. This screen shows the transmissions of up to a week in advance.
		# In "Einstellungen" it is possible to enable Infomails about TV-Planer. This Infomails
		# can now be used by SerienRecorder to create timers without any further access to
		# Wunschliste, and therefore avoids hitting Wunschliste with the enormous
		# internet traffic that was caused by the many boxes with SerienRecorder.
		#
		# Wunschliste Settings:
		# - put your favourite series on TV-Planer
		# - enable TV-Planer Infomails in "Einstellungen"
		# - set Vorlauf (i.e. 1 day)
		# - set Programmtag-Beginn (i.e. 5.00 Uhr)
		# - set MailFormat to HTML+Text (currently only HTML emails are recognized)
		#
		# When this has been finished the first TV-Planer email will be received next day.
		# 
		# SerienRecorder Settings:
		# - enable TVPlaner feature
		# - set email server, login, password and possibly modify the other parameters
		# - set the autocheck time to about 1 h after the time you receive the TV-planer emails
		#
		# Now every time the regular SerienRecorder autocheck runs, received 
		# TV-Planer emails will be used to program timers, even no marker 
		# has been created by SerienMarker before. The marker is created automatically, 
		# except for the correct url.  
		#
		if config.plugins.serienRec.tvplaner.value and self.emailData is not None:
			# check mailbox for TV-Planer EMail and create timer
			SRLogger.writeLog("\n---------' Verarbeite Daten aus TV-Planer E-Mail '---------\n", True)

			jobQueue = Queue.Queue()
			resultQueue = Queue.Queue()

			# Create the threads
			for i in range(2):
				worker = processEMailDataThread(self.emailData, jobQueue, resultQueue)
				worker.setDaemon(True)
				worker.start()

			for serienTitle,SerieUrl,SerieStaffel,SerieSender,AbEpisode,AnzahlAufnahmen,SerieEnabled,excludedWeekdays,skipSeriesServer,markerType in self.database.getMarkers(config.plugins.serienRec.BoxID.value, config.plugins.serienRec.NoOfRecords.value, self.emailData.keys()):
				print serienTitle
				if SerieEnabled:
					# Process only if series is enabled
					if 'Alle' in SerieSender:
						markerChannels = { x : x for x in webChannels }
					else:
						markerChannels = { x : x for x in SerieSender }

					jobQueue.put((markerChannels, SerieUrl, serienTitle, SerieStaffel, AbEpisode, AnzahlAufnahmen, current_time, future_time, excludedWeekdays))

			jobQueue.join()
			while not resultQueue.empty():
				(transmissions, seriesID, serienTitle, SerieStaffel, AbEpisode, AnzahlAufnahmen, current_time, future_time, excludedWeekdays) = resultQueue.get()
				self.processTransmission(transmissions, seriesID, serienTitle, SerieStaffel, AbEpisode, AnzahlAufnahmen, current_time, future_time, excludedWeekdays)
				resultQueue.task_done()

		self.createTimer()
		self.checkFinal()

	def createTimer(self, result=True):
		from SerienRecorderTimer import serienRecTimer
		timer = serienRecTimer()
		timer.setTempDB(self.tempDB)

		# versuche deaktivierte Timer zu erstellen
		timer.activate()

		# jetzt die Timer erstellen
		for x in range(self.noOfRecords):
			timer.search(x)

		# gleiche alte Timer mit EPG ab
		current_time = int(time.time())
		timer.adjustEPGtimes(current_time)
		SRLogger.writeLog("\n", True)

		# Datenbank aufräumen
		self.database.rebuild()
		self.tempDB.rebuild()

		global autoCheckFinished
		autoCheckFinished = True

		(countTimer, countTimerUpdate, countNotActiveTimer, countTimerFromWishlist, self.messageList) = timer.getCounts()

		# Statistik
		self.speedEndTime = time.clock()
		speedTime = (self.speedEndTime - self.speedStartTime)
		if config.plugins.serienRec.eventid.value:
			SRLogger.writeLog("%s/%s Serie(n) sind vorgemerkt davon wurde(n) %s Timer erstellt und %s Timer aktualisiert." % (str(self.countActivatedSeries), str(self.countSerien), str(countTimer), str(countTimerUpdate)), True)
			print "[SerienRecorder] %s/%s Serie(n) sind vorgemerkt davon wurde(n) %s Timer erstellt und %s Timer aktualisiert." % (str(self.countActivatedSeries), str(self.countSerien), str(countTimer), str(countTimerUpdate))
		else:
			SRLogger.writeLog("%s/%s Serie(n) sind vorgemerkt davon wurde(n) %s Timer erstellt." % (str(self.countActivatedSeries), str(self.countSerien), str(countTimer)), True)
			print "[SerienRecorder] %s/%s Serie(n) sind vorgemerkt davon wurde(n) %s Timer erstellt." % (str(self.countActivatedSeries), str(self.countSerien), str(countTimer))
		if countNotActiveTimer > 0:
			SRLogger.writeLog("%s Timer wurde(n) wegen Konflikten deaktiviert erstellt!" % str(countNotActiveTimer), True)
			print "[SerienRecorder] %s Timer wurde(n) wegen Konflikten deaktiviert erstellt!" % str(countNotActiveTimer)
		if countTimerFromWishlist > 0:
			SRLogger.writeLog("%s Timer vom Merkzettel wurde(n) erstellt!" % str(countTimerFromWishlist), True)
			print "[SerienRecorder] %s Timer vom Merkzettel wurde(n) erstellt!" % str(countTimerFromWishlist)
		SRLogger.writeLog("---------' Auto-Check beendet (Ausführungsdauer: %3.2f Sek.)'---------" % speedTime, True)
		print "[SerienRecorder] ---------' Auto-Check beendet (Ausführungsdauer: %3.2f Sek.)'---------" % speedTime
		if (config.plugins.serienRec.showNotification.value in ("2", "3")) and (not self.manuell):
			statisticMessage = "Serien vorgemerkt: %s/%s\nTimer erstellt: %s\nTimer aktualisiert: %s\nTimer mit Konflikten: %s\nTimer vom Merkzettel: %s" % (
			str(self.countActivatedSeries), str(self.countSerien), str(countTimer), str(countTimerUpdate),
			str(countNotActiveTimer), str(countTimerFromWishlist))
			newSeasonOrEpisodeMessage = ""
			if self.newSeriesOrEpisodesFound:
				newSeasonOrEpisodeMessage = "\n\nNeuer Serien- oder Staffelbeginn gefunden"

			Notifications.AddPopup("SerienRecorder Suchlauf für neue Timer wurde beendet.\n\n%s%s" % (
			statisticMessage, newSeasonOrEpisodeMessage), MessageBox.TYPE_INFO, timeout=10, id="Suchlauf wurde beendet")

		return result

	def checkFinal(self):
		print "[SerienRecorder] checkFinal"
		# final processing
		if config.plugins.serienRec.tvplaner.value and config.plugins.serienRec.tvplaner_movies.value:
			# remove all serien markers created for movies
			try:
				self.database.removeMovieMarkers()
				print "[SerienRecorder] ' TV-Planer FilmMarker gelöscht '"
			except:
				SRLogger.writeLog("' TV-Planer FilmMarker löschen fehlgeschlagen '", True)
				print "[SerienRecorder] ' TV-Planer FilmMarker löschen fehlgeschlagen '"
			global transmissionFailed
			if transmissionFailed: 
				# always do fullcheck after transmission error
				config.plugins.serienRec.tvplaner_last_full_check.value = int(0)
				config.plugins.serienRec.tvplaner_last_full_check.save()
				configfile.save()

		if config.plugins.serienRec.AutoBackup.value == "after":
			createBackup()

		from SerienRecorderTVPlaner import backupTVPlanerHTML
		backupTVPlanerHTML()

		# trigger read of log file
		global autoCheckFinished
		autoCheckFinished = True
		print "[SerienRecorder] checkFinal: autoCheckFinished"
		if config.plugins.serienRec.autochecktype.value == "1":
			lt = time.localtime()
			deltatime = self.getNextAutoCheckTimer(lt)
			SRLogger.writeLog("\nVerbleibende Zeit bis zum nächsten Auto-Check: %s Stunden\n" % TimeHelpers.td2HHMMstr(datetime.timedelta(minutes=deltatime+int(config.plugins.serienRec.maxDelayForAutocheck.value))), True)
			if config.plugins.serienRec.tvplaner_full_check.value:
				autoCheckDays = ((int(config.plugins.serienRec.tvplaner_last_full_check.value) + (int(config.plugins.serienRec.checkfordays.value) - 1) * 86400) - int(time.time())) / 86400
				if autoCheckDays < 0:
					autoCheckDays = 0
				SRLogger.writeLog("Verbleibende Zeit bis zum nächsten vollen Auto-Check: %d Tage" % autoCheckDays, True)

		self.tempDB = None
		self.database = None

		# in den deep-standby fahren.
		self.askForDSB()

	def processTransmission(self, data, serien_id, serien_name, staffeln, AbEpisode, AnzahlAufnahmen, current_time, future_time, excludedWeekdays=None):
		print "[SerienRecorder] processTransmissions: %r" % serien_name
		self.count_url += 1

		if data is None:
			SRLogger.writeLog("Fehler beim Abrufen und Verarbeiten der Ausstrahlungstermine [%s]" % serien_name, True)
			#print "[SerienRecorder] processTransmissions: no Data"
			return

		(fromTime, toTime) = self.database.getTimeSpan(serien_name, config.plugins.serienRec.globalFromTime.value, config.plugins.serienRec.globalToTime.value)
		if self.noOfRecords < AnzahlAufnahmen:
			self.noOfRecords = AnzahlAufnahmen

		TimeSpan_time = int(future_time)
		if config.plugins.serienRec.forceRecording.value:
			TimeSpan_time += (int(config.plugins.serienRec.TimeSpanForRegularTimer.value) - int(config.plugins.serienRec.checkfordays.value)) * 86400

		# loop over all transmissions
		self.tempDB.beginTransaction()
		for current_serien_name, sender, startzeit, endzeit, staffel, episode, title, status in data:
			start_unixtime = startzeit
			end_unixtime = endzeit

			# install missing covers
			(dirname, dirname_serie) = getDirname(self.database, serien_name, staffel)
			STBHelpers.createDirectory(current_serien_name, dirname, dirname_serie, True)

			# setze die vorlauf/nachlauf-zeit
			(margin_before, margin_after) = self.database.getMargins(serien_name, sender, config.plugins.serienRec.margin_before.value, config.plugins.serienRec.margin_after.value)
			start_unixtime = int(start_unixtime) - (int(margin_before) * 60)
			end_unixtime = int(end_unixtime) + (int(margin_after) * 60)

			# if there is no season or episode number it can be a special
			# but if we have more than one special and wunschliste.de does not
			# give us an episode number we are unable to differentiate between these specials
			if not staffel and not episode:
				staffel = "S"
				episode = "00"

			# initialize strings
			seasonEpisodeString = "S%sE%s" % (str(staffel).zfill(2), str(episode).zfill(2))
			label_serie = "%s - %s - %s" % (serien_name, seasonEpisodeString, title)

			if not config.plugins.serienRec.forceRecording.value:
				if (int(fromTime) > 0) or (int(toTime) < (23*60)+59):
					start_time = (time.localtime(int(start_unixtime)).tm_hour * 60) + time.localtime(int(start_unixtime)).tm_min
					end_time = (time.localtime(int(end_unixtime)).tm_hour * 60) + time.localtime(int(end_unixtime)).tm_min
					if not TimeHelpers.allowedTimeRange(fromTime, toTime, start_time, end_time):
						print "[SerienRecorder] processTransmissions time range ignore: %r" % serien_name
						timeRangeConfigured = "%s:%s - %s:%s" % (str(int(fromTime) / 60).zfill(2), str(int(fromTime) % 60).zfill(2), str(int(toTime) / 60).zfill(2), str(int(toTime) % 60).zfill(2))
						timeRangeTransmission = "%s:%s - %s:%s" % (str(int(start_time) / 60).zfill(2), str(int(start_time) % 60).zfill(2), str(int(end_time) / 60).zfill(2), str(int(end_time) % 60).zfill(2))
						SRLogger.writeLogFilter("timeRange", "' %s ' - Sendung (%s) nicht in Zeitspanne [%s]" % (label_serie, timeRangeTransmission, timeRangeConfigured))
						continue


			# Process channel relevant data

			##############################
			#
			# CHECK
			#
			# ueberprueft welche sender aktiviert und eingestellt sind.
			#
			(webChannel, stbChannel, stbRef, altstbChannel, altstbRef, status) = self.checkSender(sender)
			if stbChannel == "":
				SRLogger.writeLogFilter("channels", "' %s ' - STB-Sender nicht gefunden ' -> ' %s '" % (label_serie, webChannel))
				continue

			if int(status) == 0:
				SRLogger.writeLogFilter("channels", "' %s ' - STB-Sender deaktiviert -> ' %s '" % (label_serie, webChannel))
				continue

			##############################
			#
			# CHECK
			#
			# ueberprueft welche staffel(n) erlaubt sind
			#
			serieAllowed = False
			if -2 in staffeln:                          	# 'Manuell'
				serieAllowed = False
			elif (-1 in staffeln) and (0 in staffeln):		# 'Alle'
				serieAllowed = True
			elif str(staffel).isdigit():
				if int(staffel) == 0:
					if str(episode).isdigit():
						if int(episode) < int(AbEpisode):
							if config.plugins.serienRec.writeLogAllowedEpisodes.value:
								liste = staffeln[:]
								liste.sort()
								liste.reverse()
								if -1 in staffeln:
									liste.remove(-1)
									liste[0] = "ab %s" % liste[0]
								liste.reverse()
								liste.insert(0, "0 ab E%s" % str(AbEpisode).zfill(2))
								SRLogger.writeLogFilter("allowedEpisodes", "' %s ' - Episode nicht erlaubt -> ' %s ' -> ' %s '" % (label_serie, seasonEpisodeString, str(liste).replace("'", "").replace('"', "")))
							continue
						else:
							serieAllowed = True
				elif int(staffel) in staffeln:
					serieAllowed = True
				elif -1 in staffeln:		# 'folgende'
					if int(staffel) >= max(staffeln):
						serieAllowed = True
			elif self.database.getSpecialsAllowed(serien_name):
				serieAllowed = True

			vomMerkzettel = False
			if not serieAllowed:
				if self.database.hasBookmark(serien_name, staffel, episode):
					SRLogger.writeLog("' %s ' - Timer vom Merkzettel wird angelegt @ %s" % (label_serie, stbChannel), True)
					serieAllowed = True
					vomMerkzettel = True

			if not serieAllowed:
				if config.plugins.serienRec.writeLogAllowedEpisodes.value:
					liste = staffeln[:]
					liste.sort()
					liste.reverse()
					if -1 in staffeln:
						liste.remove(-1)
						liste[0] = "ab %s" % liste[0]
					liste.reverse()
					if str(episode).isdigit():
						if int(episode) < int(AbEpisode):
							liste.insert(0, "0 ab E%s" % str(AbEpisode).zfill(2))
					if -2 in staffeln:
						liste.remove(-2)
						liste.insert(0, "Manuell")
						SRLogger.writeLogFilter("allowedEpisodes", "' %s ' - Staffel nicht erlaubt -> ' %s ' -> ' %s '" % (label_serie, seasonEpisodeString, str(liste).replace("'", "").replace('"', "")))
				continue


			##############################
			#
			# try to get eventID (eit) from epgCache
			#
			eit, new_end_unixtime, new_start_unixtime = STBHelpers.getStartEndTimeFromEPG(start_unixtime, end_unixtime, margin_before, margin_after, serien_name, stbRef)
			alt_eit = 0
			alt_end_unixtime = end_unixtime
			alt_start_unixtime = start_unixtime
			if altstbRef:
				alt_eit, alt_end_unixtime, alt_start_unixtime = STBHelpers.getStartEndTimeFromEPG(start_unixtime, end_unixtime, margin_before, margin_after, serien_name, altstbRef)

			updateFromEPG = self.database.getUpdateFromEPG(serien_name)
			if updateFromEPG is False:
				new_start_unixtime = start_unixtime
				new_end_unixtime = end_unixtime
				alt_end_unixtime = end_unixtime
				alt_start_unixtime = start_unixtime

			(dirname, dirname_serie) = getDirname(self.database, serien_name, staffel)
			self.tempDB.addTransmission([(current_time, future_time, serien_name, staffel, episode, seasonEpisodeString, title, label_serie, webChannel, stbChannel, stbRef, new_start_unixtime, new_end_unixtime, eit, altstbChannel, altstbRef, alt_start_unixtime, alt_end_unixtime, alt_eit, dirname, AnzahlAufnahmen, fromTime, toTime, int(vomMerkzettel), excludedWeekdays, updateFromEPG)])
		self.tempDB.commitTransaction()


	def askForDSB(self):
		if not self.manuell:
			if config.plugins.serienRec.afterAutocheck.value != "0":
				if config.plugins.serienRec.DSBTimeout.value > 0 and not Screens.Standby.inStandby:
					print "[SerienRecorder] Try to display shutdown notification..."
					try:
						notificationText = "Soll der SerienRecorder die Box in den Ruhemodus (Standby) schalten?"
						if config.plugins.serienRec.afterAutocheck.value == "2":
							notificationText = "Soll der SerienRecorder die Box ausschalten (Deep-Standby)?"
						Notifications.AddNotificationWithCallback(self.gotoDeepStandby, MessageBox, text=notificationText, type=MessageBox.TYPE_YESNO, timeout=config.plugins.serienRec.DSBTimeout.value, default=True)
					except Exception as e:
						print "[SerienRecorder] Could not display shutdown notification - shutdown box without notification... (%s)" % str(e)
						self.gotoDeepStandby(True)
				else:
					self.gotoDeepStandby(True)

	def gotoDeepStandby(self, answer):
		if answer:
			if config.plugins.serienRec.afterAutocheck.value == "2":
				if not NavigationInstance.instance.RecordTimer.isRecording():
					for each in self.messageList:
						Notifications.RemovePopup(each[3])

					print "[SerienRecorder] gehe in Deep-Standby"
					SRLogger.writeLog("gehe in Deep-Standby")
					if Screens.Standby.inStandby:
						from RecordTimer import RecordTimerEntry
						RecordTimerEntry.TryQuitMainloop()
					else:
						Notifications.AddNotificationWithID("Shutdown", Screens.Standby.TryQuitMainloop, 1)
				else:
					print "[SerienRecorder] Eine laufende Aufnahme verhindert den Deep-Standby"
					SRLogger.writeLog("Eine laufende Aufnahme verhindert den Deep-Standby")
			else:
				print "[SerienRecorder] gehe in Standby"
				SRLogger.writeLog("gehe in Standby")
				Notifications.AddNotification(Screens.Standby.Standby)

	def checkSender(self, channel):
		if channel.lower() in self.senderListe:
			(webChannel, stbChannel, stbRef, altstbChannel, altstbRef, status) = self.senderListe[channel.lower()]
		else:
			webChannel = channel
			stbChannel = ""
			stbRef = ""
			altstbChannel = ""
			altstbRef = ""
			status = "0"
		return webChannel, stbChannel, stbRef, altstbChannel, altstbRef, status

	@staticmethod
	def dataError(error):
		print "[SerienRecorder] Es ist ein Fehler aufgetreten - die Daten konnten nicht abgerufen/verarbeitet werden: (%s)" % error
class serienRecMainChannelEdit(serienRecBaseScreen, Screen, HelpableScreen):
    def __init__(self, session):
        serienRecBaseScreen.__init__(self, session)
        Screen.__init__(self, session)
        HelpableScreen.__init__(self)
        self.session = session
        self.serienRecChannelList = []
        self.stbChannelList = []
        self.selected_sender = None
        self.skin = None
        self.displayMode = 2
        self.chooseMenuList = None
        self.chooseMenuList_popup = None
        self.chooseMenuList_popup2 = None

        from SerienRecorder import serienRecDataBaseFilePath
        from SerienRecorderDatabase import SRDatabase
        self.database = SRDatabase(serienRecDataBaseFilePath)

        from difflib import SequenceMatcher
        self.sequenceMatcher = SequenceMatcher(" ".__eq__, "", "")

        self["actions"] = HelpableActionMap(
            self, "SerienRecorderActions", {
                "ok": (self.keyOK,
                       "Popup-Fenster zur Auswahl des STB-Sender öffnen"),
                "cancel": (self.keyCancel, "zurück zur Serienplaner-Ansicht"),
                "red":
                (self.keyRed,
                 "umschalten ausgewählter Sender für Timererstellung aktiviert/deaktiviert"
                 ),
                "red_long":
                (self.keyRedLong,
                 "ausgewählten Sender aus der Channelliste endgültig löschen"),
                "green": (self.keyGreen, "Sender-Zuordnung aktualisieren"),
                "blue": (self.keyBlue, "Automatische Sender-Zuordnung"),
                "menu":
                (self.channelSetup, "Menü für Sender-Einstellungen öffnen"),
                "menu_long":
                (self.recSetup, "Menü für globale Einstellungen öffnen"),
                "left": (self.keyLeft, "zur vorherigen Seite blättern"),
                "right": (self.keyRight, "zur nächsten Seite blättern"),
                "up": (self.keyUp, "eine Zeile nach oben"),
                "down": (self.keyDown, "eine Zeile nach unten"),
                "0":
                (self.readLogFile, "Log-File des letzten Suchlaufs anzeigen"),
                "3": (self.showProposalDB,
                      "Liste der Serien/Staffel-Starts anzeigen"),
                "6":
                (self.showConflicts, "Liste der Timer-Konflikte anzeigen"),
                "7": (self.showWishlist,
                      "Merkzettel (vorgemerkte Folgen) anzeigen"),
                "8": (self.checkChannels, "Sender prüfen"),
                "9": (self.resetChannelList, "Alle Zuordnungen löschen"),
            }, -1)
        self.helpList[0][2].sort()

        self["helpActions"] = ActionMap([
            "SerienRecorderActions",
        ], {
            "displayHelp": self.showHelp,
            "displayHelp_long": self.showManual,
        }, 0)

        self.setupSkin()

        self.modus = "list"
        self.changesMade = False

        self.timer_default = eTimer()
        if isDreamOS():
            self.timer_default_conn = self.timer_default.timeout.connect(
                self.showChannels)
        else:
            self.timer_default.callback.append(self.showChannels)

        self.onLayoutFinish.append(self.__onLayoutFinished)
        self.onClose.append(self.__onClose)
        self.onLayoutFinish.append(self.setSkinProperties)

    def callHelpAction(self, *args):
        HelpableScreen.callHelpAction(self, *args)

    def setSkinProperties(self):
        super(self.__class__, self).setSkinProperties()

        self['text_green'].setText("Aktualisieren")
        self['text_ok'].setText("Sender auswählen")

        self.num_bt_text[3][1] = "Sender prüfen"
        self.num_bt_text[4][1] = "Alle löschen"
        if longButtonText:
            self.num_bt_text[4][0] = ""
            self['text_red'].setText("An/Aus (lang: Löschen)")
            self.num_bt_text[4][2] = "Setup Sender (lang: global)"
        else:
            self.num_bt_text[4][0] = buttonText_na
            self['text_red'].setText("(De)aktivieren/Löschen")
            self.num_bt_text[4][2] = "Setup Sender/global"

        self['text_blue'].setText("Auto-Zuordnung")

        self.num_bt_text[2][2] = buttonText_na
        self.num_bt_text[3][2] = buttonText_na

        super(self.__class__, self).startDisplayTimer()

    def setupSkin(self):
        self.skin = None
        InitSkin(self)

        # normal
        self.chooseMenuList = MenuList([],
                                       enableWrapAround=True,
                                       content=eListboxPythonMultiContent)
        self.chooseMenuList.l.setFont(
            0,
            gFont('Regular',
                  20 + int(config.plugins.serienRec.listFontsize.value)))
        self.chooseMenuList.l.setItemHeight(int(25 * skinFactor))
        self['list'] = self.chooseMenuList
        self['list'].show()

        # popup
        self.chooseMenuList_popup = MenuList(
            [], enableWrapAround=True, content=eListboxPythonMultiContent)
        self.chooseMenuList_popup.l.setFont(
            0,
            gFont('Regular',
                  20 + int(config.plugins.serienRec.listFontsize.value)))
        self.chooseMenuList_popup.l.setItemHeight(int(25 * skinFactor))
        self['popup_list'] = self.chooseMenuList_popup
        self['popup_list'].hide()

        # popup2
        self.chooseMenuList_popup2 = MenuList(
            [], enableWrapAround=True, content=eListboxPythonMultiContent)
        self.chooseMenuList_popup2.l.setFont(
            0,
            gFont('Regular',
                  20 + int(config.plugins.serienRec.listFontsize.value)))
        self.chooseMenuList_popup2.l.setItemHeight(int(25 * skinFactor))
        self['popup_list2'] = self.chooseMenuList_popup2
        self['popup_list2'].hide()

        self['title'].setText("Lade Wunschliste-Sender...")

        self['Web_Channel'].setText("Wunschliste")
        self['STB_Channel'].setText("STB-Sender")
        self['alt_STB_Channel'].setText("alt. STB-Sender")

        self['Web_Channel'].show()
        self['STB_Channel'].show()
        self['alt_STB_Channel'].show()
        self['separator'].show()

        if not config.plugins.serienRec.showAllButtons.value:
            self['bt_red'].show()
            self['bt_green'].show()
            self['bt_blue'].show()
            self['bt_ok'].show()
            self['bt_exit'].show()
            #self['bt_text'].show()
            self['bt_epg'].hide()
            self['bt_info'].show()
            self['bt_menu'].show()

            self['text_red'].show()
            self['text_green'].show()
            self['text_blue'].show()
            self['text_ok'].show()
            self['text_0'].show()
            self['text_1'].show()
            self['text_2'].show()
            self['text_3'].show()
            self['text_4'].show()

    def updateMenuKeys(self):
        updateMenuKeys(self)

    def channelSetup(self):
        webSender = self['list'].getCurrent()[0][0]
        self.session.open(serienRecChannelSetup, webSender)

    def setupClose(self, result):
        super(self.__class__, self).setupClose(result)

        if result[1]:
            self.showChannels()

    def __onLayoutFinished(self):
        self['title'].setText("Lade Wunschliste-Sender...")
        self.timer_default.start(0)

    def checkChannels(self):
        channels = self.database.getChannels(True)
        if config.plugins.serienRec.selectBouquets.value:
            stbChannelList = STBHelpers.buildSTBChannelList(
                config.plugins.serienRec.MainBouquet.value)
        else:
            stbChannelList = STBHelpers.buildSTBChannelList()

        stbServiceRefs = [x[1] for x in stbChannelList]
        serviceRefs = [x[2] for x in channels]
        missingServiceRefs = []
        missingServices = []

        for serviceRef in serviceRefs:
            if serviceRef not in stbServiceRefs:
                missingServiceRefs.append(serviceRef)

        for missingServiceRef in missingServiceRefs:
            for channel in channels:
                (webSender, servicename, serviceref, altservicename,
                 altserviceref, status) = channel
                if serviceref is missingServiceRef and servicename and int(
                        status) != 0:
                    missingServices.append(servicename)
                    SRLogger.writeLog(
                        "%s => %s" % (missingServiceRef, servicename), True)
                    break

        if missingServices:
            self.session.open(
                MessageBox,
                "Für folgende Sender existiert die ServiceRef nicht mehr,\nbitte die Sender neu zuweisen:\n\n"
                + "\n".join(missingServices),
                MessageBox.TYPE_INFO,
                timeout=0)
        else:
            self.session.open(MessageBox,
                              "Alle zugewiesenen Sender sind noch vorhanden.",
                              MessageBox.TYPE_INFO,
                              timeout=7)

    def showChannels(self):
        self.timer_default.stop()
        self.serienRecChannelList = []
        channels = self.database.getChannels(True)
        for channel in channels:
            (webSender, servicename, serviceref, altservicename, altserviceref,
             status) = channel
            self.serienRecChannelList.append(
                (webSender, servicename, altservicename, status))

        if len(self.serienRecChannelList) != 0:
            self['title'].setText("Sender zuordnen")
            self.chooseMenuList.setList(
                map(self.buildList, self.serienRecChannelList))
        else:
            self.channelReset(True)

    def readWebChannels(self):
        print "[SerienRecorder] call webpage."
        self['title'].setText("Lade Wunschliste-Sender...")
        try:
            self.createWebChannels(SeriesServer().doGetWebChannels(), False)
        except:
            self['title'].setText("Fehler beim Laden der Wunschliste-Sender")

    def createWebChannels(self, webChannelList, autoMatch):
        if webChannelList:
            webChannelList.sort(key=lambda x: x.lower())
            self.serienRecChannelList = []

            if len(webChannelList) != 0:
                self['title'].setText("Erstelle Sender-Liste...")

                # Get existing channels from database
                dbChannels = self.database.getChannelPairs()

                if autoMatch:
                    # Get all unassigned web channels and try to find the STB channel equivalent
                    # Update only matching channels in list
                    #sql = "UPDATE OR IGNORE Channels SET STBChannel=?, ServiceRef=?, Erlaubt=? WHERE LOWER(WebChannel)=?"
                    unassignedWebChannels = self.getUnassignedWebChannels(
                        dbChannels)

                    channels = []
                    for webChannel in unassignedWebChannels:
                        # Unmapped web channel
                        (servicename, serviceref
                         ) = self.findWebChannelInSTBChannels(webChannel)
                        if servicename and serviceref:
                            channels.append((servicename, serviceref, 1,
                                             webChannel.lower()))
                            self.serienRecChannelList.append(
                                (webChannel, servicename, "", "1"))

                        self.database.updateChannels(channels)
                        self.changesMade = True
                else:
                    # Get all new web channels (missing in SR database)
                    (newWebChannels,
                     removedWebChannels) = self.getMissingWebChannels(
                         webChannelList, dbChannels)

                    # Delete remove channels
                    if removedWebChannels:
                        SRLogger.writeLog(
                            "Folgende Sender wurden bei Wunschliste nicht mehr gefunden, die Zuordnung im SerienRecorder wurde gelöscht:\n"
                            + "\n".join(removedWebChannels), True)
                        self.session.open(
                            MessageBox,
                            "Folgende Sender wurden bei Wunschliste nicht mehr gefunden,\ndie Zuordnung im SerienRecorder wurde gelöscht:\n\n"
                            + "\n".join(removedWebChannels),
                            MessageBox.TYPE_INFO,
                            timeout=10)
                        for webChannel in removedWebChannels:
                            self.selected_sender = webChannel
                            self.channelDelete(True)

                    if not newWebChannels:
                        SRLogger.writeLog(
                            "Die SerienRecorder Senderliste ist aktuell, es wurden keine neuen Sender bei Wunschliste gefunden."
                        )
                        self.session.open(
                            MessageBox,
                            "Die SerienRecorder Senderliste ist aktuell,\nes wurden keine neuen Sender bei Wunschliste gefunden.",
                            MessageBox.TYPE_INFO,
                            timeout=10)
                        self.showChannels()
                    else:
                        newChannelsMessage = "Folgende Sender wurden neu bei Wunschliste gefunden:\n" + "\n".join(
                            newWebChannels)
                        SRLogger.writeLog(newChannelsMessage, True)
                        self.session.open(
                            MessageBox,
                            "Folgende Sender wurden neu bei Wunschliste gefunden,\nsie wurden am Ende der Liste eingefügt:\n\n"
                            + "\n".join(newWebChannels),
                            MessageBox.TYPE_INFO,
                            timeout=10)
                        channels = []
                        for webChannel in newWebChannels:
                            channels.append((webChannel, "", "", 0))
                            self.serienRecChannelList.append(
                                (webChannel, "", "", "0"))
                        self.database.addChannels(channels)

            else:
                print "[SerienRecorder] webChannel list leer."

            if len(self.serienRecChannelList) != 0:
                self.chooseMenuList.setList(
                    map(self.buildList, self.serienRecChannelList))
            else:
                print "[SerienRecorder] Fehler bei der Erstellung der SerienRecChlist."

        else:
            print "[SerienRecorder] get webChannel error."

        self['title'].setText("Wunschliste-Sender / STB-Sender")

    @staticmethod
    def getMissingWebChannels(webChannels, dbChannels):
        added = []
        removed = []

        dbWebChannels = [x[0] for x in dbChannels]

        # append missing (new) channels
        for webChannel in webChannels:
            if webChannel not in [
                    dbWebChannel for dbWebChannel in dbWebChannels
            ]:
                added.append(webChannel.encode('utf-8'))

        # append removed channels
        for dbWebChannel in dbWebChannels:
            if dbWebChannel not in [webChannel for webChannel in webChannels]:
                removed.append(dbWebChannel)

        return added, removed

    @staticmethod
    def getUnassignedWebChannels(dbChannels):
        result = []

        #append unassigned
        for x in dbChannels:
            if not x[1]:
                result.append(x[0])

        return result

    def findWebChannelInSTBChannels(self, webChannel):
        result = (None, None)
        channelFound = False

        # First try to find the HD version
        webChannelHD = webChannel + " HD"
        for servicename, serviceref in self.stbChannelList:
            self.sequenceMatcher.set_seqs(webChannelHD.lower(),
                                          servicename.lower())
            ratio = self.sequenceMatcher.ratio()
            if ratio >= 0.98:
                result = (servicename, serviceref)
                channelFound = True
                break

        if not channelFound:
            for servicename, serviceref in self.stbChannelList:
                self.sequenceMatcher.set_seqs(webChannel.lower(),
                                              servicename.lower())
                ratio = self.sequenceMatcher.ratio()
                if ratio >= 0.98:
                    result = (servicename, serviceref)
                    break

        return result

    @staticmethod
    def buildList(entry):
        from SerienRecorder import serienRecMainPath
        (webSender, stbSender, altstbSender, status) = entry
        if int(status) == 0:
            imageStatus = "%simages/minus.png" % serienRecMainPath
        else:
            imageStatus = "%simages/plus.png" % serienRecMainPath

        return [
            entry,
            (eListboxPythonMultiContent.TYPE_PIXMAP_ALPHATEST, 10,
             7 * skinFactor, 16 * skinFactor, 16 * skinFactor,
             loadPNG(imageStatus)),
            (eListboxPythonMultiContent.TYPE_TEXT, 40 * skinFactor, 0,
             300 * skinFactor, 26 * skinFactor, 0,
             RT_HALIGN_LEFT | RT_VALIGN_CENTER, webSender),
            (eListboxPythonMultiContent.TYPE_TEXT, 350 * skinFactor, 0,
             250 * skinFactor, 26 * skinFactor, 0,
             RT_HALIGN_LEFT | RT_VALIGN_CENTER, stbSender),
            (eListboxPythonMultiContent.TYPE_TEXT, 600 * skinFactor, 0,
             250 * skinFactor, 26 * skinFactor, 0,
             RT_HALIGN_LEFT | RT_VALIGN_CENTER, altstbSender,
             parseColor('yellow').argb())
        ]

    @staticmethod
    def buildList_popup(entry):
        (servicename, serviceref) = entry
        return [
            entry,
            (eListboxPythonMultiContent.TYPE_TEXT, 5, 1, 250 * skinFactor,
             25 * skinFactor, 0, RT_HALIGN_LEFT | RT_VALIGN_CENTER,
             servicename)
        ]

    def keyOK(self):
        if self['list'].getCurrent() is None:
            print "[SerienRecorder] Sender-Liste leer."
            return

        if self.modus == "list":
            self.modus = "popup_list"
            self['popup_list'].show()
            self['popup_bg'].show()
            if config.plugins.serienRec.selectBouquets.value:
                self.stbChannelList = STBHelpers.buildSTBChannelList(
                    config.plugins.serienRec.MainBouquet.value)
            else:
                self.stbChannelList = STBHelpers.buildSTBChannelList()
            self.stbChannelList.insert(0, ("", ""))
            self.chooseMenuList_popup.setList(
                map(self.buildList_popup, self.stbChannelList))
            idx = 0
            (stbChannel, altstbChannel) = self.database.getSTBChannel(
                self['list'].getCurrent()[0][0])
            if stbChannel:
                try:
                    idx = zip(*self.stbChannelList)[0].index(stbChannel)
                except:
                    pass
            self['popup_list'].moveToIndex(idx)
            self['title'].setText("Standard STB-Sender für %s:" %
                                  self['list'].getCurrent()[0][0])
        elif config.plugins.serienRec.selectBouquets.value:
            if self.modus == "popup_list":
                self.modus = "popup_list2"
                self['popup_list'].hide()
                self['popup_list2'].show()
                self['popup_bg'].show()
                self.stbChannelList = STBHelpers.buildSTBChannelList(
                    config.plugins.serienRec.AlternativeBouquet.value)
                self.stbChannelList.insert(0, ("", ""))
                self.chooseMenuList_popup2.setList(
                    map(self.buildList_popup, self.stbChannelList))
                idx = 0
                (stbChannel, altstbChannel) = self.database.getSTBChannel(
                    self['list'].getCurrent()[0][0])
                if stbChannel:
                    try:
                        idx = zip(*self.stbChannelList)[0].index(altstbChannel)
                    except:
                        pass
                self['popup_list2'].moveToIndex(idx)
                self['title'].setText("alternativer STB-Sender für %s:" %
                                      self['list'].getCurrent()[0][0])
            else:
                self.modus = "list"
                self['popup_list'].hide()
                self['popup_list2'].hide()
                self['popup_bg'].hide()

                check = self['list'].getCurrent()
                if check is None:
                    print "[SerienRecorder] Sender-Liste leer (list)."
                    return

                check = self['popup_list'].getCurrent()
                if check is None:
                    print "[SerienRecorder] Sender-Liste leer (popup_list)."
                    return

                chlistSender = self['list'].getCurrent()[0][0]
                stbSender = self['popup_list'].getCurrent()[0][0]
                stbRef = self['popup_list'].getCurrent()[0][1]
                altstbSender = self['popup_list2'].getCurrent()[0][0]
                altstbRef = self['popup_list2'].getCurrent()[0][1]
                print "[SerienRecorder] select:", chlistSender, stbSender, stbRef, altstbSender, altstbRef
                channels = []
                if stbSender != "" or altstbSender != "":
                    channels.append(
                        (stbSender, stbRef, altstbSender, altstbRef, 1,
                         chlistSender.lower()))
                else:
                    channels.append(
                        (stbSender, stbRef, altstbSender, altstbRef, 0,
                         chlistSender.lower()))
                self.database.updateChannels(channels, True)
                self.changesMade = True
                self['title'].setText("Sender zuordnen")
                self.showChannels()
        else:
            self.modus = "list"
            self['popup_list'].hide()
            self['popup_list2'].hide()
            self['popup_bg'].hide()

            if self['list'].getCurrent() is None:
                print "[SerienRecorder] Sender-Liste leer (list)."
                return

            if self['popup_list'].getCurrent() is None:
                print "[SerienRecorder] Sender-Liste leer (popup_list)."
                return

            chlistSender = self['list'].getCurrent()[0][0]
            stbSender = self['popup_list'].getCurrent()[0][0]
            stbRef = self['popup_list'].getCurrent()[0][1]
            print "[SerienRecorder] select:", chlistSender, stbSender, stbRef
            channels = []
            if stbSender != "":
                channels.append((stbSender, stbRef, 1, chlistSender.lower()))
            else:
                channels.append((stbSender, stbRef, 0, chlistSender.lower()))
            self.database.updateChannels(channels)
            self.changesMade = True
            self['title'].setText("Sender zuordnen")
            self.showChannels()

    def keyRed(self):
        if self['list'].getCurrent() is None:
            print "[SerienRecorder] Sender-Liste leer."
            return

        if self.modus == "list":
            chlistSender = self['list'].getCurrent()[0][0]
            sender_status = self['list'].getCurrent()[0][2]
            print sender_status

            self.database.changeChannelStatus(chlistSender)
            self['title'].instance.setForegroundColor(parseColor("red"))
            self['title'].setText("")
            self['title'].setText("Sender '- %s -' wurde geändert." %
                                  chlistSender)

            self.changesMade = True
            self['title'].instance.setForegroundColor(parseColor("foreground"))
            self.showChannels()

    def keyGreen(self):
        self.session.openWithCallback(self.channelReset, MessageBox,
                                      "Senderliste aktualisieren?",
                                      MessageBox.TYPE_YESNO)

    def channelReset(self, execute):
        if execute:
            print "[SerienRecorder] channel-list reset..."
            SRLogger.writeLog("Senderliste wird aktualisiert...")

            if config.plugins.serienRec.selectBouquets.value:
                self.stbChannelList = STBHelpers.buildSTBChannelList(
                    config.plugins.serienRec.MainBouquet.value)
            else:
                self.stbChannelList = STBHelpers.buildSTBChannelList()
            self['title'].setText("Lade Wunschliste-Sender...")
            try:
                self.createWebChannels(SeriesServer().doGetWebChannels(),
                                       False)
                self.database.setChannelListLastUpdate()
            except:
                self['title'].setText(
                    "Fehler beim Laden der Wunschliste-Sender")
                SRLogger.writeLog(
                    "Fehler beim Laden der Senderliste vom SerienServer.",
                    True)
        else:
            print "[SerienRecorder] channel-list ok."

    def keyBlue(self):
        self.session.openWithCallback(
            self.autoMatch, MessageBox,
            "Es wird versucht, für alle nicht zugeordneten Wunschliste-Sender, einen passenden STB-Sender zu finden, dabei werden zunächst HD Sender bevorzugt.\n\nDies kann, je nach Umfang der Senderliste, einige Zeit (u.U. einige Minuten) dauern - bitte haben Sie Geduld!\n\nAutomatische Zuordnung jetzt durchführen?",
            MessageBox.TYPE_YESNO)

    def autoMatch(self, execute):
        if execute:
            if config.plugins.serienRec.selectBouquets.value:
                self.stbChannelList = STBHelpers.buildSTBChannelList(
                    config.plugins.serienRec.MainBouquet.value)
            else:
                self.stbChannelList = STBHelpers.buildSTBChannelList()
            self['title'].setText("Versuche automatische Zuordnung...")
            try:
                self.createWebChannels(SeriesServer().doGetWebChannels(), True)
            except:
                self['title'].setText(
                    "Fehler beim Laden der Wunschliste-Sender")

    def keyRedLong(self):
        check = self['list'].getCurrent()
        if check is None:
            print "[SerienRecorder] Serien Marker leer."
            return
        else:
            self.selected_sender = self['list'].getCurrent()[0][0]
            if config.plugins.serienRec.confirmOnDelete.value:
                self.session.openWithCallback(
                    self.channelDelete,
                    MessageBox,
                    "Soll '%s' wirklich entfernt werden?" %
                    self.selected_sender,
                    MessageBox.TYPE_YESNO,
                    default=False)
            else:
                self.channelDelete(True)

    def channelDelete(self, answer):
        if not answer:
            return
        self.database.removeChannel(self.selected_sender)
        self.changesMade = True
        self['title'].instance.setForegroundColor(parseColor("red"))
        self['title'].setText("Sender '- %s -' entfernt." %
                              self.selected_sender)
        self.showChannels()

    def resetChannelList(self):
        if config.plugins.serienRec.confirmOnDelete.value:
            self.session.openWithCallback(
                self.channelDeleteAll,
                MessageBox,
                "Sollen wirklich alle Senderzuordnungen entfernt werden?",
                MessageBox.TYPE_YESNO,
                default=False)
        else:
            self.channelDeleteAll(True)

    def channelDeleteAll(self, answer):
        if not answer:
            return
        self.database.removeAllChannels()
        self.changesMade = True
        self['title'].instance.setForegroundColor(parseColor("red"))
        self['title'].setText("Alle Senderzuordnungen entfernt.")
        self.showChannels()

    def keyLeft(self):
        self[self.modus].pageUp()

    def keyRight(self):
        self[self.modus].pageDown()

    def keyDown(self):
        self[self.modus].down()

    def keyUp(self):
        self[self.modus].up()

    def __onClose(self):
        self.stopDisplayTimer()

    def keyCancel(self):
        if self.modus == "popup_list":
            self.modus = "list"
            self['popup_list'].hide()
            self['popup_bg'].hide()
        elif self.modus == "popup_list2":
            self.modus = "list"
            self['popup_list2'].hide()
            self['popup_bg'].hide()
        else:
            if config.plugins.serienRec.refreshViews.value:
                self.close(self.changesMade)
            else:
                self.close(False)