# -*- coding: utf-8 -*-
from flask import Flask,render_template
from flask.ext.bootstrap import Bootstrap, WebCDN, ConditionalCDN, BOOTSTRAP_VERSION, JQUERY_VERSION, HTML5SHIV_VERSION, RESPONDJS_VERSION
from flask.ext.moment import Moment
from datetime import datetime
import sys

#py2 unicode
reload(sys)
sys.setdefaultencoding('utf-8')
app = Flask(__name__)
bootstrap = Bootstrap(app)
moment = Moment(app)

def change_cdn_domestic(tar_app):
    """
    中国特色 flask-bootstrap
    源码来自 新浪微博 @蛋-壳-酱 万分感谢！
    :param tar_app:
    :return:
    """
    static = tar_app.extensions['bootstrap']['cdns']['static']
    local = tar_app.extensions['bootstrap']['cdns']['local']

    def change_one(tar_lib, tar_ver, fallback):
        tar_js = ConditionalCDN('BOOTSTRAP_SERVE_LOCAL', fallback,
                                WebCDN('//cdn.bootcss.com/' + tar_lib + '/' + tar_ver + '/'))
        tar_app.extensions['bootstrap']['cdns'][tar_lib] = tar_js

    libs = {'jquery': {'ver': JQUERY_VERSION, 'fallback': local},
            'bootstrap': {'ver': BOOTSTRAP_VERSION, 'fallback': local},
            'html5shiv': {'ver': HTML5SHIV_VERSION, 'fallback': static},
            'respond.js': {'ver': RESPONDJS_VERSION, 'fallback': static}}
    for lib, par in libs.items():
        change_one(lib, par['ver'], par['fallback'])

change_cdn_domestic(app)

@app.route('/')
def index():
    return render_template('index.html', current_time=datetime.utcnow())

@app.route('/user/<name>')
def hello_world(name):
    return render_template('user.html', name=name)

@app.errorhandler(404)
def page_not_found(e):
    return render_template('404.html'), 404

@app.errorhandler(500)
def internal_server_error(e):
    return render_template('500.html'), 500

if __name__ == '__main__':
    app.run(
        debug=True
    )


from django.shortcuts import render, get_object_or_404, redirect
from movies.models import Movie, Person, Genre, Language, Watcher, Country, Rating, Review, Notification, MovieList
from django.contrib.auth.decorators import login_required
from django.http import HttpResponse, Http404
from django.core import files
from django.db.models import Q
import sys
import json
import requests
import datetime
import tempfile
from movies.pagination import Pagination

def process_movies(w, ms, settings):
    if settings.get('owned', False):
        w_owned = w.owned.all()
        for m in w_owned:
            pass
    if settings.get('watched', False):
        w_ratings = Rating.objects.filter(watcher=w)
        for m in w_ratings:
            pass
    if settings.get('user', False):
        u_ratings = Rating.objects.filter(watcher=settings.get('user', False))
        for m in u_ratings:
            pass
    for m in ms:
        if settings.get('owned', False):
            m.is_owned = False
            for o in w_owned:
                if o.id == m.id:
                    m.is_owned = True
                    break
        if settings.get('watched', False):
            m.is_watched = False
            m.my_rating = 0
            for o in w_ratings:
                if o.movie_id == m.id:
                    m.is_watched = True
                    m.my_rating = o.rating
                    break
        if settings.get('user', False):
            m.user_watched = False
            m.user_rating = 0
            for o in u_ratings:
                if o.movie_id == m.id:
                    m.user_watched = True
                    m.user_rating = o.rating
                    break

@login_required
def home(request):
    movies = Movie.objects.order_by('-date_added', '-id').prefetch_related('directors', 'actors', 'genres')[:10]
    movie_count = Movie.objects.all().count()
    ratings = Rating.objects.order_by('-date_added', '-id').select_related()[:10]
    rating_count = Rating.objects.all().count()
    reviews = Review.objects.order_by('-date_added', '-id').select_related()[:10]
    review_count = Review.objects.all().count()
    lists = MovieList.objects.order_by('-date_updated', '-id')[:10]
    list_count = MovieList.objects.all().count()
    process_movies(request.user.watcher, movies, {
        'watched': True,
        'owned': True,
    })
    return render(request, 'home.html', {
        'movies': movies,
        'ratings': ratings,
        'reviews': reviews,
        'lists': lists,
        'menu_home': True,
        'show_watched': True,
        'show_owned': True,
        'movie_pagination': Pagination(1, (movie_count+9)/10),
        'rating_pagination': Pagination(1, (rating_count+9)/10),
        'review_pagination': Pagination(1, (review_count+9)/10),
        'list_pagination': Pagination(1, (list_count+9)/10),
        'counter_offset': 0,
    })

@login_required
def profile(request):
    w = request.user.watcher
    ratings = Rating.objects.filter(watcher=w).order_by('-date_added', '-id').select_related()[:10]
    rating_count = Rating.objects.filter(watcher=w).count()
    reviews = Review.objects.filter(watcher=w).order_by('-date_added', '-id').select_related()[:10]
    review_count = Review.objects.filter(watcher=w).count()
    return render(request, 'profile/profile.html', {
        'ratings': ratings,
        'reviews': reviews,
        'menu_profile': True,
        'rating_pagination': Pagination(1, (rating_count+9)/10),
        'review_pagination': Pagination(1, (review_count+9)/10),
        'counter_offset': 0,
        'hide_user': True,
    })

@login_required
def profile_waiting(request):
    w = request.user.watcher
    ms = Movie.objects.filter(owners=w).exclude(watched_by=w).order_by('year').prefetch_related('directors', 'actors', 'genres')
    process_movies(w, ms, {'watched': True})
    return render(request, 'profile/index.html', {
        'movies': ms,
        'menu_profile': True,
        'submenu_waiting': True,
        'show_watched': True,
    })

@login_required
def profile_owned(request):
    ms = request.user.watcher.owned.all().order_by('year').prefetch_related('directors', 'actors', 'genres')
    process_movies(request.user.watcher, ms, {'owned': True})
    return render(request, 'profile/index.html', {
        'movies': ms,
        'menu_profile': True,
        'submenu_owned': True,
        'show_owned': True,
    })

@login_required
def profile_watched(request):
    ms = request.user.watcher.watched.all().order_by('year').prefetch_related('directors', 'actors', 'genres')
    process_movies(request.user.watcher, ms, {'watched': True})
    return render(request, 'profile/index.html', {
        'movies': ms,
        'menu_profile': True,
        'submenu_watched': True,
        'show_watched': True,
    })

@login_required
def profile_lists(request):
    ls = MovieList.objects.filter(watcher=request.user.watcher).order_by('-date_updated')
    return render(request, 'profile/lists.html', {
        'lists': ls,
        'menu_profile': True,
        'submenu_lists': True,
    })

@login_required
def profile_settings(request):
    return render(request, 'profile/settings.html', {
        'menu_profile': True,
        'submenu_settings': True,
    })

@login_required
def profile_notifications(request):
    ns = Notification.objects.filter(watcher=request.user.watcher).order_by('-date_added')
    rs = Notification.objects.filter(target=request.user.watcher).order_by('-date_added')
    return render(request, 'profile/notifications.html', {
        'all_notifications': ns,
        'reverse_notifications': rs,
        'menu_profile': True,
        'submenu_notifications': True,
    })

@login_required
def users(request):
    ws = Watcher.objects.exclude(id=request.user.watcher.id)
    return render(request, 'users/index.html', {
        'watchers': ws,
        'menu_users': True,
        'hide_submenu': True,
    })

@login_required
def user(request, id):
    w = get_object_or_404(Watcher, id=id)
    if w == request.user.watcher:
        return redirect(profile)
    ratings = Rating.objects.filter(watcher=w).order_by('-date_added', '-id').select_related()[:10]
    rating_count = Rating.objects.filter(watcher=w).count()
    reviews = Review.objects.filter(watcher=w).order_by('-date_added', '-id').select_related()[:10]
    review_count = Review.objects.filter(watcher=w).count()
    return render(request, 'users/profile.html', {
        'ratings': ratings,
        'reviews': reviews,
        'menu_users': True,
        'menu_users_value': w.get_name(),
        'watcher': w,
        'rating_pagination': Pagination(1, (rating_count+9)/10),
        'review_pagination': Pagination(1, (review_count+9)/10),
        'counter_offset': 0,
        'hide_user': True,
    })

@login_required
def user_borrow(request, id):
    w = get_object_or_404(Watcher, id=id)
    if w==request.user.watcher:
        return redirect(profile)
    ms = Movie.objects.filter(owners=w).exclude(owners=request.user.watcher).prefetch_related('directors', 'actors', 'genres')
    process_movies(request.user.watcher, ms, {
        'owned': True,
        'user': w,
    })
    return render(request, 'users/user.html', {
        'movies': ms,
        'menu_users': True,
        'submenu_borrow': True,
        'menu_users_value': w.get_name(),
        'watcher': w,
        'show_rated': True,
        'show_owned': True,
    });

@login_required
def user_owned(request, id):
    w = get_object_or_404(Watcher, id=id)
    if w==request.user.watcher:
        return redirect(profile)
    ms = w.owned.all().order_by('year').prefetch_related('directors', 'actors', 'genres')
    process_movies(request.user.watcher, ms, {'watched': True})
    return render(request, 'users/user.html', {
        'movies': ms,
        'menu_users': True,
        'submenu_owned': True,
        'menu_users_value': w.get_name(),
        'watcher': w,
        'show_watched': True,
    })

@login_required
def user_watched(request, id):
    w = get_object_or_404(Watcher, id=id)
    if w==request.user.watcher:
        return redirect(profile)
    ms = w.watched.all().order_by('year').prefetch_related('directors', 'actors', 'genres')
    process_movies(request.user.watcher, ms, {
        'watched': True,
        'user': w,
    })
    return render(request, 'users/user.html', {
        'movies': ms,
        'menu_users': True,
        'submenu_watched': True,
        'menu_users_value': w.get_name(),
        'watcher': w,
        'show_rated': True,
        'show_watched': True,
    })

@login_required
def user_lists(request, id):
    w = get_object_or_404(Watcher, id=id)
    if w==request.user.watcher:
        return redirect(profile)
    ls = MovieList.objects.filter(watcher=w).order_by('-date_updated')
    return render(request, 'users/lists.html', {
        'lists': ls,
        'menu_users': True,
        'submenu_lists': True,
        'menu_users_value': w.get_name(),
        'watcher': w,
    })

@login_required
def show_list(request, id):
    l = get_object_or_404(MovieList, id=id)
    ms = l.movies.all().prefetch_related('directors', 'actors', 'genres')
    is_own = l.watcher == request.user.watcher
    if is_own:
        process_movies(request.user.watcher, ms, {'watched': True})
        return render(request, 'profile/list.html', {
            'list': l,
            'movies': ms,
            'menu_profile': True,
            'submenu_lists': True,
            'show_watched': True,
        })
    else:
        process_movies(request.user.watcher, ms, {
            'watched': True,
            'user': l.watcher,
        })
        return render(request, 'users/list.html', {
            'list': l,
            'movies': ms,
            'menu_users': True,
            'submenu_lists': True,
            'watcher': l.watcher,
            'show_watched': True,
            'show_rated': True,
        })

@login_required
def remove_list(request, id):
    l = get_object_or_404(MovieList, id=id)
    if l.watcher != request.user.watcher:
        raise Http404()
    l.delete()
    return redirect(profile_lists)

