예제 #1
0
def snapshot(season_id, episode_id, ms):
    # Load PNG from database.
    cur = get_db().cursor()
    cur.execute(
        'SELECT png FROM snapshot'
        ' WHERE episode_id=:episode_id AND ms=:ms', {
            'episode_id': episode_id,
            'ms': ms
        })
    res = cur.fetchone()
    if res is None:
        flask.abort(404, 'time not found')
    image = Image.open(io.BytesIO(res['png']))

    # Draw text if requested.
    top_text = (b64decode(flask.request.args.get('topb64', '')).decode(
        'ascii', 'ignore'))
    bottom_text = (b64decode(flask.request.args.get('btmb64', '')).decode(
        'ascii', 'ignore'))
    if top_text != '' or bottom_text != '':
        drawtext(image, top_text, bottom_text)

    # Return as compressed JPEG.
    res = io.BytesIO()
    image.save(res, 'jpeg', quality=JPEG_QUALITY)
    return flask.Response(res.getvalue(), mimetype='image/jpeg')
예제 #2
0
def browse_episode(season_id, episode_id):
    cur = get_db().cursor()
    targs = {}

    # Retrieve season information.
    cur.execute('SELECT slug, icon_png, name FROM season WHERE id=:season_id',
                {'season_id': season_id})
    res = cur.fetchone()
    targs['season'] = res['slug']
    targs['season_name'] = res['name']
    targs['season_has_icon'] = res['icon_png'] is not None

    # Retrieve episode information.
    cur.execute('SELECT slug, name FROM episode WHERE id=:episode_id',
                {'episode_id': episode_id})
    res = cur.fetchone()
    targs['episode'] = res['slug']
    targs['episode_name'] = res['name']

    # Retrieve all subtitles.
    cur.execute(
        'SELECT start_ms, end_ms, snapshot_ms, content FROM subtitle '
        ' WHERE episode_id=:episode_id ORDER BY start_ms',
        {'episode_id': episode_id})
    res = cur.fetchall()
    if len(res) == 0:
        flask.abort(404, 'no subtitles found')
    targs['subtitles'] = res

    def str_ms(ms):
        return strftimecode(timedelta(milliseconds=ms))

    targs['str_ms'] = str_ms
    return flask.render_template('episode.html', **targs)
예제 #3
0
def search():
    query = flask.request.args.get('q')
    if query is None:
        query = ''

    query = unquote(query)
    query = re.sub(r'[^a-zA-Z0-9 \']', '', query)
    query = query[0:MAX_SEARCH_LENGTH]
    if query == '':
        return flask.render_template('search.html', query='')

    cur = get_db().cursor()
    cur.execute('PRAGMA full_column_names = ON')
    cur.execute(
        '    SELECT episode.slug, season.slug, search.snapshot_ms, search.content '
        '           FROM season '
        'INNER JOIN episode ON episode.season_id = season.id '
        'INNER JOIN (SELECT episode_id, snapshot_ms, content FROM subtitle_search '
        '             WHERE content MATCH :query LIMIT :n_results) search '
        '           ON search.episode_id = episode.id', {
            'query': ' '.join('"%s"' % term for term in query.split()),
            'n_results': N_SEARCH_RESULTS
        })
    results = cur.fetchall()
    return flask.render_template('search.html',
                                 query=query,
                                 results=results,
                                 n_results=len(results))
예제 #4
0
def check_time(episode_id, ms):
    cur = get_db().cursor()
    cur.execute(
        'SELECT ms FROM snapshot WHERE episode_id=:episode_id AND ms=:ms', {
            'episode_id': episode_id,
            'ms': ms
        })
    return cur.fetchone() is not None
예제 #5
0
def read_library_command():
    database.remove()
    db = database.get_db()
    with current_app.open_resource('schema.sql', mode='r') as f:
        db.cursor().executescript(f.read())
    db.commit()

    library_data = load_library_file(Path(current_app.config.get('LIBRARY')))
    database.populate(library_data)
예제 #6
0
def check_range(episode_id, ms1, ms2, max_length):
    if ms1 >= ms2 or ms1 < 0 or ms2 - ms1 > max_length.total_seconds() * 1000:
        return False
    else:
        cur = get_db().cursor()
        cur.execute('SELECT duration FROM episode WHERE id=:episode_id',
                    {'episode_id': episode_id})
        res = cur.fetchone()
        return (ms2 <= res['duration'] and check_time(episode_id, ms1)
                and check_time(episode_id, ms2))
예제 #7
0
def snapshot_tiny(season_id, episode_id, ms):
    cur = get_db().cursor()
    cur.execute(
        'SELECT jpeg FROM snapshot_tiny '
        ' WHERE episode_id=:episode_id AND ms=:ms', {
            'episode_id': episode_id,
            'ms': ms
        })
    res = cur.fetchone()
    if res is None:
        flask.abort(404, 'time not found')
    return flask.Response(res['jpeg'], mimetype='image/jpeg')
