def cleanDB(): if config.use_database: logger.info(u"Cleaning database...") db.checkDB() myDB = db.DBConnection() if config.clean_uncomplete_only: reslut = myDB.select("SELECT * from scrobble where process < {0}".format(config.min_progress)) else: reslut = myDB.select("SELECT * from scrobble") if reslut: counter=0 for item in reslut: filename = os.path.split(item["thepath"])[1] thedate = datetime.datetime.fromtimestamp(float(item["lastviewed"])) timedelta = thedate + datetime.timedelta(weeks=8) if timedelta < datetime.datetime.now(): counter=counter+1 logger.debug(u"Deleting {0} from database because lastviewed more than 8 weeks ago".format(filename)) myDB.action("DELETE from scrobble where id = {0}".format(item["id"])) logger.info(u"removed {0} old entrys from databse".format(counter)) else: logger.info(u"no need to clean database for now")
def getProcess(length, viewed): length = durationStamps(length) viewed = durationStamps(viewed) try: percent = int(viewed) / (int(length) / 100) except: percent = 0 logger.debug(u"Duration: {0}s, Viewed: {1}s = {2}% watched".format(length, viewed, percent)) if percent > 100: percent=100 return percent
def durationStamps(time): try: h, m, s = time.split(":") timestamp = int(h*60) timestamp = (timestamp + int(m))*60 timestamp = (timestamp + int(s)) logger.debug(u"timestamp for: {0} is {1}".format(time, timestamp)) except: timestamp = time logger.debug(u"{0} seems to be a timestamp already".format(time)) return timestamp
def checkIMDB(filename): filename = filename + ".imdb" if os.path.exists(filename): f = open(filename, "r") imdb_id = f.read() f.close() logger.info(u"found a imdb file with the ID: {0}".format(imdb_id)) return imdb_id else: logger.debug(u"no imdb file found for: {0}".format(filename)) return None
def sendRequest(mediaelement): if mediaelement["process"] < config.min_progress and mediaelement["process"] > 7: response = watching(mediaelement) elif mediaelement["process"] < 7: logger.info(u"not scrobbleing because progress is lower than 7%") response = "not scrobbleing because progress is lower than 7%" else: response = scrobble(mediaelement) if not response: logger.debug(u"Scrobble failed, trying to mark as seen manually...") response = seen(mediaelement) return response
def _notifyBoxcar(self, title, message=None, username=None, force=False): if not config.use_boxcar and not force: logger.debug("Notification for Boxcar not enabled, skipping this notification") return False if not username: username = config.boxcar_username logger.debug("Sending notification for {0}".format(message)) self._sendBoxcar(message, title, username) return True
def buildMediaElement(mediaelement, theid): #check if given id is already in Database and get the lastviewed value to compare if its the same entry. if mediaelement: logger.info(u"processing file: {0}".format(mediaelement["thepath"])) logger.debug(u"mediatype: {0}, directory: {1}".format(mediaelement["type"], mediaelement["directory"])) mediaelement["id"] = theid mediaelement["duration"] = helper.getVideoDuration(theid) mediaelement["viewed"], mediaelement["lastviewed"] = getDurationFromLog(theid) mediaelement["process"] = helper.getProcess(mediaelement["duration"], mediaelement["viewed"]) #quit here if process is not enough... (saves time) # if int(mediaelement["process"]) < int(config.min_progress): # logger.error(u"File with the ID: {0}, has been viewed {1}% we need at least {2}%... skipping it".format(mediaelement["id"], mediaelement["process"], config.min_progress)) # return None # else: #currently only used for movies... idk if its possible to scrobble this for series. #mediaelement["lastviewedstamp"] = calendar.timegm(mediaelement["lastviewed"].timetuple()) mediaelement["lastviewedstamp"] = time.mktime(mediaelement["lastviewed"].timetuple()) #generate timestamp from lastviewed (datetime obj) #d = datetime.datetime.now() #calendar.timegm(d.timetuple()) #timestamp is needed for scrobbling last viewed date and to save it in database... #generate datetime from timestamp #datetime.datetime.utcfromtimestamp(1341237828) #handling for mediatype series if mediaelement["type"] == "series": try: mediaelement["tvdb_id"], mediaelement["name"] = helper.checkNFO(mediaelement["thepath"], "series") mediaelement["season"], mediaelement["episode"] = helper.checkNFO(mediaelement["thepath"], "episode") except: logger.error(u"Could not create {0} MediaElement".format(mediaelement["type"])) return None #handling for mediatype movies if mediaelement["type"] == "movie": try: mediaelement["name"], mediaelement["imdb_id"], mediaelement["year"], mediaelement["hasnfo"] = helper.checkNFO(mediaelement["thepath"], "movie") except: logger.error(u"Could not create {0} MediaElement".format(mediaelement["type"])) return None #log the created mediaobject in debug mode logger.debug(u"MediaElement successfully created: {0}".format(mediaelement)) #insert created infos in database if activated if config.use_database: helper.mediaelementToDatabase(mediaelement) return mediaelement else: logger.error(u"File with the ID: {0} seems not to be a media file that i currently support") return None
def send(action, postdata, mediaelement): url = "http://api.trakt.tv/{0}/{1}".format(action, config.trakt_key) try: logger.info(u"Sending infos for {0} \"{1}\" to trakt".format(mediaelement["type"], mediaelement["name"])) except: logger.info(u"Sending infos to trakt") logger.debug(u"Sending infos to trakt: URL: {0}, Data: {1}".format(url, postdata)) try: request = urllib2.Request(url, json.dumps(postdata)) response = urllib2.urlopen(request) response = response.read() response = json.loads(response) except urllib2.HTTPError, e: response = {'status' : 'failure', 'error' : responses[e.code][1]}
def _sendBoxcar(self, msg, title, email, subscribe=False): msg = msg.strip() curUrl = API_URL data = urllib.urlencode({ 'email': email, 'notification[from_screen_name]': title, 'notification[message]': msg.encode('utf-8'), 'notification[from_remote_service_id]': int(time.time()) }) if subscribe: # subscription notification data = urllib.urlencode({'email': email}) curUrl = curUrl + "/subscribe" req = urllib2.Request(curUrl) try: handle = urllib2.urlopen(req, data) handle.close() except urllib2.URLError, e: if not hasattr(e, 'code'): logger.error("Boxcar notification failed. {0}".format(ex(e))) return False else: logger.warning("Boxcar notification failed. Error code: {0}".format(str(e.code))) if e.code == 404: #HTTP status 404 if the provided email address isn't a Boxcar user. logger.warning("Username is wrong/not a boxcar email. Boxcar will send an email to it") return False elif e.code == 401: #For HTTP status code 401's, it is because you are passing in either an invalid token, or the user has not added your service. if subscribe: #If the user has already added your service, we'll return an HTTP status code of 401. logger.error("Already subscribed to service") # i dont know if this is true or false ... its neither but i also dont know how we got here in the first place return False else: #HTTP status 401 if the user doesn't have the service added subscribeNote = self._sendBoxcar(msg, title, email, True) if subscribeNote: logger.debug("Subscription send") return True else: logger.error("Subscription could not be send") return False elif e.code == 400: #If you receive an HTTP status code of 400, it is because you failed to send the proper parameters logger.error("Wrong data send to boxcar") return False
def tmdbsearch(searchstring): logger.debug(u"searchstring: {0}".format(searchstring)) if searchstring[:2] == "tt": movieinfo = tmdb.getMovieInfo('{0}'.format(searchstring)) else: results = tmdb.search(searchstring) if results: firstresult = results[0] movieinfo = firstresult.info() else: #search again for movie without the year searchstring = re.sub(" \([0-9]{4}\)", "", searchstring) results = tmdb.search(searchstring) if results: firstresult = results[0] movieinfo = firstresult.info() else: logger.error(u"Can't find any matches for {0}: {1}".format(nfotype, searchstring)) imdb_id = movieinfo["imdb_id"] title = movieinfo["original_name"] logger.info(u"Found result for {0} -> Fullname: {1} imdb_id: {2}".format(searchstring, title, imdb_id)) return title, imdb_id
def getDurationFromLog(id): dates = idtimes[id] startdate = dates[1] enddade = dates[-1] duration = enddade - startdate logger.debug(u"Fileid: " + str(id)) logger.debug(u"Duration: " + str(duration)) h, m, s = str(duration).split(":") time = int(h)*60 time = (time + int(m))*60 time = (time + int(s)) logger.debug(u"Duration Timestamp: {0}".format(time)) logger.debug(u"Last viewed: {0}, for: {1}".format(enddade, duration)) return time, enddade
def action(self, query, args=None): with db_lock: if query == None: return sqlResult = None attempt = 0 while attempt < 5: try: if args == None: logger.debug("{0}: {1}".format(self.filename, query)) #print query sqlResult = self.connection.execute(query) else: logger.debug("{0}: {1} with args {2}".format(self.filename, query, args)) #print query, args sqlResult = self.connection.execute(query, args) self.connection.commit() # get out of the connection attempt loop since we were successful break except sqlite3.OperationalError, e: if "unable to open database file" in e.message or "database is locked" in e.message: logger.warning(u"DB error: ".format(ex(e))) #print "error(e)" attempt += 1 time.sleep(1) else: logger.error(u"DB error: ".format(ex(e))) #print "error(e)" raise except sqlite3.DatabaseError, e: logger.error(u"Fatal error executing query: ".format(ex(e))) #print "error(e)" raise
def getDurationFromLog(theid): dates = idtimes[theid] startdate = dates[0] try: enddate = dates[-1] except: enddate = startdate duration = enddate - startdate logger.debug(u"Fileid: " + str(theid)) logger.debug(u"Viewed: " + str(duration)) h, m, s = str(duration).split(":") time = int(h)*60 time = (time + int(m))*60 time = (time + int(s)) logger.debug(u"Viewed Timestamp: {0}".format(time)) logger.debug(u"Last viewed: {0}, for: {1}".format(enddate, duration)) return time, enddate
def checkNFO(filepath, nfotype): hasnfo = False #check the nfo for the needed id stuff... #check if there is an nfo file... if not, f**k it and try to get infos from tvdb... if nfotype == "series": directory = os.path.dirname(filepath) directory = re.sub(r'Staffel \d{2}|Season \d{2}', '', directory) nfofile = os.path.join(directory, "tvshow.nfo") try: dom = parse(nfofile) seriesidTag = dom.getElementsByTagName('id')[0].toxml() seriesid=seriesidTag.replace('<id>','').replace('</id>','') try: nameTag = dom.getElementsByTagName('showtitle')[0].toxml() name=nameTag.replace('<showtitle>','').replace('</showtitle>','') except: nameTag = dom.getElementsByTagName('title')[0].toxml() name=nameTag.replace('<title>','').replace('</title>','') logger.debug(u"SeriesID for {0} is: {1}".format(name, seriesid)) return seriesid, name except: #TODO: fix some unicode errors here... logger.error(u"cant find/open file: {0}".format(nfofile)) if config.try_guessing: logger.info(u"Trying to guess infos from Filename...") seriesname = os.path.basename(filepath) p = re.match(seriesregex, seriesname) name = p.group("name").replace(".", " ").strip() season = p.group("season") episode = p.group("episode") logger.debug(u"Type: {3}, Name: {0}, Season: {1}, Episode: {2}".format(name, season, episode, nfotype)) t = tvdb_api.Tvdb() showinfo = t[name] tvdb_id = showinfo["id"] realname = showinfo["seriesname"] year = showinfo["firstaired"] #logger.debug("tvdb gave the following keys: {0}".format(showinfo.data.keys())) logger.info(u"Found result for {0} -> Fullname: {1}, tvdb_id: {2}, Year: {3}".format(seriesname, realname, tvdb_id, year)) return tvdb_id, realname else: logger.error(u"Please enable try_guessing in settings or create an tvshow.nfo for: {0}".format(directory)) return 0 if nfotype == "episode": filename, extension = os.path.splitext(filepath) nfofile = filename + ".nfo" try: dom = parse(nfofile) episodeTag = dom.getElementsByTagName('episode')[0].toxml() episode=episodeTag.replace('<episode>','').replace('</episode>','') seasonTag = dom.getElementsByTagName('season')[0].toxml() season=seasonTag.replace('<season>','').replace('</season>','') episodeTag = dom.getElementsByTagName('episode')[0].toxml() episode=episodeTag.replace('<episode>','').replace('</episode>','') logger.info(u'TVSHOW info -> Season: {0}, Episode: {1}'.format(season, episode)) return season, episode except: logger.error(u"Cant find/open/parse file: {0}".format(nfofile)) if config.try_guessing: logger.info(u"try to guess infos from Filename...") seriesname = os.path.basename(filepath) p = re.match(seriesregex, seriesname) name = p.group("name").replace(".", " ").strip() season = p.group("season") episode = p.group("episode") logger.debug(u"Type: {3}, Series: {0}, Season: {1}, Episode: {2}".format(seriesname, season, episode, nfotype)) return season, episode else: logger.error(u"Please enable try_guessing in settings or create an .nfo for: {0}".format(directory)) return 0 if nfotype == "movie": #order of use: .nfo, .imdb, try_guessing filename, extension = os.path.splitext(filepath) nfofile = filename + ".nfo" if os.path.exists(nfofile): hasnfo = True try: dom = parse(nfofile) tvdb_idtag = dom.getElementsByTagName('id')[0].toxml() tvdb_id=tvdb_idtag.replace('<id>','').replace('</id>','') nametag = dom.getElementsByTagName('title')[0].toxml() name=nametag.replace('<title>','').replace('</title>','') if name[:4].lower() in config.the_srings: name = name[4:] + ', ' + name[:4].strip() yeartag = dom.getElementsByTagName('year')[0].toxml() year=yeartag.replace('<year>','').replace('</year>','') logger.info(u'Movie info -> Name: {0}, Year: {1}, imdb_id: {2}'.format(name, year, tvdb_id)) return name, tvdb_id, year except: logger.error(u"Cant find/open file: {0}".format(nfofile)) imdbcheck = checkIMDB(filename) if imdbcheck: searchstring = imdbcheck else: searchstring = None #only use try_guessing if there was no imdb file... if config.try_guessing and not searchstring: logger.info(u"try to guess infos from Filename...") try: moviename = os.path.basename(filepath) for junk in config.removejunk: moviename = moviename.replace(junk,'') p = re.match(movieregex, moviename) name = p.group("name").replace("."," ").replace("-"," ").strip() if name[:4].lower() in config.the_srings: name = name[4:] + ', ' + name[:4].strip() year = p.group("year") searchstring = "{0} ({1})".format(name, year) except: moviename = os.path.dirname(filepath) for junk in config.removejunk: moviename = moviename.replace(junk,'') directory, moviename = os.path.split(moviename) p = re.match(movieregex, moviename) name = p.group("name").replace("."," ").strip() year = p.group("year") searchstring = "{0} ({1})".format(name, year) logger.debug(u"Type: {3}, Name: {0}, Year: {1}, Searchstring: {2}".format(name, year, searchstring, nfotype)) #we need imdb id for scrobbleing to trakt, so lets make a moviedb lookup here to get these infos (especially if there is no year in the name....) #this ALWAYS uses the first resault that comes from tmdb... else: logger.error(u"Please enable try_guessing in settings or create an .nfo for: {0}".format(filepath)) return 0 if searchstring: title, imdb_id = tmdbsearch(searchstring) return title, imdb_id, year, hasnfo else: logger.error(u"Something went terrible wrong here...") return 0
# Insert local directories into path sys.path.insert(0, os.path.join(path, 'lib')) #TODO: cleanup! #check if debugmode is acitvated try: debugfile = open('/var/packages/MediaServer/etc/dmsinfo.conf') filelines = debugfile.readlines() debugfile.close() value = filelines[-1].replace("loglevel_mediaservice=\"","").replace("\"\n","") if int(value) < 3: logger.error(u"MediaServer not running in Debugmode!") sys.exit(u"Please enable Debugmode for MediaServer first!") else: logger.debug(u"MediaServer running in Debugmode") except: logger.error(u"Can't check if your MeidaServer runs in Debugmode or not...") def getDurationFromLog(theid): dates = idtimes[theid] startdate = dates[0] try: enddate = dates[-1] except: enddate = startdate duration = enddate - startdate logger.debug(u"Fileid: " + str(theid))
logger.error("Already subscribed to service") # i dont know if this is true or false ... its neither but i also dont know how we got here in the first place return False else: #HTTP status 401 if the user doesn't have the service added subscribeNote = self._sendBoxcar(msg, title, email, True) if subscribeNote: logger.debug("Subscription send") return True else: logger.error("Subscription could not be send") return False elif e.code == 400: #If you receive an HTTP status code of 400, it is because you failed to send the proper parameters logger.error("Wrong data send to boxcar") return False else:# 200 logger.debug("Boxcar notification successful.") return True def _notifyBoxcar(self, title, message=None, username=None, force=False): if not config.use_boxcar and not force: logger.debug("Notification for Boxcar not enabled, skipping this notification") return False if not username: username = config.boxcar_username logger.debug("Sending notification for {0}".format(message)) self._sendBoxcar(message, title, username) return True
logger.info(u"Sending infos for {0} \"{1}\" to trakt".format(mediaelement["type"], mediaelement["name"])) except: logger.info(u"Sending infos to trakt") logger.debug(u"Sending infos to trakt: URL: {0}, Data: {1}".format(url, postdata)) try: request = urllib2.Request(url, json.dumps(postdata)) response = urllib2.urlopen(request) response = response.read() response = json.loads(response) except urllib2.HTTPError, e: response = {'status' : 'failure', 'error' : responses[e.code][1]} #return None except urllib2.URLError, e: response = {'status' : 'failure', 'error' : e.reason[0]} #return None logger.debug("response: {0}".format(response)) if response['status'] == 'success': #create an nfo file for later use... # if not mediaelement["hasnfo"]: # helper.makeNFO(mediaelement) #marking the id as scrobbled inside the database... if not action.split("/")[-1] == "watching": if config.use_database: helper.markScrobbled(mediaelement["id"]) return True else: return None
def getSeries(filepath, curdir): myfilestring = filepath.replace(curdir,'') series, season, filename = myfilestring.split('/') logger.debug(u"Splitting {0} -> Series: {1}, Season: {2}, Filename: {3}".format(filepath, series, season, filename))