@login_required
def add_list(request):
    if request.method != "POST":
        raise Http404()
    title = request.POST['title']
    description = request.POST['description']
    if not title or not description:
        return redirect(profile_lists)
    MovieList.objects.create(title=title, description=description, watcher=request.user.watcher)
    return redirect(profile_lists)

@login_required
def show_list_for_movie(request, id):
    m = get_object_or_404(Movie, id=id)
    ls = MovieList.objects.filter(watcher=request.user.watcher)
    for l in ls:
        l.has_movie = (l.movies.filter(id=m.id).count() > 0)
    return render(request, 'partial/lists_movie.html', {
        'movie': m,
        'lists': ls,
    })

@login_required
def add_movie_to_list(request, list_id, movie_id):
    try:
        m = get_object_or_404(Movie, id=movie_id)
        l = get_object_or_404(MovieList, id=list_id)
    except:
        return HttpResponse(json.dumps({'status': False}), content_type='application/json')
    l.movies.add(m)
    l.date_updated = datetime.datetime.now()
    l.save()
    return HttpResponse(json.dumps({'status': True}), content_type='application/json')

@login_required
def remove_movie_from_list(request, list_id, movie_id):
    try:
        m = get_object_or_404(Movie, id=movie_id)
        l = get_object_or_404(MovieList, id=list_id)
    except:
        return HttpResponse(json.dumps({'status': False}), content_type='application/json')
    l.movies.remove(m)
    l.date_updated = datetime.datetime.now()
    l.save()
    return HttpResponse(json.dumps({'status': True}), content_type='application/json')

@login_required
def movie(request, id):
    m = get_object_or_404(Movie, id=id)
    if request.user.watcher.owned.filter(id=id).count() > 0:
        m.is_owned = True
    else:
        m.is_owned = False
    try:
        r = Rating.objects.get(watcher=request.user.watcher, movie=m)
        m.is_watched = True
        m.my_rating = r.rating
    except:
        m.is_watched = False
        m.my_rating = 0
    ratings = Rating.objects.filter(movie=m).exclude(watcher=request.user.watcher)
    reviews = Review.objects.filter(movie=m).exclude(watcher=request.user.watcher)
    try:
        my_review = Review.objects.get(watcher=request.user.watcher, movie=m)
    except:
        my_review = False
    rating_dict = dict([(o.watcher_id, o) for o in ratings])
    for r in reviews:
        r.rated = rating_dict.get(r.watcher_id, False)
    watchers = Watcher.objects.all().exclude(id=request.user.watcher.id)
    owners_dict = dict([(o.id, o.id) for o in m.owners.all()])
    reviewers_dict = dict([(r.watcher_id, r.watcher_id) for r in m.reviewed_by.all()])
    for w in watchers:
        w.owns = (w.id in owners_dict)
        w.reviewed = (w.id in reviewers_dict)
    ls = m.movielist_set.all().order_by('-date_updated', '-id')
    for l in ls:
        if l.watcher == request.user.watcher:
            l.is_own = True
        else:
            l.is_own = False
    return render(request, 'movies/movie.html', {
        'movie': m,
        'ratings': ratings,
        'reviews': reviews,
        'lists': ls,
        'watchers': watchers,
        'my_review': my_review,
        'menu_movies': True,
        'hide_submenu': True,
        'menu_movies_value': m.title,
    })

@login_required
def movie_review(request, id):
    m = get_object_or_404(Movie, id=id)
    if request.method == "POST":
        if not 'review' in request.POST or not request.POST['review']:
            return redirect(movie, id)
        try:
            review = Review.objects.get(watcher=request.user.watcher, movie=m)
            review.review = request.POST['review']
            review.save()
        except:
            review = Review.objects.create(watcher=request.user.watcher, movie=m, review=request.POST['review'])
        return redirect(movie, id)
    try:
        review = Review.objects.get(watcher=request.user.watcher, movie=m)
    except:
        review = False
    return render(request, 'movies/review.html', {
        'movie': m,
        'review': review,
        'menu_movies': True,
        'hide_submenu': True,
        'menu_movies_value': "Review (%s)" % (m.title),
    })

@login_required
def movies(request):
    ms = Movie.objects.all().order_by('year').prefetch_related('directors', 'actors', 'genres')
    process_movies(request.user.watcher, ms,{
        'watched': True,
        'owned': True,
    })
    return render(request, 'movies/index.html', {
        'movies': ms,
        'menu_movies': True,
        'submenu_all': True,
        'show_watched': True,
        'show_owned': True,
    })

@login_required
def years(request):
    ys = Movie.objects.all().order_by('year').values_list('year', flat=True).distinct()
    return render(request, 'movies/years.html', {
        'years': ys,
        'menu_movies': True,
        'submenu_years': True,
        'show_submenu_search': True,
    })

@login_required
def by_year(request, y):
    ms = Movie.objects.filter(year=y).order_by('year').prefetch_related('directors', 'actors', 'genres')
    process_movies(request.user.watcher, ms, {
        'watched': True,
        'owned': True,
    })
    return render(request, 'movies/index.html', {
        'movies': ms,
        'menu_movies': True,
        'submenu_years': True,
        'menu_movies_value': "By Year (%s)" % (y),
        'show_watched': True,
        'show_owned': True,
    })

@login_required
def genres(request):
    gs = Genre.objects.all().order_by('name')
    return render(request, 'movies/genres.html', {
        'genres': gs,
        'menu_movies': True,
        'submenu_genres': True,
        'show_submenu_search': True,
    })

@login_required
def by_genre(request, id):
    g = get_object_or_404(Genre, id=id)
    ms = Movie.objects.filter(genres=g).order_by('year').prefetch_related('directors', 'actors', 'genres')
    process_movies(request.user.watcher, ms, {
        'watched': True,
        'owned': True,
    })
    return render(request, 'movies/index.html', {
        'movies': ms,
        'menu_movies': True,
        'submenu_genres': True,
        'menu_movies_value': "By Genre (%s)" % (g.name),
        'show_watched': True,
        'show_owned': True,
    })

@login_required
def languages(request):
    ls = Language.objects.all().order_by('name')
    return render(request, 'movies/languages.html', {
        'languages': ls,
        'menu_movies': True,
        'submenu_languages': True,
        'show_submenu_search': True,
    })

@login_required
def by_language(request, id):
    l = get_object_or_404(Language, id=id)
    ms = Movie.objects.filter(language=l).order_by('year').prefetch_related('directors', 'actors', 'genres')
    process_movies(request.user.watcher, ms, {
        'watched': True,
        'owned': True,
    })
    return render(request, 'movies/index.html', {
        'movies': ms,
        'menu_movies': True,
        'submenu_languages': True,
        'menu_movies_value': "By Language (%s)" % (l.name),
        'show_watched': True,
        'show_owned': True,
    })

@login_required
def countries(request):
    cs = Country.objects.all().order_by('name')
    return render(request, 'movies/countries.html', {
        'countries': cs,
        'menu_movies': True,
        'submenu_countries': True,
        'show_submenu_search': True,
    })

@login_required
def by_country(request, id):
    c = get_object_or_404(Country, id=id)
    ms = Movie.objects.filter(country=c).order_by('year').prefetch_related('directors', 'actors', 'genres')
    process_movies(request.user.watcher, ms, {
        'watched': True,
        'owned': True,
    })
    return render(request, 'movies/index.html', {
        'movies': ms,
        'menu_movies': True,
        'submenu_countries': True,
        'menu_movies_value': "By Country (%s)" % (c.name),
        'show_watched': True,
        'show_owned': True,
    })

@login_required
def by_query(request, query):
    ms = Movie.objects.filter(Q(title__icontains=query) | Q(subtitle__icontains=query) | Q(imdbID=query)).order_by('year').prefetch_related('directors', 'actors', 'genres')
    ps = Person.objects.filter(name__icontains=query)
    if ms.count() == 1 and ps.count() == 0:
        return redirect(movie, ms[0].id)
    if ms.count() == 0 and ps.count() == 1:
        return redirect(by_person, ps[0].id)
    process_movies(request.user.watcher, ms, {
        'watched': True,
        'owned': True,
    })
    return render(request, 'movies/query.html', {
        'movies': ms,
        'persons': ps,
        'menu_movies': True,
        'submenu_query': True,
        'menu_movies_value': "By Query (%s)" % (query),
        'show_watched': True,
        'show_owned': True,
    })

@login_required
def persons(request):
    ps = Person.objects.all().order_by('name')
    return render(request, 'movies/persons.html', {
        'persons': ps,
        'menu_movies': True,
        'submenu_persons': True,
        'show_submenu_search': True,
    })

@login_required
def by_person(request, id):
    p = get_object_or_404(Person, id=id)
    directed = p.directed.all().order_by('year').prefetch_related('directors', 'actors', 'genres')
    written = p.written.all().order_by('year').prefetch_related('directors', 'actors', 'genres')
    acted_in = p.acted_in.all().order_by('year').prefetch_related('directors', 'actors', 'genres')
    process_movies(request.user.watcher, directed, {
        'watched': True,
        'owned': True,
    })
    process_movies(request.user.watcher, written, {
        'watched': True,
        'owned': True,
    })
    process_movies(request.user.watcher, acted_in, {
        'watched': True,
        'owned': True,
    })
    return render(request, 'movies/person.html', {
        'person': p,
        'directed': directed,
        'acted_in': acted_in,
        'written': written,
        'menu_movies': True,
        'submenu_persons': True,
        'menu_movies_value': "By Person (%s)" % (p.name),
        'show_watched': True,
        'show_owned': True,
    })

@login_required
def pagination_movie(request, page):
    if request.method != "POST":
        raise Http404()
    try:
        page = int(page)
    except:
        raise Http404()
    m_count = Movie.objects.all().count()
    if page*10-10 > m_count:
        raise Http404()
    ms = Movie.objects.order_by('-date_added', '-id').prefetch_related('directors', 'actors', 'genres')[page*10-10:page*10]
    process_movies(request.user.watcher, ms, {
        'watched': True,
        'owned': True,
    })
    return render(request, 'partial/movie_table.html', {
        'movies': ms,
        'show_watched': True,
        'show_owned': True,
        'pagination': Pagination(page, (m_count+9)/10),
        'counter_offset': page*10-10,
    })

@login_required
def pagination_rating(request, page):
    if request.method != "POST":
        raise Http404()
    try:
        page = int(page)
    except:
        raise Http404()
    r_count = Rating.objects.all().count()
    if page*10-10 > r_count:
        raise Http404()
    rs = Rating.objects.order_by('-date_added', '-id').select_related()[page*10-10:page*10]
    return render(request, 'partial/rating_table.html', {
        'ratings': rs,
        'pagination': Pagination(page, (r_count+9)/10),
        'counter_offset': page*10-10,
    })

@login_required
def pagination_review(request, page):
    if request.method != "POST":
        raise Http404()
    try:
        page = int(page)
    except:
        raise Http404()
    r_count = Review.objects.all().count()
    if page*10-10 > r_count:
        raise Http404()
    rs = Review.objects.order_by('-date_added', '-id').select_related()[page*10-10:page*10]
    return render(request, 'partial/review_table.html', {
        'reviews': rs,
        'pagination': Pagination(page, (r_count+9)/10),
        'counter_offset': page*10-10,
    })

@login_required
def pagination_list(request, page):
    if request.method != "POST":
        raise Http404()
    try:
        page = int(page)
    except:
        raise Http404()
    l_count = MovieList.objects.all().count()
    if page*10-10 > l_count:
        raise Http404()
    ls = MovieList.objects.order_by('-date_updated', '-id')[page*10-10:page*10]
    return render(request, 'partial/list_table.html', {
        'lists': ls,
        'pagination': Pagination(page, (l_count+9)/10),
        'counter_offset': page*10-10,
    })