예제 #8
0
def webm(season_id, episode_id, ms1, ms2):
    if not check_range(episode_id, ms1, ms2,
                       flask.current_app.config.get('MAX_WEBM_LENGTH')):
        flask.abort(400, 'bad time range')

    cur = get_db().cursor()
    cur.execute('SELECT video_path FROM episode WHERE id=:episode_id',
                {'episode_id': episode_id})
    res = cur.fetchone()
    video_path = res['video_path']

    return flask.Response(ff.make_webm(video_path, ms1, ms2),
                          mimetype='video/webm')
예제 #9
0
def season_icon(season_id):
    cur = get_db().cursor()

    # Retrieve season information.
    cur.execute('SELECT icon_png FROM season WHERE id=:season_id',
                {'season_id': season_id})
    res = cur.fetchone()
    icon_data = res['icon_png']
    if icon_data is None:
        flask.abort(404, 'no icon available')

    # Return icon.
    response = flask.make_response(icon_data)
    response.headers.set('Content-Type', 'image/png')
    return response
예제 #10
0
def gif_with_subtitles(season_id, episode_id, ms1, ms2):
    if not check_range(episode_id, ms1, ms2,
                       flask.current_app.config.get('MAX_GIF_LENGTH')):
        flask.abort(400, 'bad time range')

    cur = get_db().cursor()
    cur.execute(
        'SELECT video_path, subtitles_path FROM episode WHERE id=:episode_id',
        {'episode_id': episode_id})
    res = cur.fetchone()
    video_path = res['video_path']
    subtitles_path = res['subtitles_path']

    return flask.Response(ff.make_gif_with_subtitles(video_path,
                                                     subtitles_path, ms1, ms2),
                          mimetype='image/gif')
예제 #11
0
def browse_season(season_id):
    cur = get_db().cursor()
    targs = {}

    # Retrieve season information.
    cur.execute('SELECT slug, icon_png, name FROM season WHERE id=:season_id',
                {'season_id': season_id})
    res = cur.fetchone()
    targs['season'] = res['slug']
    targs['season_name'] = res['name']
    targs['season_has_icon'] = res['icon_png'] is not None

    # Retrieve episodes.
    cur.execute(
        'SELECT slug, name, duration, snapshot_ms FROM episode '
        ' WHERE season_id=:season_id', {'season_id': season_id})
    targs['episodes'] = cur.fetchall()

    def str_ms(ms):
        return strftimecode(timedelta(milliseconds=ms))

    targs['str_ms'] = str_ms
    return flask.render_template('season.html', **targs)
예제 #12
0
def index():
    cur = get_db().cursor()
    cur.execute('SELECT slug, name FROM season')
    return flask.render_template('index.html', seasons=cur.fetchall())
예제 #13
0
def browse_moment(season_id, episode_id, ms):
    cur = get_db().cursor()
    targs = {'ms': ms}

    # Retrieve season information.
    cur.execute('SELECT slug, icon_png, name FROM season WHERE id=:season_id',
                {'season_id': season_id})
    res = cur.fetchone()
    targs['season'] = res['slug']
    targs['season_name'] = res['name']
    targs['season_has_icon'] = res['icon_png'] is not None

    # Retrieve episode information.
    cur.execute('SELECT slug, name FROM episode WHERE id=:episode_id',
                {'episode_id': episode_id})
    res = cur.fetchone()
    targs['episode'] = res['slug']
    targs['episode_name'] = res['name']

    # Locate relevant subtitles.
    cur.execute(
        'SELECT content, start_ms, end_ms, snapshot_ms FROM subtitle '
        ' WHERE episode_id=:episode_id '
        '       AND MIN(ABS(start_ms-:ms), ABS(end_ms-:ms))<=:ms_range', {
            'episode_id': episode_id,
            'ms': ms,
            'ms_range': CLOSE_SUBTITLE_SECS * 1000
        })
    subtitles = cur.fetchall()
    targs['subtitles'] = subtitles
    targs['current_line'] = next(
        map(
            lambda row: strip_html(row['content']),
            filter(lambda row: ms >= row['start_ms'] and ms <= row['end_ms'],
                   subtitles)), '')

    # Locate surrounding images.
    nav_list = [ms]
    cur.execute(
        '  SELECT ms FROM snapshot WHERE episode_id=:episode_id AND ms<:ms '
        'ORDER BY ms DESC LIMIT :steps', {
            'episode_id': episode_id,
            'ms': ms,
            'steps': NAV_STEPS
        })
    nav_list += [row['ms'] for row in cur.fetchall()]
    cur.execute(
        '  SELECT ms FROM snapshot WHERE episode_id=:episode_id AND ms>:ms '
        'ORDER BY ms ASC LIMIT :steps', {
            'episode_id': episode_id,
            'ms': ms,
            'steps': NAV_STEPS
        })
    nav_list += [row['ms'] for row in cur.fetchall()]
    nav_list.sort()
    targs['nav_list'] = nav_list

    def encode_text(content):
        return b64encode(strip_html(content).encode('utf-8'))

    targs['encode_text'] = encode_text
    return flask.render_template('moment.html', **targs)