def homepage(request): """homepage view for / on hdd-indexer Serves the homepage at root (/) with index.html Passes hdd_name, hdd_root, movie_folder, crawler_status Args: request(RequestContext) - passed by Django Returns: response(Response) - file template to serve Raises: None """ log.info('served homepage') return render( request, 'hdd_indexer/index.html', { 'hdd_name': HDDName.get_solo(), 'hdd_root': HDDRoot.get_solo(), 'movie_folder': path.join( HDDRoot.get_solo().path, MovieFolder.get_solo().relpath, ), 'crawler_status': crawler_status(), } )
def start_loader(): """Start the loader Starts the loader after checking hdd and movie folder are accessible. Args: None Returns: None Raises: None """ hdd_root = HDDRoot.get_solo().path if not path.exists(hdd_root): print _ERROR[1] return _ERROR[1] movie_folder = MovieFolder.get_solo().relpath if not path.exists(path.join(hdd_root, movie_folder)): print _ERROR[1] return _ERROR[2] loader_status('STATUS', True) thread = Thread(target=_run) thread.daemon = True thread.start()
def setup(request): """Setup for first-use """ if not request.POST: log.info('served setup page') return render( request, 'hdd_indexer/setup.html', { 'RegistrationKey': RegistrationKey.get_solo().key, 'hdd_name': HDDName.get_solo().name, 'hdd_root': HDDRoot.get_solo().path, 'movie_folder': MovieFolder.get_solo().relpath, 'opensub_id': OpenSubKey.get_solo().uid, 'opensub_key': OpenSubKey.get_solo().key, 'tmdb_key': TMDbKey.get_solo().key, 'error': False, 'err_msg': '', } ) error = False err_msg = 'Validation errors have been found: ' log.info('POST: preferences and settings in setup') # validations # registration key registration_key = request.POST.get('ID', '') if registration_key: # make sure that it is valid registration key registration_key_db = RegistrationKey.get_solo() registration_key_db.key = registration_key registration_key_db.save() log.info('registration key = %s saved to db' % registration_key) else: pass # hdd name hdd_name = request.POST.get('HDDName', '') pattern = re.compile(r'^[0-9a-zA-z_-]+$') if pattern.match(hdd_name): hdd_name_db = HDDName.get_solo() hdd_name_db.name = hdd_name hdd_name_db.save() log.info('hdd_name: %s saved to db' % hdd_name) else: error = True err_msg = ' '.join(((err_msg, 'HDD Name,'))) log.error('%s is not a valid hdd_name' % hdd_name) # hdd root hdd_root = request.POST.get('HDDRoot', '') if path.exists(hdd_root): hdd_root_db = HDDRoot.get_solo() hdd_root_db.path = hdd_root hdd_root_db.save() log.info('hdd_root = %s saved to db' % hdd_root) else: error = True err_msg = ' '.join(((err_msg, 'HDD Root,'))) log.error('%s is not a valid path' % hdd_root) # movie folder movie_folder = request.POST.get('MovieFolder', '') log.info('POST: movie_folder = %s' % movie_folder) if path.exists(movie_folder): movie_folder_db = MovieFolder.get_solo() movie_folder_db.relpath = movie_folder movie_folder_db.save() log.info('movie_folder = %s saved to db' % movie_folder) else: error = True err_msg = ' '.join((err_msg, 'Movie Folder,')) log.error('%s is not a valid path' % movie_folder) # tmdb key # TODO: check tmdb key is valid tmdb_key = request.POST.get('TMDB_KEY', '') log.info('POST: tmdb_key = %s' % tmdb_key) if len(tmdb_key) >= 5: tmdb_db = TMDbKey.get_solo() tmdb_db.key = tmdb_key tmdb_db.save() log.info('tmdb_key = %s saved to db' % tmdb_key) else: error = True err_msg = ' '.join(((err_msg, 'TMDb Key,'))) log.error('%s is not a valid tmdb_key' % tmdb_key) # opensub # TODO: check opensub key is valid opensub_id = request.POST.get('OpenSubID', '') opensub_key = request.POST.get('OpenSubKey', '') log.info('opensub id:%s key:%s' % (opensub_id, opensub_key)) if opensub_id and opensub_key: if len(opensub_id) >= 5 and len(opensub_key) >= 5: opensub_db = OpenSubKey.get_solo() opensub_db.uid = opensub_id opensub_db.key = opensub_key opensub_db.save() log.info('opensub id:%s key:%s saved to db' % ( opensub_id, opensub_key )) else: error = True err_msg = ' '.join((err_msg, 'OpenSubtitles ID and Key,')) log.info('opensub id:%s key:%s are not valid' % ( opensub_id, opensub_key )) if error is False: log.info('setup complete, redirected to welcome page') return render( request, 'hdd_indexer/help.html', { 'welcome': True, } ) log.error('setup input has errors, redirect to setup page') return render( request, 'hdd_indexer/setup.html', { 'RegistrationKey': RegistrationKey, 'hdd_name': hdd_name, 'hdd_root': hdd_root, 'movie_folder': movie_folder, 'opensub_id': opensub_id, 'opensub_key': opensub_key, 'tmdb_key': tmdb_key, 'error': error, 'err_msg': err_msg, } )
def settings(request): """settings view for / on hdd-indexer Validates settings sent using POST POST: hdd_name(str) hdd_root(str) movie_folder(str) Args: request(RequestContext) - passed by Django Returns: response(HttpResponse) - resposne to POST request Raises: None """ def response(d=True, v=True): """Response for POST methods returns a HTTPResponse with content type json Args: d(bool): POST success (JQuery done) v(bool): POST validation """ payload = { 'done': d, 'validation': v, } log.debug('settings validation: %s' % payload) return HttpResponse( json.dumps(payload), content_type='application/json' ) # if request is not POST, return error if request.method != 'POST': # 405: Method not allowed log.error('405: Method not allowed') return HttpResponse(status=405) # request for HDD Name if request.POST.get('hdd_name', None): hdd_name = request.POST['hdd_name'] log.info('POST: hdd_name: %s' % hdd_name) pattern = re.compile(r'^[0-9a-zA-z_-]+$') if pattern.match(hdd_name): try: hdd_name_db = HDDName.get_solo() hdd_name_db.name = hdd_name hdd_name_db.save() log.info('hdd_name = %s saved to db' % hdd_name) return response() except ValueError: return response(d=False, v=True) except TypeError: return response(d=False, v=False) except Exception as e: print e return response(d=False, v=False) else: log.error('%s is a not a valid hdd_name' % hdd_name) return response(d=False, v=True) # request for HDD Root elif request.POST.get('hdd_root', None): hdd_root = request.POST['hdd_root'] log.info('POST: hdd_root = %s' % hdd_root) if path.isdir(hdd_root): hdd_root_db = HDDRoot.get_solo() hdd_root_db.path = hdd_root hdd_root_db.save() log.info('hdd_root = %s saved to db' % hdd_root) return response() else: log.error('%s is not a valid path' % hdd_root) return response(d=False, v=True) # request for Movie Folder elif request.POST.get('movie_folder', None): movie_folder = request.POST['movie_folder'] log.info('POST: movie_folder = %s' % movie_folder) hdd_root = HDDRoot.get_solo().path if not movie_folder.startswith(hdd_root): log.error('movie_folder does not start with hdd_root') return response(d=False, v=True) if not path.isdir(movie_folder): log.error('movie_folder is not a valid path') return response(d=False, v=True) movie_folder = path.relpath(movie_folder, hdd_root) movie_folder_db = MovieFolder.get_solo() movie_folder_db.relpath = movie_folder movie_folder_db.save() log.info('movie_folder = %s saved to db' % movie_folder) return response(d=True) log.error('405: Method not allowed') return HttpResponse(status=405)
def _organize(criterion): """organize movies on disk/database by provided criterion Selects all movies and updates their filenames based on their metadata titles. Moves their files to organized folders whose name and hierarchy are based on criterion selected. Args: criterion(str): user choice of organization criterion Returns: None Raises: None """ def create_folder(folder): """ creates a folder if it does not exist Args: folder(str): path of the folder Returns: None Raises: None """ # TODO: check if path is valid if not path.exists(path.join(destination, folder)): log.info('created directory %s' % folder) makedirs(path.join(destination, folder)) # functions for selected criterion _get_folder, _field_exists = _criterion_tools(criterion) # temporary folder for holding created folders tempname = 'tmp' log.debug('temporary folder set to ./%s' % tempname) uncategorized = 'uncategorized' log.debug('uncategorized folder set to ./%s/%s' % ( tempname, uncategorized)) parentpath = path.join( HDDRoot.get_solo().path, MovieFolder.get_solo().relpath) destination = path.join(parentpath, tempname) create_folder(destination) movies = Movie.objects.all() for movie in movies: # parent folder for the movie file if _field_exists(movie): folder = _get_folder(movie) else: folder = uncategorized log.debug('folder: %s' % folder) create_folder(folder) # create new filename -> title with extension fname = make_fname(movie.title, movie.relpath) # move the file to its new location newpath = path.join( path.join(destination, folder), fname) oldpath = path.join(parentpath, movie.relpath) move(oldpath, newpath) log.debug('%s moved from %s to %s' % ( movie.title, movie.relpath, newpath)) # update movie path to the newpath movie.relpath = path.join(folder, fname) # save updated movie to database movie.save() # move other files from movie_folder to new folder other_files = path.join(destination, 'other_files') create_folder(other_files) for root, directory, files in walk(parentpath): # don't go into the temporary folder if not root.startswith(destination): for somefile in files: move( path.join(root, somefile), path.join(other_files, somefile)) log.info('moved other files into %s' % other_files) # remove all directories from movie folder for directory in walk(parentpath).next()[1]: if directory != tempname: rmtree(path.join(parentpath, directory)) log.info('removed all directories from movie folder') # move all new folders into movie folder directory for directory in walk(destination).next()[1]: move( path.join(destination, directory), path.join(parentpath, directory)) # delete temporary directory rmtree(destination) # update status of organizer organizer_status('STATUS', False)
def opensub(relpath): """OpenSubtitle identification of movie Uses the OpenSubtitles API to identify movie Args: relpath(str): relative path of movie file Returns: imdb_id(int): on success, returns idetified imdb id None: on failure Raises: None """ if 'sub' not in opensub.__dict__: sub = opensub_initiate() if sub: opensub.sub = sub token = sub.login( OpenSubKey.get_solo().uid, OpenSubKey.get_solo().key ) opensub.token = token opensub.lock = Lock() try: # login to opensub using API sub = opensub.sub token = opensub.token if not token: # return sub print 'null token' log.error('path: %s open sub null token' % relpath) return # check that the file is accessible if not path.exists(path.join( HDDRoot.get_solo().path, MovieFolder.get_solo().relpath, relpath, )): print "ERROR: " + relpath log.error('path: %s does not exist' % relpath) return f = File(path.join( HDDRoot.get_solo().path, MovieFolder.get_solo().relpath, relpath, )) if f is None: log.error('path: %s open sub file error' % relpath) return hash = f.get_hash() size = f.size with opensub.lock: data = sub.search_subtitles([{ 'sublanguageid': 'all', 'moviehash': hash, 'moviebytesize': size, }]) if type(data) is list: if data[0].get('IDMovieImdb', None): return data[0]['IDMovieImdb'] else: log.warning('%s opensub failed to identify movie' % relpath) except ProtocolError as e: # most likely network error or API server error print "E: " + str(e) except AssertionError: print 'Failed to authenticate opensubtitles login.' except ProtocolError as e: """ TODO: gaierror: [Errno 8] nodename nor servname provided, or not known """ if e.errcode == 503: # ProtocolError - 503 Service Unavailable print 'Check network connection and try again.' log.error('path: %s open sub error occured' % relpath) log.error(traceback.format_exc()) except Exception: log.error('path: %s open sub error occured' % relpath) log.error(traceback.format_exc())