@login_required
def pagination_user_movie(request, id, page):
    w = get_object_or_404(Watcher, id=id)
    if request.method != "POST":
        raise Http404()
    try:
        page = int(page)
    except:
        raise Http404()
    m_count = w.watched.all().count()
    if page*10-10 > m_count:
        raise Http404()
    ms = w.watched.order_by('-date_added', '-id').prefetch_related('directors', 'actors', 'genres')[page*10-10:page*10]
    process_movies(request.user.watcher, ms, {
        'watched': True,
        'owned': True,
        'user': w,
    })
    return render(request, 'partial/movie_table.html', {
        'movies': ms,
        'show_watched': True,
        'show_owned': True,
        'show_rated': True,
        'pagination': Pagination(page, (m_count+9)/10),
        'counter_offset': page*10-10,
    })

@login_required
def pagination_user_rating(request, id, page):
    w = get_object_or_404(Watcher, id=id)
    if request.method != "POST":
        raise Http404()
    try:
        page = int(page)
    except:
        raise Http404()
    r_count = Rating.objects.filter(watcher=w).count()
    if page*10-10 > r_count:
        raise Http404()
    rs = Rating.objects.filter(watcher=w).order_by('-date_added', '-id').select_related()[page*10-10:page*10]
    return render(request, 'partial/rating_table.html', {
        'ratings': rs,
        'pagination': Pagination(page, (r_count+9)/10),
        'counter_offset': page*10-10,
        'hide_user': True,
    })

@login_required
def pagination_user_review(request, id, page):
    w = get_object_or_404(Watcher, id=id)
    if request.method != "POST":
        raise Http404()
    try:
        page = int(page)
    except:
        raise Http404()
    r_count = Review.objects.filter(watcher=w).count()
    if page*10-10 > r_count:
        raise Http404()
    rs = Review.objects.filter(watcher=w).order_by('-date_added', '-id').select_related()[page*10-10:page*10]
    return render(request, 'partial/review_table.html', {
        'reviews': rs,
        'pagination': Pagination(page, (r_count+9)/10),
        'counter_offset': page*10-10,
        'hide_user': True,
    })

@login_required
def pagination_profile_movie(request, page):
    return pagination_user_movie(request, request.user.watcher.id, page)

@login_required
def pagination_profile_rating(request, page):
    return pagination_user_rating(request, request.user.watcher.id, page)

@login_required
def pagination_profile_review(request, page):
    return pagniation_user_rating(request, request.user.watcher.id, page)

@login_required
def notification_read(request, id):
    if request.method != "POST":
        raise Http404()
    notif = get_object_or_404(Notification, id=id, watcher=request.user.watcher)
    notif.read = True
    notif.save()
    return HttpResponse(json.dumps({'status': True}), content_type='application/json')

@login_required
def movie_suggest(request, movie_id, watcher_id):
    if request.method != "POST":
        raise Http404()
    movie = get_object_or_404(Movie, id=movie_id)
    watcher = get_object_or_404(Watcher, id=watcher_id)
    if watcher == request.user.watcher:
        raise Http404()
    Notification.create_suggestion(watcher, request.user.watcher, movie)
    return HttpResponse(json.dumps({'status': True}), content_type='application/json')

@login_required
def movie_ask_borrow(request, movie_id, watcher_id):
    if request.method != "POST":
        raise Http404()
    movie = get_object_or_404(Movie, id=movie_id)
    watcher = get_object_or_404(Watcher, id=watcher_id)
    if watcher == request.user.watcher:
        raise Http404()
    Notification.create_ask_borrow(watcher, request.user.watcher, movie)
    return HttpResponse(json.dumps({'status': True}), content_type='application/json')

@login_required
def movie_ask_review(request, movie_id, watcher_id):
    if request.method != "POST":
        raise Http404()
    movie = get_object_or_404(Movie, id=movie_id)
    watcher = get_object_or_404(Watcher, id=watcher_id)
    if watcher == request.user.watcher:
        raise Http404()
    Notification.create_ask_review(watcher, request.user.watcher, movie)
    return HttpResponse(json.dumps({'status': True}), content_type='application/json')

@login_required
def user_ask_suggest(request, id):
    if request.method != "POST":
        raise Http404()
    w = get_object_or_404(Watcher, id=id)
    if request.user.watcher == w:
        raise Http404()
    Notification.create_ask_suggestion(w, request.user.watcher)
    return HttpResponse(json.dumps({'status': True}), content_type='application/json')

@login_required
def profile_settings_mail(request):
    if request.method != "POST" or not 'value' in request.POST:
        raise Http404()
    receive = False
    if request.POST['value'] == 'true':
        receive = True
    request.user.watcher.settings_mail = receive
    request.user.watcher.save()
    return HttpResponse(json.dumps({'status': True}), content_type='application/json')

@login_required
def own(request, id):
    try:
        m = Movie.objects.get(id=id)
    except:
        return HttpResponse(json.dumps({'status': False}), content_type='application/json')
    request.user.watcher.owned.add(m)
    return HttpResponse(json.dumps({'status': True}), content_type='application/json')

@login_required
def unown(request, id):
    try:
        m = Movie.objects.get(id=id)
    except:
        return HttpResponse(json.dumps({'status': False}), content_type='application/json')
    request.user.watcher.owned.remove(m)
    return HttpResponse(json.dumps({'status': True}), content_type='application/json')

@login_required
def watch(request, id):
    if request.method != 'POST' or not 'rating' in request.POST:
        return HttpResponse(json.dumps({'status': False}), content_type='application/json')
    try:
        m = Movie.objects.get(id=id)
    except:
        return HttpResponse(json.dumps({'status': False}), content_type='application/json')
    rating = request.POST['rating']
    if Rating.objects.filter(watcher=request.user.watcher, movie=m).count() > 0:
        return HttpResponse(json.dumps({'status': False}), content_type='application/json')
    try:
        Rating.objects.create(watcher=request.user.watcher, movie=m, rating=rating)
    except:
        return HttpResponse(json.dumps({'status': False}), content_type='application/json')
    rating = int(rating)
    raters = Rating.objects.filter(movie=m).count()
    if raters == 0:
        m.avg_rating = rating
    else:
        m.avg_rating = (m.avg_rating*(raters-1)+rating)/raters;
    m.save()
    return HttpResponse(json.dumps({'status': True, 'rating': m.avg_rating}), content_type='application/json')

@login_required
def rate(request, id):
    if request.method != 'POST' or not 'rating' in request.POST:
        return HttpResponse(json.dumps({'status': False}), content_type='application/json')
    try:
        m = Movie.objects.get(id=id)
        ratingObj = Rating.objects.get(watcher=request.user.watcher, movie=m)
    except:
        return HttpResponse(json.dumps({'status': False}), content_type='application/json')
    rating = request.POST['rating']
    try:
        oldRating = ratingObj.rating
        ratingObj.rating = rating
        ratingObj.save()
    except:
        return HttpResponse(json.dumps({'status': False}), content_type='application/json')
    rating = int(rating)
    raters = Rating.objects.filter(movie=m).count()
    m.avg_rating = (m.avg_rating*(raters)+rating-oldRating)/raters;
    m.save()
    return HttpResponse(json.dumps({'status': True, 'rating': m.avg_rating}), content_type='application/json')

@login_required
def add(request):
    if request.method == "POST":
        title = request.POST['title']
        subtitle = request.POST.get('subtitle', None)
        yr = request.POST['year']
        genres = []
        for g in request.POST['genres'].split(','):
            g = g.strip()
            try:
                g = Genre.objects.get(name=g)
            except:
                g = Genre.objects.create(name=g)
            genres.append(g)
        runtime = request.POST['runtime']
        plot = request.POST['plot']
        languages = []
        for l in request.POST['languages'].split(','):
            l = l.strip()
            try:
                l = Language.objects.get(name=l)
            except:
                l = Language.objects.create(name=l)
            languages.append(l)
        countries = []
        for c in request.POST['country'].split(','):
            c = c.strip()
            try:
                c = Country.objects.get(name=c)
            except:
                c = Country.objects.create(name=c)
            countries.append(c)
        imdbID = request.POST['imdbID']
        if Movie.objects.filter(imdbID=imdbID).count() > 0:
            return redirect(movie, get_object_or_404(Movie, imdbID=imdbID).id)
        directors = []
        for d in request.POST['directors'].split(','):
            d = d.strip()
            try:
                d = Person.objects.get(name=d)
            except:
                d = Person.objects.create(name=d)
            directors.append(d)
        writers = []
        for w in request.POST['writers'].split(','):
            w = w.strip()
            try:
                w = Person.objects.get(name=w)
            except:
                w = Person.objects.create(name=w)
            writers.append(w)
        actors = []
        for a in request.POST['actors'].split(','):
            a = a.strip()
            try:
                a = Person.objects.get(name=a)
            except:
                a = Person.objects.create(name=a)
            actors.append(a)
        owned = 'owned' in request.POST
        m = Movie.objects.create(title=title, year=yr, runtime=runtime,
                        plot=plot, imdbID=imdbID, subtitle=subtitle)
        if 'url' in request.POST and request.POST['url']:
            url = request.POST['url']
            req = requests.get(url, stream=True)
            if req.status_code == requests.codes.ok:
                file_name = "%s.jpg" % (m.imdbID)
                lf = tempfile.NamedTemporaryFile()
                for block in req.iter_content(1024*8):
                    if not block:
                        break
                    lf.write(block)
                m.poster.save(file_name, files.File(lf))
        m.save()
        for g in genres:
            m.genres.add(g)
        for l in languages:
            m.language.add(l)
        for c in countries:
            m.country.add(c)
        for d in directors:
            m.directors.add(d)
        for w in writers:
            m.writers.add(w)
        for a in actors:
            m.actors.add(a)
        if owned:
            request.user.watcher.owned.add(m)
        return redirect(movie, m.id)
    return render(request, 'add.html', {
        'menu_add': True,
    })


import arrow
from keg.db import db
from keg_elements.db.mixins import DefaultColsMixin, MethodsMixin
from sqlalchemy.dialects.postgresql import insert as pgsql_insert
from sqlalchemy.inspection import inspect

class EntityMixin(DefaultColsMixin, MethodsMixin):
    @classmethod
    def upsert(cls, values=None, on_conflict_do='update', index_elements=None, **kwargs):
        if index_elements is None:
            index_elements = cls.__upsert_index_elements__

        if values is None:
            values = kwargs

        primary_key_col = inspect(cls).primary_key[0]
        stmt = pgsql_insert(cls.__table__).returning(primary_key_col).values(**values)

        assert on_conflict_do in ('nothing', 'update')
        if on_conflict_do == 'update':
            touching_timestamps = {}
            if hasattr(cls, 'updated_utc'):
                # on_conflict_do_update won't take into account columns onupdate attributes
                touching_timestamps.update({'updated_utc': arrow.utcnow()})
            stmt = stmt.on_conflict_do_update(
                index_elements=index_elements,
                set_={**values, **touching_timestamps}
            )
        else:
            stmt = stmt.on_conflict_do_nothing(index_elements=index_elements)

        result = db.session.execute(stmt)

        return result.scalar()

