web.py 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. from flask import Flask, render_template, make_response, request, g
  2. from bookworm import s3, constants
  3. import sqlite3
  4. import json
  5. import redis
  6. import os
  7. import re
  8. s3client = s3.client()
  9. app = Flask(__name__)
  10. r = redis.StrictRedis(host='localhost', port=6379, decode_responses=True)
  11. def dict_factory(cursor, row):
  12. d = {}
  13. for idx, col in enumerate(cursor.description):
  14. d[col[0]] = row[idx]
  15. return d
  16. def get_db():
  17. db = getattr(g, '_database', None)
  18. if db is None:
  19. db = sqlite3.connect('books.db')
  20. db.row_factory = dict_factory
  21. g._database = db
  22. return db
  23. @app.route('/books/status', methods=['GET'])
  24. def status_books():
  25. keys = r.keys(f'{constants.JOB_KEY_PREFIX}*')
  26. ret = {}
  27. for key in keys:
  28. val = r.hgetall(key)
  29. ret[key] = val
  30. return json.dumps(ret)
  31. def clean_book_name(book):
  32. cbr = re.compile(r'epub|azw3|mobi|\(v[0-9.]+\)')
  33. return cbr.sub('', book).rstrip('() .-')
  34. @app.route('/')
  35. def index():
  36. objects = s3client.list_objects_v2(Bucket=constants.BUCKET.PROCESSED_FILE)['Contents']
  37. objects = sorted(objects, key=lambda x: x['LastModified'], reverse=True)
  38. books = [(obj['Key'], clean_book_name(obj['Key'])) for obj in objects]
  39. return render_template('kindle-index.j2', books=books)
  40. @app.route('/book/<path:book>')
  41. def serve_books(book):
  42. obj = s3client.get_object(Bucket=constants.BUCKET.PROCESSED_FILE, Key=book)
  43. data = obj['Body'].read()
  44. response = make_response(data)
  45. response.headers.set('Content-Disposition', f'attachment; filename="{book}"')
  46. response.headers.set('Content-Length', len(data))
  47. _, ext = os.path.splitext(book)
  48. if ext == '.mobi':
  49. content_type = 'application/x-mobipocket-ebook'
  50. elif ext == '.azw3':
  51. content_type = 'application/x-mobi8-ebook'
  52. else:
  53. content_type = 'text/plain'
  54. response.headers.set('Content-Type', content_type)
  55. return response
  56. @app.route('/book/search', methods=['GET'])
  57. def search_books():
  58. terms = request.args.get('terms').split()
  59. cur = get_db().cursor()
  60. conditions = []
  61. for term in terms:
  62. condition = f"lower(book) like '%{term}%'"
  63. conditions.append(condition)
  64. all_conditions = ' AND '.join(conditions)
  65. rows = cur.execute('SELECT bot, book FROM books where %s LIMIT 100' % all_conditions)
  66. return json.dumps(list(rows))
  67. # books = db.fetchall('books',
  68. # fields=['bot', 'book'],
  69. # where=('lower(book) like all(%s)', [terms]),
  70. # limit=100)
  71. # return json.dumps([b._asdict() for b in books])
  72. @app.route('/book/fetch', methods=['POST'])
  73. def fetch_books():
  74. fetch = request.json
  75. data = {'command': f'!{fetch["bot"]} {fetch["book"]}',
  76. 'meta': {
  77. 'unpack_file_queue': constants.REDIS.Q_UNPACK_FILE,
  78. 'fetch_file_queue': constants.REDIS.Q_FETCH_FILE,
  79. 'raw_file_bucket': constants.BUCKET.RAW_FILE,
  80. 'processed_file_bucket': constants.BUCKET.PROCESSED_FILE,
  81. }
  82. }
  83. r.rpush(constants.REDIS.Q_BOOK_COMMANDS, json.dumps(data))
  84. return ''
  85. @app.route('/books/batch_update', methods=['POST'])
  86. def batch_update():
  87. fetch = request.json
  88. if fetch['secret_key'] != 'super_secret':
  89. return '401'
  90. batch_update_commands = ['@pondering42', '@dv8', '@shytot', '@dragnbreaker', '@Xon-new']
  91. for command in batch_update_commands:
  92. data = {'command': command,
  93. 'meta': {
  94. 'unpack_file_queue': constants.REDIS.Q_PROCESS_BATCH_FILE,
  95. 'fetch_file_queue': constants.REDIS.Q_FETCH_FILE,
  96. 'raw_file_bucket': constants.BUCKET.RAW_FILE,
  97. 'processed_file_bucket': constants.BUCKET.PROCESSED_FILE,
  98. }
  99. }
  100. r.rpush(constants.REDIS.Q_BOOK_COMMANDS, json.dumps(data))
  101. return ''
  102. def main():
  103. db = sqlite3.connect('books.db')
  104. c = db.cursor()
  105. sql = 'CREATE TABLE IF NOT EXISTS books (bot TEXT(40), book TEXT(200), size INT)'
  106. c.execute(sql)
  107. sql = 'CREATE UNIQUE INDEX IF NOT EXISTS books_unique ON books(bot, book)'
  108. c.execute(sql)
  109. db.commit()
  110. db.close()
  111. app.run(host='0.0.0.0', debug=True)
  112. if __name__ == '__main__':
  113. main()