Browse Source

add query_movie_json flask route

master
cinnaboot 7 years ago
parent
commit
7be03e5a77
  1. 122
      video_metadata/views/tmdb.py

122
video_metadata/views/tmdb.py

@ -12,7 +12,7 @@ from urllib.error import URLError, HTTPError
import urllib.parse import urllib.parse
import urllib.request import urllib.request
from flask import Blueprint, current_app, flash, Flask, request, render_template from flask import Blueprint, current_app, flash, Flask, jsonify, request, render_template, Response
from .. import util from .. import util
from .. import db from .. import db
@ -73,6 +73,18 @@ class view_result:
poster_path: str = 'no_image.png' poster_path: str = 'no_image.png'
tmdb_link: str = '' tmdb_link: str = ''
# NOTE: haven't found a better way to json encode dataclasses :(
class result_encoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, view_result):
return obj.__dict__
try:
ret = json.JSONEncoder.default(self, obj)
except TypeError:
return ''
return ret
#################### ####################
# flask routes # flask routes
@ -102,11 +114,11 @@ def list_movie_test():
url_prefix = current_app.config['VIDEO_URL_PREFIX'] url_prefix = current_app.config['VIDEO_URL_PREFIX']
) )
@bp.route('/query_movie', methods=['GET', 'POST']) @bp.route('/query_movie', methods=['GET', 'POST'])
def query_movie(): def query_movie():
errors = [] errors = []
query = query_data() query = query_data()
response = response_data()
view_results = [] view_results = []
# NOTE: query string can be submitted from a link or form input # NOTE: query string can be submitted from a link or form input
@ -118,32 +130,9 @@ def query_movie():
query.raw_query_str = request.args['query'] query.raw_query_str = request.args['query']
query.rel_path = request.args['rel_path'] query.rel_path = request.args['rel_path']
# TODO: if query_obj.query_type is still 'UNKNOWN' from parseQueryStr(), make queries to q_res = doQueryAlgorithm(query)
# both tmdb endpoints (movie and tv) errors = q_res['errors']
if query.raw_query_str and parseQueryStr(query): view_results = q_res['results']
if isQueryCached(query.parsed_query_str):
view_results = makeLocalQuery(query)
else:
makeTMDBQuery(query, response)
try:
response.parsed_response = json.loads(response.response_body)
except json.JSONDecodeError as e:
view_data.errors.append(e)
if 'total_results' in response.parsed_response:
response.result_count = response.parsed_response['total_results']
# TODO: it's possible for the query results to span multiple 'pages'
# see) https://developers.themoviedb.org/3/search/search-movies
if 'results' in response.parsed_response:
for result in response.parsed_response['results']:
view_results.append(parseTMDBResult(result, query.query_type))
storeTMDBQueryResults(query, view_results)
errors.extend(query.errors)
errors.extend(response.errors)
if errors: if errors:
view_results.clear() view_results.clear()
@ -155,14 +144,40 @@ def query_movie():
'tmdb/query.html', 'tmdb/query.html',
view_data = view_results, view_data = view_results,
rel_path = query.rel_path, rel_path = query.rel_path,
debug_str = '{} \n {} \n {} \n'.format( debug_str = '{} \n {} \n'.format(
util.dumpObject(query), util.dumpObject(query),
util.dumpObject(response),
util.dumpObject(view_results) util.dumpObject(view_results)
) )
) )
@bp.route('/query_movie_json')
def query_movie_json():
query = query_data()
results = []
if 'query' in request.args and 'rel_path' in request.args:
query.raw_query_str = request.args['query']
query.rel_path = request.args['rel_path']
q_res = doQueryAlgorithm(query)
errors = q_res['errors']
results = q_res['results']
current_app.logger.debug(f'{util.getFunctionName()}, results length: {len(results)}')
else:
errors = ['required parameters: query, rel_path']
if errors:
for e in errors:
current_app.logger.error(e)
return jsonify(errors=errors)
res = Response(json.dumps(results, cls=result_encoder))
res.headers.set('Content-Type', 'application/json')
return res
# TODO: add option for tv shows # TODO: add option for tv shows
# TODO: this endpoint should be http POST only
@bp.route('/create_mapping') @bp.route('/create_mapping')
def create_mapping(): def create_mapping():
movie_id = request.args.get('movie_id') movie_id = request.args.get('movie_id')
@ -197,6 +212,41 @@ def create_mapping():
################### ###################
# helpers # helpers
def doQueryAlgorithm(query:query_data) -> list:
errors, view_results = [], []
response = response_data()
# TODO: if query_obj.query_type is still 'UNKNOWN' from parseQueryStr(), make queries to
# both tmdb endpoints (movie and tv)
if query.raw_query_str and parseQueryStr(query):
if isQueryCached(query.parsed_query_str):
view_results = makeLocalQuery(query)
current_app.logger.debug(f'{util.getFunctionName()}, view_results length: {len(view_results)}')
else:
makeTMDBQuery(query, response)
try:
response.parsed_response = json.loads(response.response_body)
except json.JSONDecodeError as e:
errors.append(e)
if 'total_results' in response.parsed_response:
response.result_count = response.parsed_response['total_results']
# TODO: it's possible for the query results to span multiple 'pages'
# see) https://developers.themoviedb.org/3/search/search-movies
if 'results' in response.parsed_response:
for result in response.parsed_response['results']:
view_results.append(parseTMDBResult(result, query.query_type))
storeTMDBQueryResults(query, view_results)
errors.extend(query.errors)
errors.extend(response.errors)
return {'errors': errors, 'results': view_results}
# TODO: need a way to correctly parse titles like: "2001: A Space Odyssey (1968)" # TODO: need a way to correctly parse titles like: "2001: A Space Odyssey (1968)"
# with legitimate dates in the title # with legitimate dates in the title
def parseQueryStr(query_obj): def parseQueryStr(query_obj):
@ -225,16 +275,19 @@ def parseQueryStr(query_obj):
return True return True
def isQueryCached(query_str): def isQueryCached(query_str):
conn = db.get_db() conn = db.get_db()
cur = conn.cursor() cur = conn.cursor()
cur.execute('SELECT COUNT(*) FROM movie_queries WHERE query=?', (query_str,)) cur.execute('SELECT COUNT(*) FROM movie_queries WHERE query=?', (query_str,))
count = cur.fetchone()[0] count = cur.fetchone()[0]
current_app.logger.debug(
current_app.logger.debug('movie_queries count: "{}, query: {}"'.format(count, query_str)) f'{util.getFunctionName()}, movie_queries count: {count}, query: "{query_str}"'
)
return (count > 0) return (count > 0)
# NOTE: returns list of 'view_result' objects that match the query_obj.parsed_query_str # NOTE: returns list of 'view_result' objects that match the query_obj.parsed_query_str
# stored in the local db cache # stored in the local db cache
def makeLocalQuery(query_obj): def makeLocalQuery(query_obj):
@ -256,6 +309,7 @@ def makeLocalQuery(query_obj):
return results return results
def buildViewResult(db_row): def buildViewResult(db_row):
vr = view_result() vr = view_result()
vr.id = db_row['movie_id'] vr.id = db_row['movie_id']
@ -270,6 +324,8 @@ def buildViewResult(db_row):
return vr return vr
# TODO: add info and debug logging for network requests
def makeTMDBQuery(query_obj, response_obj): def makeTMDBQuery(query_obj, response_obj):
if query_obj.query_type == query_type.MOVIE: if query_obj.query_type == query_type.MOVIE:
search_part = TMDB_SEARCH_MOVIE search_part = TMDB_SEARCH_MOVIE
@ -319,6 +375,7 @@ def makeTMDBQuery(query_obj, response_obj):
return True return True
# NOTE: @param result is parsed JSON object from tmdb API # NOTE: @param result is parsed JSON object from tmdb API
def parseTMDBResult(result, query_type): def parseTMDBResult(result, query_type):
parsed = view_result() parsed = view_result()
@ -338,6 +395,7 @@ def parseTMDBResult(result, query_type):
return parsed return parsed
def storeTMDBQueryResults(query_obj, result_list): def storeTMDBQueryResults(query_obj, result_list):
conn = db.get_db() conn = db.get_db()
cur = conn.cursor() cur = conn.cursor()

Loading…
Cancel
Save