def tc_relation(kwargs, rel_col_name, rel_ent_cls):
    id_col_name = f'{rel_col_name}_id'
    rel_name_dunder = f'{rel_col_name}__'

    if id_col_name not in kwargs and rel_col_name not in kwargs:
        rel_keys = [key for key in kwargs.keys() if key.startswith(rel_name_dunder)]
        rel_kwargs = {key.replace(rel_name_dunder, '', 1): kwargs.pop(key) for key in rel_keys}
        rel_ent_inst = rel_ent_cls.testing_create(**rel_kwargs)
        kwargs[id_col_name] = rel_ent_inst.id

    return kwargs


from flask import Flask, render_template
from data import db_session
from data.users import User
from data.jobs import Jobs
import os

app = Flask(__name__)
app.config['SECRET_KEY'] = 'yandexlyceum_secret_key'

@app.route("/")
def main():
    db_session.global_init("db/blogs.db")
    db_sess = db_session.create_session()
    data = []
    for job in db_sess.query(Jobs).all():
        for user in db_sess.query(User).filter(User.id == job.team_leader):
            full_name = f"{user.surname} {user.name}"
            data.append([job.job, full_name, job.work_size, job.collaborators, job.is_finished])
    return render_template('journal.html', data=data)

if __name__ == '__main__':
    app.run(port=8080, host='127.0.0.1')

WEB. Знакомство с flask-sqlalchemy/Журнал работ/main.py


#БСБО-05-19 Салынь Даниил Леонидович
wb_tree = []

def fill_wb_tree():
    global wb_tree
    global i
    black = []
    white = []
    black.extend([white, white, white])
    white.extend([black, black])
    wb_tree.append(black)

fill_wb_tree()


import time
from queue import Empty, Full

import cv2
from imutils import resize

from pipert.core.message import Message
from pipert.core.message_handlers import RedisHandler
from pipert.core.message import message_decode, message_encode
from pipert.core.routine import Routine

class Listen2Stream(Routine):

    def __init__(self, stream_address, queue, fps=30., *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.stream_address = stream_address
        self.isFile = str(stream_address).endswith("mp4")
        self.stream = None
        # self.stream = cv2.VideoCapture(self.stream_address)
        self.queue = queue
        self.fps = fps
        self.updated_config = {}

    def begin_capture(self):
        self.stream = cv2.VideoCapture(self.stream_address)
        if self.isFile:
            self.fps = self.stream.get(cv2.CAP_PROP_FPS)
            self.stream.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
            self.stream.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)
        self.logger.info("Starting video capture on %s", self.stream_address)

    def change_stream(self):
        if self.stream_address == self.updated_config['stream_address']:
            return
        self.stream_address = self.updated_config['stream_address']
        self.fps = self.updated_config['FPS']
        self.isFile = str(self.stream_address).endswith("mp4")
        self.logger.info("Changing source stream address to %s",
                         self.updated_config['stream_address'])
        self.begin_capture()

    def grab_frame(self):
        grabbed, frame = self.stream.read()
        msg = Message(frame, self.stream_address)
        msg.record_entry(self.component_name, self.logger)
        return grabbed, msg

    def main_logic(self, *args, **kwargs):
        if self.updated_config:
            self.change_stream()
            self.updated_config = {}

        start = time.time()
        grabbed, msg = self.grab_frame()
        if grabbed:
            frame = msg.get_payload()
            frame = resize(frame, 640, 480)
            # if the stream is from a webcam, flip the frame
            if self.stream_address == 0:
                frame = cv2.flip(frame, 1)
            try:
                self.queue.get(block=False)
            except Empty:
                pass
            finally:
                msg.update_payload(frame)
                self.queue.put(msg)
                if self.isFile:
                    wait = time.time() - start
                    time.sleep(max(1 / self.fps - wait, 0))
                # self.queue.put(frame, block=False)
                time.sleep(0)
                return True

    def setup(self, *args, **kwargs):
        self.begin_capture()

    def cleanup(self, *args, **kwargs):
        self.stream.release()
        del self.stream

# TODO: add Error handling to connection
class Message2Redis(Routine):

    def __init__(self, out_key, url, queue, maxlen, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.out_key = out_key
        self.url = url
        self.queue = queue
        self.maxlen = maxlen
        self.msg_handler = None

    def main_logic(self, *args, **kwargs):
        try:
            msg = self.queue.get(block=False)
            msg.record_exit(self.component_name, self.logger)
            encoded_msg = message_encode(msg)
            self.msg_handler.send(encoded_msg, self.out_key)
            time.sleep(0)
            return True
        except Empty:
            time.sleep(0)  # yield the control of the thread
            return False

    def setup(self, *args, **kwargs):
        self.msg_handler = RedisHandler(self.url, self.maxlen)
        self.msg_handler.connect()

    def cleanup(self, *args, **kwargs):
        self.msg_handler.close()

class MessageFromRedis(Routine):

    def __init__(self, in_key, url, queue, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.in_key = in_key
        self.url = url
        self.queue = queue
        self.msg_handler = None
        self.flip = False
        self.negative = False

    def main_logic(self, *args, **kwargs):
        encoded_msg = self.msg_handler.receive(self.in_key)
        if encoded_msg:
            msg = message_decode(encoded_msg)
            msg.record_entry(self.component_name, self.logger)
            try:
                self.queue.put(msg, block=False)
                return True
            except Full:
                try:
                    self.queue.get(block=False)
                except Empty:
                    pass
                finally:
                    self.queue.put(msg, block=False)
                    return True
        else:
            time.sleep(0)
            return False

    def setup(self, *args, **kwargs):
        self.msg_handler = RedisHandler(self.url)
        self.msg_handler.connect()

    def cleanup(self, *args, **kwargs):
        self.msg_handler.close()

class DisplayCV2(Routine):
    def __init__(self, queue, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.queue = queue
        self.negative = False

    def main_logic(self, *args, **kwargs):
        try:
            msg = self.queue.get(block=False)
            frame = msg.get_payload()
            if self.negative:
                frame = 255 - frame
            cv2.imshow('Display', frame)
            cv2.waitKey(1)
        except Empty:
            time.sleep(0)

    def setup(self, *args, **kwargs):
        pass

    def cleanup(self, *args, **kwargs):
        cv2.destroyAllWindows()

class DisplayFlask(Routine):
    def __init__(self, in_key, queue, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.in_key = in_key
        self.queue = queue
        self.negative = False

    def main_logic(self, *args, **kwargs):
        try:
            frame = self.queue.get(block=False)
            if self.negative:
                frame = 255 - frame
            cv2.imshow('Display', frame)
            cv2.waitKey(1)
            return True
        except Empty:
            time.sleep(0)
            return False

    def setup(self, *args, **kwargs):
        pass

    def cleanup(self, *args, **kwargs):
        cv2.destroyAllWindows()


from path_finder.utility.Graph import Graph
from django.db.models import Q
from path_finder.models import Routes, Airports

class PathSearcher():
    """
    Queries routes starting at specified origin on a BFS basis until a path
    to the request destination is found.
    """

    def __init__(self):
        self.valid_path_exists = True
        self.graph = None
        self.errors_list = []

    def build_graph(self, origin_str, destination_str):
        self.verify_origin_and_destination(origin_str, destination_str)
        self.graph = Graph(origin_str)
        traversed = []  # Routes that have already been traversed
        next_level_of_paths = self.find_initial_routes_from_origin_string(
            origin_str, )
        if (len(self.errors()) is not 0):
            return
        while next_level_of_paths != []:
            for path in next_level_of_paths:
                traversed.append(path.id)
                self.graph.add_edge(path.origin.IATA, path.destination.IATA)
                if (path.destination.IATA == destination_str):
                    return

            temp = self.find_routes_from_origins(
                next_level_of_paths,
                traversed)
            next_level_of_paths = temp

        # If entire function finishes then there is no solution
        self.log_error("No Route")

    def find_shortest_path(self, origin, destination):
        """
        A BFS that finds the shortest path from origin to destination in the
        in-memory graph.
        """

        graph = self.graph.graph
        queue = []
        queue.append([origin])

        while queue:
            path = queue.pop(0)
            last_node = path[-1]
            if last_node == destination:
                return path

            for adjacent in graph.get(last_node):
                if adjacent not in path:
                    new_path = list(path)
                    new_path.append(adjacent)
                    queue.append(new_path)

    def find_routes_from_origins(self, origins, traversed):
        """
        Queries database for flights origination from an airport in the
        origins list

        Parameters:
        origins [str] - List of IATA codes of origin airport.
        traversed [int] - List of Routes ids that have already been queried.

        Return Value:
        [Route] - List of Routes objects from datbase
        """
        routes = []
        for location in origins:
            new_routes = Routes.objects.filter(
                Q(origin=location.destination) & ~Q(id__in=traversed))
            routes += [route for route in new_routes]
        return routes

    def find_initial_routes_from_origin_string(self, origin_str):
        return Routes.objects.filter(Q(origin=origin_str))

    def verify_origin_and_destination(self, origin_str, destination_str):
        if not Airports.objects.filter(Q(IATA=origin_str)):
            self.log_error("Invalid Origin")
        if not Airports.objects.filter(Q(IATA=destination_str)):
            self.log_error("Invalid Destination")

    def log_error(self, error_msg):
        self.errors_list.append(error_msg)

    def errors(self):
        return self.errors_list


def str_replace(string):
    """
    把字符串中的每个空格替换成"%20"
    """
    # 从后面开始复制和替换
    str_len1 = len(string)
    space_num = 0

    for i in range(str_len1):
        if string[i] == ' ':
            space_num += 1

    str_len2 = str_len1 + 2 * space_num
    str_list = [''] * (str_len2)
    p = str_len1 - 1
    q = str_len2 - 1

    while p != q:
        if string[p] != ' ':
            str_list[q] = string[p]
            p -= 1
            q -= 1
        else:
            str_list[q-2:q+1] = ['%', '2', '0']
            p -= 1
            q -= 3

    return string[0:p+1] + ''.join(str_list)

if __name__ == "__main__":
    string = "We are happy"
    print(str_replace(string))

    print(string.replace(' ', '%20'))


#-*- coding: utf-8 -*-

from pathlib import Path
import sqlite3, os, copy, glob, time, threading, datetime, shutil, logging, json, csv
from itertools import chain
from PIL import Image, ImageSequence
import my_utils as mutl

LIST_DELIMITER = ';'
sqlite3.dbapi2.converters['DATETIME'] = sqlite3.dbapi2.converters['TIMESTAMP']

class DataBaseManager():
    """
    GUIメインからのデータベース操作をSQLを意識せずに済むようにラッピングする。
    """
    logger = logging.getLogger('MyDBApp')

    DATABASE_NAME = 'database.sqlite'

    FILE_ENCODING = 'utf-8'

    DATA_DIR = 'data'
    TAG_IMAGE_DIR = 'tag_image'
    BACKUP_DIR = 'backup'
    FILE_NUMBER_OF_DIGITS = 5

    SUPPORTED_EXT = ["jpg", "jpeg", "png", "bmp", "gif", "zip"]

    TEMPLATE_MAIN_COLUMN = {
        'Title': 'text primary key',
        'InitialCharacter': 'text',
        'Updated': 'datetime',
        'FileNum': 'Integer',
        'Size': 'Real',
        'Link':'text',
        'IsFavorite': 'Integer',
        'favorite': 'text',
        'chapter': 'text'
    }

    TEMPLATE_TAGS_COLUMN = {
        'Name': 'text primary key',
        'InitialCharacter': 'text',
        'Link': 'text',
        'Image': 'text',
        'IsFavorite': 'Integer'
    }

    db_root = ''
    data_dir = ''
    tag_dir = ''

    record_num = 0

    # ファイル複製スレッド
    file_op_progress = {
        'task_num':0,
        'task_index':0,
        'title':'',
        'file_num':0,
        'done_file':0,
        'all_size':0,
        'done_size':0,
        'speed':0,
        'remaining_time':0.0
        }
    is_cancel = False

    # cursorのスレッド以外で発行されたSQL文を溜め込む
    sql_tasks = []

    dbm_thread_id = 0

    file_op_tasks = []
    file_op_thread = threading.Thread() # ファイル操作用のスレッド

    def __init__(self):
        self.logger.debug('get instance')

    def __del__(self):
        self.logger.debug('delete instance')
        self.close()

    # データベース操作
    def close(self):

        if self.file_op_thread.is_alive():
            self.file_op_thread.join()

        self.sql_tasks = []

        if self.db_root != '':
            self.cursor.close()
            self.connection.close()
            self.db_root == ''

    def database_is_exist(self, db_root):
        db_path = os.path.join(db_root, self.DATABASE_NAME)
        return os.path.exists(db_path)

    def connect_database(self, db_root):

        db_path = os.path.join(db_root, self.DATABASE_NAME)
        if not os.path.exists(db_path):
            return False

        self.db_root = db_root
        self.data_dir = os.path.join(self.db_root, self.DATA_DIR)
        self.tag_dir = os.path.join(self.db_root, self.TAG_IMAGE_DIR)

        self.logger.debug('open database')

        self.connection = sqlite3.connect(db_path, detect_types = sqlite3.PARSE_DECLTYPES|sqlite3.PARSE_COLNAMES)
        self.cursor = self.connection.cursor()

        return self.get_free_space() / 1024 #MiBで帰ってくる

    def create_database(self, db_root, db_option={}):
        """
        概要:
            新規データベースを作成する。
        引数:
            db_root: データベースのルートディレクトリ
            additional_tags: ユーザが任意で追加していくタグのdict
                - key:タグ名、value:tuple(sqlite内でのデータ型, 最大登録数)
        返り値:
            db_rootにdatabase.sqliteが存在する場合Falseリターン
        メモ:
        """

        # すでにデータベースがある場合はFalseリターン
        db_path = os.path.join(db_root, self.DATABASE_NAME)
        if os.path.exists(db_path):
            return False

        # データベースとデータ置き場の作成
        self.db_root = db_root
        self.connection = sqlite3.connect(db_path, detect_types = sqlite3.PARSE_DECLTYPES|sqlite3.PARSE_COLNAMES)
        self.cursor = self.connection.cursor()

        self.data_dir = os.path.join(self.db_root, self.DATA_DIR)
        if not os.path.exists(self.data_dir):
            os.mkdir(self.data_dir)

        self.tag_dir = os.path.join(self.db_root, self.TAG_IMAGE_DIR)
        if not os.path.exists(self.tag_dir):
            os.mkdir(self.tag_dir)

        # Mainテーブルを作成する。
        table_name = 'MainTable'
        table_columns = copy.deepcopy(self.TEMPLATE_MAIN_COLUMN)
        table_columns.update(db_option)
        tmp_str = ','.join(['{} {}'.format(key, value) for key,value in table_columns.items()])
        sql = 'create table if not exists {} ({})'.format(table_name, tmp_str)

        self.logger.debug(sql)
        self.cursor.execute(sql)

        # 追加タグ記録用のテーブルを作成する
        for key in db_option.keys():
            table_name = key
            tmp_str = ','.join(['{} {}'.format(key, value) for key,value in self.TEMPLATE_TAGS_COLUMN.items()])
            sql = 'create table if not exists {} ({})'.format(table_name, tmp_str)
            self.logger.debug(sql)
            self.cursor.execute(sql)

        self.connection.commit()

        return True

    def copy_database(self, dst_path):

        if self.file_op_thread.is_alive():
            return False

        self.file_op_tasks = []
        data_list = self.get_items(['Title', 'FileNum', 'Size'])

        dst_data_path = os.path.join(dst_path, self.DATA_DIR)

        all_size = 0
        for row in data_list:

            title = row[0]
            filenum = row[1]
            src_size = row[2]
            all_size += src_size

            src_path = os.path.join(self.data_dir, title)
            new_path = os.path.join(dst_data_path, title)

            # ファイルコピーのタスクを作成する -簡易版
            self.file_op_tasks.append({
                'title':title,
                'src_path':src_path,
                'src_size':src_size,
                'dst_path':new_path,
                'file_num':filenum
                })

        os.mkdir(dst_data_path)

        dst_tag_path = os.path.join(dst_path, self.TAG_IMAGE_DIR)
        shutil.copytree(self.tag_dir, dst_tag_path)

        src_db_path = os.path.join(self.db_root, self.DATABASE_NAME)
        dst_db_path = os.path.join(dst_path, self.DATABASE_NAME)
        shutil.copyfile(src_db_path, dst_db_path)

        self.file_op_thread = threading.Thread(target=self._copy_database,daemon=False)
        self.file_op_thread.start()

        return True

    def _copy_database(self):

        # TODO: このやりかただと進捗表示が細かくできない

        self.file_op_progress['task_num'] = len(self.file_op_tasks)

        self.file_op_progress['done_size'] = 0
        self.file_op_progress['all_size'] = 0
        for ftask in self.file_op_tasks:
            self.file_op_progress['all_size'] += ftask['src_size']

        start = time.time()

        for t_idx, ftask in enumerate(self.file_op_tasks):

            # 初期設定
            title = ftask['title']
            trg_path = ftask['dst_path']
            src_path = ftask['src_path']

            self.file_op_progress['task_index'] = t_idx+1
            self.file_op_progress['title'] = title
            self.file_op_progress['file_num'] = ftask['file_num']

            shutil.copytree(src_path, trg_path)

            # 処理速度、残り時間予測
            self.file_op_progress['done_size'] += ftask['src_size']
            process_time = time.time() - start
            if process_time != 0:
                self.file_op_progress['speed'] = self.file_op_progress['done_size']/process_time # [MiB/s]

            if self.file_op_progress['speed'] != 0:
                self.file_op_progress['remaining_time'] = (self.file_op_progress['all_size'] - self.file_op_progress['done_size']) / self.file_op_progress['speed']

    def get_free_space(self):
        """
        接続中のデータベースのディスク空き容量を取得する
        """
        try:
            disk_info = shutil.disk_usage(self.db_root)
            return disk_info.free / (1024*1024)
        except:
            return 0

    # MainTable操作
    def get_db_info(self):
        size_list = self.get_items('Size', convert=True)
        num = len(size_list)
        if num == 0:
            sum_size = 0
        else:
            sum_size = sum(size_list)
        return num, sum_size

    def insert_records(self, records, move_file=False):
        """
        概要:
            レコードを登録する。
            登録のみでファイルの移動はせず、クラス内のfile_op_tasksに追加される。
            別途start_file_operationでコピータスクを実行する。
            本関数を小分けで使用してタスクを貯めてからまとめて実行もできるはず...
        引数:
            records: 下記の構造を持つ辞書のリスト
                {
                    path:登録ファイル群のフォルダのパス（必須）
                    Title:登録タイトル（レコードの主キー、必須）
                    values_dict:{その他のカラム内容の辞書、任意}
                }
            move_file:コピーではなくファイルを移動する。
        返り値:
            err_info: 'title: エラー内容'のstringのリスト
        メモ:
            ・err_infoは辞書のほうが使い勝手がよいかも
            ・未実装のエラーハンドリング
                - values_dictの不正なカラム
                - pathとtitleがない場合
            ・上書きができるようにすると色々と幅が広がる
                - 上書きモードと追加モードなどなど
        """

        op_mode = 'move' if move_file else 'copy'
        title_list = self.get_items('Title', convert=True)

        self.file_op_tasks = []

        err_info = []
        for info in records:

            # 情報の取り出し
            title = info['Title']
            src_path = info['path']
            values_dict = copy.deepcopy(info['values_dict'])

            # 同名タイトル
            if title in title_list:
                err_info.append('{} : 同名タイトルがあります。'.format(title))
                break

            # パスの正当性確認
            if not os.path.exists(src_path):
                err_info.append('{} : 該当するフォルダがありません。'.format(title))
                break

            # ファイル一覧取得
            file_list, file_size = mutl.search_files_deep(src_path, self.SUPPORTED_EXT)
            file_size /= (1024 * 1024)
            #file_list = sorted(list(chain.from_iterable([glob.glob(os.path.join(src_path, "*." + ext)) for ext in self.SUPPORTED_EXT])))

            # ファイルがない場合
            if len(file_list) == 0:
                err_info.append('{} : 該当するファイルがありません。'.format(title))
                break

            # レコードを作成する
            try:
                values_dict['Title'] = title
                values_dict['FileNum'] = 0
                values_dict['Size'] = 0.0
                values_dict['Link'] = ''
                values_dict['IsFavorite'] = 0
                values_dict['favorite'] = []
                values_dict['chapter'] = []
                sql_tmp, sql_values = self._convert_dict4sql(values_dict)
                sql = 'insert into MainTable {}'.format(sql_tmp)
                self.logger.debug('{} {}'.format(sql, sql_values))
                self.cursor.execute(sql, sql_values)
            except:
                err_info.append((title, 'SQL Insert Error'))
                break

            # ファイルコピーのタスクを作成する
            self.file_op_tasks.append({
                'operation':op_mode,
                'title':title,
                'src_list':file_list,
                'src_size':file_size,
                'dst_path':os.path.join(self.data_dir, title),
                'init_num':0,
                'init_size':0.0
                })

        self.connection.commit()

        return err_info

    def add_files(self, title, file_list):

        if len(file_list) == 0:
            return False

        self.file_op_tasks = []

        file_size = 0
        for fl in file_list:
            file_size += os.path.getsize(fl)
        file_size /= (1024 * 1024)

        init_info = self.get_items(['FileNum','Size'], title=title)

        # ファイルコピーのタスクを作成する
        self.file_op_tasks.append({
            'operation':'copy',
            'title':title,
            'src_list':sorted(file_list, key=mutl.numericalSort),
            'src_size':file_size,
            'dst_path':os.path.join(self.data_dir, title),
            'init_num':init_info[0][0],
            'init_size':init_info[0][1]
            })

        return True

    def delete_record(self, titles):
        """
        概要:
            指定されたレコードと該当するファイルを削除する。
        引数:
            titles: 削除するレコードのtitleのリスト
        返り値:
            False：前のスレッドが生きている場合にFalseを返す。
        メモ:
            ファイル削除は別スレッドだが、shutil.rmtreeでの一括消去のため進捗は確認できない。
            copyのタスクと同じ形式でまとめたいところ。
        """

        if self.file_op_thread.is_alive():
            return False

        for title in titles:
            sql = 'DELETE FROM MainTable WHERE Title="{}"'.format(title)
            self.logger.debug(sql)
            self.cursor.execute(sql)

        self.file_op_thread = threading.Thread(target=self._delete_titles, args=([titles]),daemon=False)
        self.file_op_thread.start()

        self.connection.commit()

        return True

    def delete_files(self, title,file_idx):
        """
        概要:
        引数:
        返り値:
        メモ:
        """
        if len(file_idx) == 0:
            return False

        self.file_op_tasks = []

        init_info = self.get_items(['FileNum','Size','favorite','chapter'], title=title, convert=True)

        init_favorite = []
        for i in init_info['favorite'][0]:
            if i.isdecimal():
                init_favorite.append(int(i))
        init_chapter = []
        for i in init_info['chapter'][0]:
            if i.isdecimal():
                init_chapter.append(int(i))

        # ファイルコピーのタスクを作成する
        self.file_op_tasks.append({
            'operation':'delete',
            'title':title,
            'src_list':sorted(file_idx),
            'src_size':0, # TODO: 現状、使っていない
            'dst_path':os.path.join(self.data_dir, title),
            'init_num':init_info['FileNum'][0][0],
            'init_size':init_info['Size'][0][0],
            'init_favorite': copy.deepcopy(init_favorite),
            'init_chapter':copy.deepcopy(init_chapter)
            })

        return True

    def start_file_operation(self):
        """
        概要:
            insert_recordsで発生したfile_op_tasksを別スレッドで実行する。
            レコード内容を更新するsqlをsql_tasksとして溜め込むため、コピー完了後にresolve_sql_tasksの実行が必要。
            スレッドの生存は、file_op_is_aliveで確認できる。
            コピーの進捗状況は、get_file_op_progressで取得できる。
        引数:
        返り値:
            False：前のスレッドが生きている場合にFalseを返す。
        メモ:
            ・sqlが、cursorを取得したスレッドでしか実行できないので、タスクとしてためている。
                - sqlの実施だけメインスレッドに帰ってきて実行とかできないだろうか...
            ・キャンセル操作への対応
        """

        if self.file_op_thread.is_alive():
            return False

        self.file_op_thread = threading.Thread(target=self._run_file_operation,daemon=False)
        self.file_op_thread.start()

        return True

    def sort_files(self, title,ref_index, insert_index):

        if len(insert_index) == 0:
            return

        title_dir, file_list, _ = self.get_file_list(title)
        init_info = self.get_items(['favorite','chapter'], title=title, convert=True)

        init_favorite = set([])
        for i in init_info['favorite'][0]:
            if i.isdecimal():
                init_favorite.add(int(i))
        init_chapter = set([])
        for i in init_info['chapter'][0]:
            if i.isdecimal():
                init_chapter.add(int(i))

        # 対象範囲のインデックスをすべて取得
        tmp_set = set(insert_index) | set([ref_index])
        trg_idx = set(range(min(tmp_set),max(tmp_set)+1))
        # 入れ替え対象のインデックスを除く, リスト化して指定位置に挿入
        new_order = sorted(trg_idx ^ insert_index)
        ref_pos = new_order.index(ref_index)
        new_order[ref_pos:ref_pos] = sorted(insert_index)

        # ソート１ - 元ファイルをいったん別名にして避難しつつ、ファイル名変更タスクの作成
        old_order = sorted(trg_idx)
        sort_task = []
        new_favorite = set([])
        new_chapter = set([])
        for i, old_idx in enumerate(new_order):

            new_idx = old_order[i]
            if old_idx == new_idx:
                continue

            if old_idx in init_favorite:
                init_favorite.remove(old_idx)
                new_favorite.add(new_idx)
            if old_idx in init_chapter:
                init_chapter.remove(old_idx)
                new_chapter.add(new_idx)

            fname = file_list[old_idx]
            old_idx_str, ext = os.path.splitext(fname) # インデックスと拡張子に分解

            old_path = os.path.join(title_dir, fname)
            tmp_path = os.path.join(title_dir, '_' + fname)
            os.rename(old_path, tmp_path)
            #print('{} -> {}'.format(old_path, tmp_path))

            new_idx_str = str(new_idx).zfill(self.FILE_NUMBER_OF_DIGITS)
            new_path = os.path.join(title_dir, new_idx_str + ext)

            sort_task.append((tmp_path, new_path))

            if ext == '.zip':
                old_thum_path = os.path.join(title_dir, '__thumbnail__', old_idx_str + '.png')
                tmp_thum_path = os.path.join(title_dir, '__thumbnail__', '_' + old_idx_str + '.png')
                os.rename(old_thum_path, tmp_thum_path)
                #print('{} -> {}'.format(old_thum_path, tmp_thum_path))

                new_thum_path = os.path.join(title_dir, '__thumbnail__', new_idx_str + '.png')
                sort_task.append((tmp_thum_path, new_thum_path))

        # ソート２ - ファイル名変更の実施
        for stask in sort_task:
            os.rename(stask[0], stask[1])
            #print('{} -> {}'.format(stask[0], stask[1]))

        new_favorite |= init_favorite
        new_chapter |= init_chapter

        # データベースの情報変更
        values_dict = {}
        values_dict['favorite'] = sorted(new_favorite)
        values_dict['chapter'] = sorted(new_chapter)
        #print(values_dict)

        self.update_record(title, values_dict=values_dict)

    def update_record(self, title, values_dict):
        """
        登録済みのデータのアップデート
        """
        data_list = []

        for key, value in values_dict.items():

            if key is 'Title':
                b_path = os.path.join(self.data_dir, title)
                n_path = os.path.join(self.data_dir, value)
                os.rename(b_path, n_path)

            if type(value) is list:
                tmp_val = LIST_DELIMITER.join([str(i) for i in value])
            else:
                tmp_val = value
            data_list.append('{0}="{1}"'.format(key,tmp_val))

        sql_set_data = ','.join(data_list)
        sql = 'UPDATE MainTable SET {0} WHERE Title="{1}"'.format(sql_set_data, title)

        # cursorのスレッドのみ実行可能なため、それ以外はタスクとして溜め込む
        try:
            self.logger.debug(sql)
            self.cursor.execute(sql)
            self.connection.commit()
        except:
            self.logger.debug('before SQL STACKED')
            self.sql_tasks.append(sql)

    def title_is_exist(self, title):
        sql = 'SELECT COUNT(*) FROM MainTable WHERE Title="{}"'.format(title)
        self.cursor.execute(sql)
        result = self.cursor.fetchall()
        return result[0][0] != 0

    def resolve_sql_tasks(self):
        """
        未実行のSQL文を実行する
        """
        for sql in self.sql_tasks:
            self.logger.debug(sql)
            self.cursor.execute(sql)

        self.sql_tasks = []
        self.connection.commit()

    def _run_file_operation(self):

        # TODO: 中断操作対応

        self.file_op_progress['task_num'] = len(self.file_op_tasks)

        self.file_op_progress['done_size'] = 0
        self.file_op_progress['all_size'] = 0
        for ftask in self.file_op_tasks:
            self.file_op_progress['all_size'] += ftask['src_size']

        start = time.time()

        for t_idx, ftask in enumerate(self.file_op_tasks):

            # 初期設定
            op_mode = ftask['operation']
            title = ftask['title']
            trg_path = ftask['dst_path']
            src_list = ftask['src_list']
            idx_offset = ftask['init_num']

            values_dict = {}
            values_dict['FileNum'] = ftask['init_num']
            values_dict['Size'] = ftask['init_size']

            self.file_op_progress['task_index'] = t_idx+1
            self.file_op_progress['title'] = title
            self.file_op_progress['file_num'] = len(src_list)
            self.file_op_progress['done_file'] = 0

            if op_mode in ['move', 'copy']:

                if not os.path.exists(trg_path):
                    os.mkdir(trg_path)

                for i, file_path in enumerate(src_list):
                    _, ext = os.path.splitext(file_path)
                    new_name = str(i + idx_offset).zfill(self.FILE_NUMBER_OF_DIGITS)
                    new_path = os.path.join(trg_path, new_name)
                    if ext == '.gif':
                        thum_dir = os.path.join(trg_path, '__thumbnail__')
                        if not os.path.exists(thum_dir):
                            os.mkdir(thum_dir)
                        self._gif_to_zip(file_path, new_path, thum_dir)
                        fsize = os.path.getsize(new_path + '.zip') / (1024*1024)
                        values_dict['Size'] += fsize
                    else:
                        # TODO: 上書き操作は仮で禁止にしている
                        new_path = new_path + ext
                        if not os.path.exists(new_path):
                            if op_mode == 'move':
                                shutil.move(file_path, new_path)
                            elif op_mode == 'copy':
                                shutil.copyfile(file_path, new_path)
                        fsize = os.path.getsize(new_path) / (1024*1024)
                        values_dict['Size'] += fsize
                    values_dict['FileNum'] += 1
                    self.file_op_progress['done_file'] += 1

                    # 処理速度、残り時間予測
                    self.file_op_progress['done_size'] += fsize
                    process_time = time.time() - start
                    if process_time != 0:
                        self.file_op_progress['speed'] = self.file_op_progress['done_size']/process_time # [MiB/s]

                    if self.file_op_progress['speed'] != 0:
                        self.file_op_progress['remaining_time'] = (self.file_op_progress['all_size'] - self.file_op_progress['done_size']) / self.file_op_progress['speed']

                values_dict['Updated'] = datetime.datetime.now()

            elif op_mode == 'delete':

                # deleteの場合はindexのリストが渡されている想定
                # renameも兼ねるため、結局trg_path内を全探索する

                title_dir, file_list, _ = self.get_file_list(title)

                new_favorite = []
                new_chapter = []
                count_new_idx = 0
                for i, fname in enumerate(file_list):

                    idx_str, ext = os.path.splitext(fname) # インデックスと拡張子に分解
                    idx = int(idx_str)

                    fpath = os.path.join(title_dir, fname)

                    if ext == '.zip':
                        thum_name = idx_str + '.png'
                        thum_path = os.path.join(title_dir, '__thumbnail__', thum_name)

                    if idx in src_list:
                        fsize = os.path.getsize(fpath) / (1024*1024)
                        os.remove(fpath)
                        if ext == '.zip':
                            os.remove(thum_path)
                        values_dict['FileNum'] -= 1
                        values_dict['Size'] -= fsize
                        self.file_op_progress['done_file'] += 1
                    else:
                        if idx != count_new_idx:
                            new_idx_str = str(count_new_idx).zfill(self.FILE_NUMBER_OF_DIGITS)
                            new_path = os.path.join(title_dir, new_idx_str + ext)
                            os.rename(fpath, new_path)
                            if ext == '.zip':
                                new_thum_path = os.path.join(title_dir, '__thumbnail__', new_idx_str + '.png')
                                os.rename(thum_path, new_thum_path)
                        if idx in ftask['init_favorite']:
                            new_favorite.append(count_new_idx)
                        if idx in ftask['init_chapter']:
                            new_chapter.append(count_new_idx)
                        count_new_idx += 1

                values_dict['favorite'] = sorted(new_favorite)
                values_dict['chapter'] = sorted(new_chapter)

            # データベース情報更新
            self.update_record(title, values_dict=values_dict)
            self.logger.debug('Copy Operation Finished')

    def _delete_titles(self, titles):

        for title in titles:
            del_path = os.path.join(self.data_dir, title)
            if os.path.exists(del_path):
                shutil.rmtree(del_path)

        self.logger.debug('Delete Operation Finished')

    def file_op_is_alive(self):
        return self.file_op_thread.is_alive()

    def get_file_op_progress(self):
        return copy.deepcopy(self.file_op_progress)

    def get_items(self, col_name, title=None, convert=False):
        """
        col_namesのリストに対するSELECT結果（tuple）を返す。
        covertをTrueにすると、tupleから変換して返す。
        　・col_nameがstrならlist
        　・col_nameがlistならcol_nameをkeyとしたdict
        """

        if type(col_name) is list:
            sql = 'SELECT {} FROM MainTable'.format(','.join(col_name))
        elif type(col_name) is str:
            sql = 'SELECT {} FROM MainTable'.format(col_name)
        else:
            return []

        if not title is None:
            sql += ' WHERE Title="{}"'.format(title)

        self.logger.debug(sql)
        self.cursor.execute(sql)

        result = self.cursor.fetchall()

        if convert:
            if type(col_name) is list:
                tmp_dict = {}
                for cl in col_name:
                    tmp_dict[cl] = []
                for row in result:
                    for i, cl in enumerate(col_name):
                        tmp_dict[cl].append(self._convert_list(row[i]))
                return tmp_dict
            elif type(col_name) is str:
                tmp_list = []
                for row in result:
                    tmp_list += self._convert_list(row[0])
                return tmp_list
        else:
            return result

    def get_titles(self, filter_option={}, init_chars=[], enable_or=False, sort_option=('Updated',True)):

        col_names = ['Title', 'FileNum', 'IsFavorite', 'InitialCharacter'] + list(filter_option.keys())

        sort_order = 'DESC' if sort_option[1] else 'ASC'
        sql = 'SELECT {} FROM MainTable ORDER BY {} {}'.format(','.join(col_names), sort_option[0], sort_order)
        ret = self.cursor.execute(sql)

        title_list = []
        for row in ret.fetchall():

            if len(init_chars) != 0:
                if not row[3] in init_chars:
                    continue

            if len(filter_option.keys()) == 0:
                flag = True
            else:
                flag = False if enable_or else True
                for i in range(4, len(col_names)):
                    # 値取得
                    ref_val = self._convert_list(row[i])
                    key = col_names[i]
                    f_val = filter_option[key]
                    for fv in f_val:
                        if enable_or:
                            flag |= (fv in ref_val)
                        else:
                            flag &= (fv in ref_val)
            if flag:
                title_list.append((row[0],row[1],row[2]))

        return title_list

    def get_file_list(self, title):

        file_dir = os.path.join(self.data_dir, title)

        if not os.path.exists(file_dir):
            return '', []

        #登録時に拡張子はフィルタされるのでファイルすべてを取得しているが、早くなるかは不明
        #tmp_list = sorted(glob.glob(os.path.join(file_dir, "*")))
        #file_list = [os.path.basename(r) for r in tmp_list]

        tmp_list, file_size = mutl.search_files(file_dir, self.SUPPORTED_EXT)
        #tmp_list = sorted(list(chain.from_iterable([glob.glob(os.path.join(file_dir, "*." + ext)) for ext in self.SUPPORTED_EXT])))

        file_list = [os.path.basename(r) for r in tmp_list]

        return file_dir, file_list, file_size

    # 追加項目操作
    def get_additional_table(self):
        """
        ユーザ作成のタグ一覧の取得
        (= MainTable以外のテーブル名の一覧)
        """
        table_list = []
        self.cursor.execute("select * from sqlite_master where type='table'")
        for x in self.cursor.fetchall():
            if not x[1] == 'MainTable':
                table_list.append(x[1])
        return table_list

    def add_tag(self, table, values_dict):
        """
        新規タグを追加する
            tagはMainTable内に存在するタグ種別名
            valuesは追加するタグ内容のリスト[Name, InitialCharacter]
        Nameが重複した場合はFalseリターン
        """
        if not 'Name' in values_dict.keys():
            return False
        elif self.tag_is_exist(table, values_dict['Name']):
            return False

        try:
            sql_tmp, sql_values = self._convert_dict4sql(values_dict)
            sql = 'insert into {} {}'.format(table, sql_tmp)
            #sql = 'insert into {}(Name, InitialCharacter, Link, IsFavorite, Image) VALUES(?,?,?,?,?)'.format(table)
            self.logger.debug('{} {}'.format(sql, sql_values))
            self.cursor.execute(sql, sql_values)
            self.connection.commit()

            return True
        except:
            return False

    def update_tag(self, table, tag_name, values_dict):
        """
        タグの情報を変更する。
        """
        if 'Name' in values_dict.keys():
            if self.tag_is_exist(table, values_dict['Name']):
                return False

        data_list = []

        for key, value in values_dict.items():

            if type(value) is list:
                tmp_val = LIST_DELIMITER.join([str(i) for i in value])
            else:
                tmp_val = value

            if key == 'Image':
                # valueが空欄の場合は削除指令

                im_path = self.get_tag_image(table,tag_name)
                try:
                    os.remove(im_path)
                except:
                    self.logger.debug('Failed to remove file. {}'.format(im_path))
                finally:
                    if value == '':
                        tmp_val = ''
                    else:
                        tmp_val = self._asign_tag_image(table, value, tag_name)

            data_list.append('{0}="{1}"'.format(key,tmp_val))

        sql_set_data = ','.join(data_list)
        sql = 'UPDATE {0} SET {1} WHERE Name="{2}"'.format(table, sql_set_data, tag_name)

        try:
            self.logger.debug(sql)
            self.cursor.execute(sql)
            self.connection.commit()
        except:
            return False

        # タグ名を変更した場合 - MainTableにも反映する
        if 'Name' in values_dict.keys():
            old_name = tag_name
            new_name = values_dict['Name']
            update_list = [] # tuple(Title, NewList)

            self._update_tag_image(table, old_name, new_name)

            sql = 'SELECT Title,{} FROM MainTable'.format(table)
            ret = self.cursor.execute(sql)

            for row in ret.fetchall():
                title = row[0]
                tag_list = self._convert_list(row[1])
                if old_name in tag_list:
                    new_list = [new_name if t == old_name else t for t in tag_list]
                    update_list.append((title,{table:copy.deepcopy(new_list)}))

            for ul in update_list:
                self.update_record(title=ul[0],values_dict=ul[1])

        return True

    def delete_tags(self, table, names):

        for name in names:
            sql = 'DELETE FROM {} WHERE Name="{}"'.format(table, name)

            im_path = self.get_tag_image(table, name)
            if im_path != '':
                try:
                    os.remove(im_path)
                except:
                    self.logger.debug('Failed to remove file. {}'.format(im_path))

            self.logger.debug(sql)
            self.cursor.execute(sql)
            self.connection.commit()

            # MainTableも変更しに行く
            update_list = [] # tuple(Title, NewList)
            sql = 'SELECT Title,{} FROM MainTable'.format(table)
            ret = self.cursor.execute(sql)

            for row in ret.fetchall():
                title = row[0]
                tmp_list = self._convert_list(row[1])

                if name in tmp_list:
                    tmp_list.remove(name)
                    update_list.append((title,{table:copy.deepcopy(tmp_list)}))
            for ul in update_list:
                self.update_record(title=ul[0],values_dict=ul[1])

        return

    def tag_is_exist(self, table, name):
        sql = 'SELECT COUNT(*) FROM {} WHERE Name="{}"'.format(table, name)
        self.cursor.execute(sql)
        result = self.cursor.fetchall()
        return result[0][0] != 0

    def get_tag_image(self, table, name):
        sql = 'SELECT Image FROM {} WHERE Name="{}"'.format(table, name)
        self.cursor.execute(sql)
        result = self.cursor.fetchall()
        if result[0][0] == '':
            return ''
        else:
            im_name = '{}{}'.format(name, result[0][0])
            return os.path.join(self.tag_dir, table, im_name)

    def _asign_tag_image(self, table, src_path, tag_name):

        tmp_path = os.path.join(self.tag_dir, table)
        if not os.path.exists(tmp_path):
            os.mkdir(tmp_path)

        _, ext = os.path.splitext(src_path)
        new_name = '{}{}'.format(tag_name, ext)

        try:
            shutil.copyfile(src_path, os.path.join(tmp_path, new_name))
        except:
            self.logger.debug('Failed to copy file. {}'.format(src_path))

        return ext

    def _update_tag_image(self, table, old_name, new_name):

        sql = 'SELECT Image FROM {} WHERE Name="{}"'.format(table, new_name)
        self.cursor.execute(sql)
        result = self.cursor.fetchall()
        if result[0][0] == '':
            return

        ext = result[0][0]

        old_im_path = os.path.join(self.tag_dir, table, '{}{}'.format(old_name, ext))
        new_im_path = os.path.join(self.tag_dir, table, '{}{}'.format(new_name, ext))

        try:
            os.rename(old_im_path, new_im_path)
        except:
            self.logger.debug('Failed to change name. {} -> {}'.format(old_im_path, new_im_path))

    def get_tag_list(self, tag):
        sql = 'SELECT * FROM {}'.format(tag)
        self.cursor.execute(sql)
        return self.cursor.fetchall()

    def get_tag_items_with_num(self, tag_table, init_chars=[]):
        """
        タグ内容に該当する項目数をカウントして返す。
        リスト項目があるためfor文ループをしている
        """
        sql = 'SELECT Name,InitialCharacter,IsFavorite FROM {}'.format(tag_table)

        tag_info = {}
        self.cursor.execute(sql)
        for row in self.cursor.fetchall():
            if len(init_chars) != 0:
                if row[1] in init_chars:
                    tag_info[row[0]] = [0, row[2]]
            else:
                tag_info[row[0]] = [0, row[2]]

        sql = 'SELECT {} FROM MainTable'.format(tag_table)
        self.cursor.execute(sql)
        for row in self.cursor.fetchall():
            item_list = self._convert_list(row[0])
            for il in item_list:
                if il in tag_info.keys():
                    tag_info[il][0] += 1

        return tag_info

    def get_tag_items(self, table, col_name, name=None, convert=False):
        """
        get_itemのタグ用のテーブル版
        """

        if type(col_name) is list:
            sql = 'SELECT {} FROM {}'.format(','.join(col_name), table)
        elif type(col_name) is str:
            sql = 'SELECT {} FROM {}'.format(col_name, table)
        else:
            return []

        if not name is None:
            sql += ' WHERE Name="{}"'.format(name)

        self.logger.debug(sql)
        ret = self.cursor.execute(sql)

        if convert:
            if type(col_name) is list:
                tmp_dict = {}
                for cl in col_name:
                    tmp_dict[cl] = []
                for row in ret.fetchall():
                    for i, cl in enumerate(col_name):
                        tmp_dict[cl].append(self._convert_list(row[i]))
                return tmp_dict
            elif type(col_name) is str:
                tmp_list = []
                for row in ret.fetchall():
                    tmp_list += self._convert_list(row[0])
                return tmp_list
        else:
            return ret.fetchall()

    def tag_backup(self):

        date_str = datetime.datetime.now().strftime('%Y%m%d%H%M')
        save_dir = os.path.join(self.db_root, self.BACKUP_DIR, date_str)

        if not os.path.exists(save_dir):
            os.makedirs(save_dir, exist_ok=True)

        table_list = self.get_additional_table()
        for table in table_list:
            fname = os.path.join(save_dir, table + '.csv')
            with open(fname, "w", encoding=self.FILE_ENCODING) as write_file:
                writer = csv.writer(write_file, lineterminator='\n')
                sql = 'SELECT Name,InitialCharacter,Link,IsFavorite FROM {}'.format(table)
                for row in self.cursor.execute(sql):
                    writer.writerow(list(row))
                    #write_file.write(write_txt)

    def add_tag_batch(self, table, path):
        """
        CSVファイルを使ってタグを追加する.
        [Name, InitialCharacter, Link, IsFavoriteの順]
        """
        success_tags = []

        if not os.path.exists(path):
            return success_tags

        with open(path, "r", encoding=self.FILE_ENCODING) as read_file:
            reader = csv.reader(read_file)

            for row in reader:

                num = len(row)
                if num < 2:
                    continue
                elif (row[0] == '') | (row[1] == ''):
                    continue

                values_dict = {
                    'Name':row[0],
                    'InitialCharacter':row[1],
                    'Link':'' if num < 3 else row[2],
                    'IsFavorite':'' if num < 4 else row[3],
                    'Image':''
                }

                if self.add_tag(table, values_dict):
                    success_tags.append(row[0])

        return success_tags

    def show_all(self):
        sql = 'SELECT * FROM MainTable'
        ret = self.cursor.execute(sql)
        for row in ret.fetchall():
            print(row)

    def _convert_dict4sql(self, input_dict):
        """
        辞書形式のデータをSQLのVALUES文に対応させる。
        プレースホルダー型。
        """

        key_list = []
        tmp_list = []
        values = []

        for key, value in input_dict.items():
            key_list.append(key)
            tmp_list.append('?')

            if type(value) is list:
                values.append(LIST_DELIMITER.join([str(i) for i in value]))
            else:
                values.append(value)

        key_list_str = ','.join(key_list)
        tmp_list_str = ','.join(tmp_list)

        sql = '({0}) values ({1})'.format(key_list_str, tmp_list_str)
        sql_values = tuple(values)

        return sql, sql_values

    def _convert_list(self, src):
        if type(src) is str:
            tmp_list = src.split(LIST_DELIMITER)
            return tmp_list
        else:
            return list([src])

    def _gif_to_zip(self, src_gif, dst_dir, thum_dir):

        if not os.path.exists(dst_dir):
            os.mkdir(dst_dir)

        gif = Image.open(src_gif)
        for i, f in enumerate(ImageSequence.Iterator(gif)):
            if i == 0:
                thum_name = os.path.basename(dst_dir) + '.png'
                thum_path = '{}/{}'.format(thum_dir, thum_name)
                f.save(thum_path)

            img_name = str(i).zfill(3) + ".png"
            img_path = '{}/{}'.format(dst_dir, img_name)
            #print(img_path)
            f.save(img_path)

        """
        thum_name = os.path.basename(dst_dir)
        for f in frames:
            name = '{}/{}{}'.format(thum_dir, thum_name, '.gif')
            f.save(name)
            break
        """
        shutil.make_archive(dst_dir, 'zip', dst_dir)
        shutil.rmtree(dst_dir)


from flask import Flask
from flask import request
from flask import jsonify
from flask import Response
from flask import abort
from flask_cors import CORS
from weather import weather
from api_errors import *
import datetime

app = Flask(__name__)
app.url_map.strict_slashes = False
cors = CORS(app)

@app.errorhandler(ApiError)
def handle_api_error(error):
    response = jsonify(error.to_dict())
    response.status_code = error.status_code
    return response

@app.route('/api/historical', methods=['GET'])
def historical():
    dates = weather.get_historical()
    date_dict_array = [{'DATE':date} for date in dates]
    return jsonify(date_dict_array), 200

@app.route('/api/historical/<date>', methods=['GET'])
def get_date(date):
    validate_date(date)
    date_info = weather.get_date(date)
    return jsonify(date_info), 200

@app.route('/api/historical', methods=['POST'])
def add_date():
    content = request.get_json()
    if 'DATE' not in content or 'TMAX' not in content or 'TMIN' not in content:
        raise ApiError('A parameter is missing.', status_code=400)

    validate_date(content['DATE'])
    date_text = content['DATE']

    tmax = 0.0
    try:
        tmax = float(content['TMAX'])
    except ValueError:
        raise ApiError('TMAX cannot be converted to a float.', status_code=400)

    tmin = 0.0
    try:
        tmin = float(content['TMIN'])
    except ValueError:
        raise ApiError('TMIN cannot be converted to a float.', status_code=400)

    date = weather.add_date(date_text, tmax, tmin)
    return jsonify({'DATE':date['DATE']}), 201

@app.route('/api/forecast/<start_date>', methods=['GET'])
def get_forecast(start_date):
    validate_date(start_date)
    forecast = weather.get_forecast(start_date)
    return jsonify(forecast), 200

@app.route('/api/historical/<date>', methods=['DELETE'])
def delete_date(date):
    validate_date(date)
    weather.delete_date(date)
    return ('', 204)

def validate_date(date_text):
    if type(date_text) is not str:
        raise ApiError("Incorrect data type.", 400)
    try:
        if date_text != datetime.datetime.strptime(date_text, r'%Y%m%d').strftime(r'%Y%m%d'):
            raise ValueError
    except ValueError:
        raise ApiError("Incorrect date format, should be YYYYMMDD.", 400)

# Start flask server when calling on the file
if __name__ == '__main__':
    app.run(host='0.0.0.0', debug=False, port=80)


from datetime import timedelta
from functools import update_wrapper
from flask import Flask, json, render_template, request, redirect, jsonify, request, make_response
from catboost import CatBoostRegressor
from flask.globals import current_app
from flask.helpers import make_response
from flask_sqlalchemy import SQLAlchemy
import sqlite3
from flask_cors import CORS
from Python_algo.support import user_details

import pandas as pd
import numpy as np
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///burnout.db'
db = SQLAlchemy(app)
CORS(app)

db_file = "burnout.db"

# Entry class for Db stuff
class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    emp_id = db.Column(db.String(25), unique=True, nullable=False)
    date = db.Column(db.String(20), nullable=False)
    Gender = db.Column(db.String(6), nullable=False)
    company = db.Column(db.String(10), nullable=False)
    WFH = db.Column(db.String(10), nullable=False)
    Designation = db.Column(db.Float, nullable=False)
    Resource_Allocation = db.Column(db.Float, nullable=False)

    def __repr__(self):
        return f"User('{self.emp_id}', '{self.date}', '{self.Gender}', {self.Designation}, {self.Resource_Allocation})"

class bout(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    emp_id = db.Column(db.String(25), nullable=False)
    Burn = db.Column(db.Float, nullable=False)

    def __repr__(self):
        return f"User('{self.emp_id}', {self.fat})"

def check_user_db(emp_id):
    conn = sqlite3.connect(db_file)
    cur = conn.cursor()
    names = cur.execute(
        "SELECT emp_id FROM User WHERE emp_id='{emp_id}'".format(emp_id=emp_id))
    nam = names.fetchall()
    for i in nam:
        if(i[0] == emp_id):
            return True
        else:
            return False

from_file = CatBoostRegressor()
model = from_file.load_model("model.pkl")

@app.route('/')
def hello_world():
    return render_template("index.html")

@app.route('/error')
def error():
    return render_template("404.html")

@app.route('/login', methods=['POST'])
def signup():
    req = request.form

    emp1 = str(req.get('employee_id'))
    Men = float(req.get('mental_fatigue'))
    print(emp1, Men)
    respo = "You are not a user, Please sign up"

    details = user_details(emp1, Men)
    burnout = model.predict(details)

    if (check_user_db(emp1)):
        try:
            entry = bout(emp_id=emp1, Burn=burnout)
            db.session.add(entry)
            db.session.commit()

            return str(burnout)
        except Exception as e:
            return str(burnout)
    else:
        return respo

@app.route('/submit', methods=['POST'])
def submit():
    if request.method == 'POST':

        emp = request.form['Employee Id']
        date_emp = (request.form['date'])
        Gender = int(request.form['Gender'])
        Com = int(request.form['Company type'])
        WFH = int(request.form['WFH'])
        Des = float(request.form['Designation'])
        Res = float(request.form['Resorce Allocation'])

        if (not check_user_db(emp)):
            if(Gender == 0):
                G="Female"
            else:
                G="Male"
            if Com == 0:
                c = "Service"
            else:
                c = "Product"
            if WFH == 0:
                w = "Not WFH"
            else:
                w = "WFH"
            # try:
            entry = User(emp_id=emp, date=date_emp, Gender=G, company=c,
                         WFH=w, Designation=Des, Resource_Allocation=Res)
            db.session.add(entry)
            db.session.commit()

            return redirect("/")

        else:
            return "You are already registered! Please login!!"

if __name__ == '__main__':
    app.run(debug=True)


# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.utils.translation import gettext_lazy as __
from django.shortcuts import redirect, reverse
from django.shortcuts import render
from django.db import transaction
from django.contrib.auth.decorators import login_required
from django.http import HttpResponseRedirect
from django import forms

from bioresources.models.Resource import Collaboration
from bioseq.models.Taxon import  Taxon

@login_required
def submission_start(request):
    return render(request, 'submission/submission_start.html', {})

from django_select2.forms import ModelSelect2Widget

class TaxSelect(ModelSelect2Widget):
    def label_from_instance(self,obj):
        return str(obj.scientific_name())

class TaxChoiceField(forms.ChoiceField):
    def valid_value(self, value):
        return True
    def clean(self, value):
        value = super(self.__class__,self).clean(value)
        if value:
            return Taxon.objects.get(taxon_id=value)
        return None

def form_clean_data(form):
    cleaned_data = super(form.__class__, form).clean()
    qs = form._meta.model.objects.filter(name=cleaned_data["name"])
    # if cleaned_data["ncbi_tax"]:
    #     form.data["ncbi_tax"] = Taxon.objects.get(taxon_id=cleaned_data["ncbi_tax"])
    if "pk" in form.data:
        if qs.exclude(id=form.data["pk"]).exists():
            form._errors['name'] = form._errors.get('name', [])
            form._errors['name'].append(__("%s already exists") % cleaned_data["name"])
    else:
        if qs.exists():
            form._errors['name'] = form._errors.get('name', [])
            form._errors['name'].append(__("%s already exists") % cleaned_data["name"])

def submit_model(form_class, request):
    if request.method == 'POST':
        if "pk" in request.GET:
            obj = form_class._meta.model.objects.get(id=request.GET["pk"])
            form = form_class(request.POST, instance=obj)
        else:
            form = form_class(request.POST)

        if form.is_valid():
            with transaction.atomic():
                obj = form.save()
                if not Collaboration.objects.filter(resource=obj, person=request.user.person).exists():
                    Collaboration.objects.create(resource=obj, person=request.user.person,
                                                 type=Collaboration.COLLABORATION_TYPES.owner)
            return HttpResponseRedirect(reverse("bioresources:" + obj.type_name() + "_view", args=[obj.id]))
    else:
        if "pk" in request.GET:
            resource = form_class._meta.model.objects.get(id=request.GET["pk"])
            form = form_class(instance=resource)
        else:
            form = form_class()

    data = {'form': form}
    if "pk" in request.GET:
        data["pk"] = request.GET["pk"]

    return render(request, 'submission/tool_submission.html', data)


import random
import discord
from discord.ext import commands

from .inputs import cl, cf, chill, cfe, ur
from .utils import COLOR

class Coffee(commands.Cog):
    def __init__(self, client):
        self.client = client

    @commands.command(aliases=['ask_out'])
    async def wannagrabacoffee(self, ctx, *, member: discord.Member):
        '''Wanna ask someone out on coffee'''
        embed = discord.Embed(
            title=f'{member}, Someone wants to grab a coffee with you...*wink *wink',
            color=COLOR.DEFAULT)
        embed.add_field(name='This happened....', value=f'{random.choice(cf)}')
        embed.set_footer(text='not actually')
        await ctx.send(embed=embed)

    @commands.command(aliases=['brew'])
    async def coffee(self, ctx):
        '''A lovely coffee command (sip, sip)'''
        op = f'{random.choice(cfe)}'
        embed = discord.Embed(title='Coffee',
                              description=op,
                              color=COLOR.DEFAULT)
        embed.set_footer(
            text=f'Caffeiene Level-{random.choice(cl)}.{random.choice(chill)}')
        embed.set_image(url=random.choice(ur))
        await ctx.send(embed=embed)

def setup(client):
    client.add_cog(Coffee(client))