album .tar
This commit is contained in:
parent
c493362520
commit
7ad6160d38
8 changed files with 69 additions and 164 deletions
|
@ -1,114 +0,0 @@
|
||||||
start_time = time.time()
|
|
||||||
|
|
||||||
|
|
||||||
# Raise for cases where the minimum > maximum
|
|
||||||
for (maxkey, maxval) in maximums.items():
|
|
||||||
if maxkey not in minimums:
|
|
||||||
continue
|
|
||||||
minval = minimums[maxkey]
|
|
||||||
if minval > maxval:
|
|
||||||
raise ValueError('Impossible min-max for %s' % maxkey)
|
|
||||||
|
|
||||||
conditions = []
|
|
||||||
minmaxers = {'<=': maximums, '>=': minimums}
|
|
||||||
|
|
||||||
# Convert the min-max parameters into query strings
|
|
||||||
print('Writing minmaxers')
|
|
||||||
for (comparator, minmaxer) in minmaxers.items():
|
|
||||||
for (field, value) in minmaxer.items():
|
|
||||||
if field not in Photo.int_properties:
|
|
||||||
raise ValueError('Unknown Photo property: %s' % field)
|
|
||||||
|
|
||||||
value = str(value)
|
|
||||||
query = min_max_query_builder(field, comparator, value)
|
|
||||||
conditions.append(query)
|
|
||||||
|
|
||||||
print(conditions)
|
|
||||||
|
|
||||||
print('Writing extension rule')
|
|
||||||
if extension is not None:
|
|
||||||
if isinstance(extension, str):
|
|
||||||
extension = [extension]
|
|
||||||
|
|
||||||
# Normalize to prevent injections
|
|
||||||
extension = [normalize_tagname(e) for e in extension]
|
|
||||||
extension = ['extension == "%s"' % e for e in extension]
|
|
||||||
extension = ' OR '.join(extension)
|
|
||||||
extension = '(%s)' % extension
|
|
||||||
conditions.append(extension)
|
|
||||||
|
|
||||||
def setify(l):
|
|
||||||
if l is None:
|
|
||||||
return set()
|
|
||||||
else:
|
|
||||||
return set(self.get_tag_by_name(t) for t in l)
|
|
||||||
|
|
||||||
tag_musts = setify(tag_musts)
|
|
||||||
tag_mays = setify(tag_mays)
|
|
||||||
tag_forbids = setify(tag_forbids)
|
|
||||||
|
|
||||||
base = '''
|
|
||||||
{negator} EXISTS(
|
|
||||||
SELECT 1 FROM photo_tag_rel
|
|
||||||
WHERE photo_tag_rel.photoid == photos.id
|
|
||||||
AND photo_tag_rel.tagid {operator} {value}
|
|
||||||
)'''
|
|
||||||
|
|
||||||
print('Writing musts')
|
|
||||||
for tag in tag_musts:
|
|
||||||
# tagid == must
|
|
||||||
query = base.format(
|
|
||||||
negator='',
|
|
||||||
operator='==',
|
|
||||||
value='"%s"' % tag.id,
|
|
||||||
)
|
|
||||||
conditions.append(query)
|
|
||||||
|
|
||||||
print('Writing mays')
|
|
||||||
if len(tag_mays) > 0:
|
|
||||||
# not any(tagid not in mays)
|
|
||||||
acceptable = tag_mays.union(tag_musts)
|
|
||||||
acceptable = ['"%s"' % t.id for t in acceptable]
|
|
||||||
acceptable = ', '.join(acceptable)
|
|
||||||
query = base.format(
|
|
||||||
negator='',
|
|
||||||
operator='IN',
|
|
||||||
value='(%s)' % acceptable,
|
|
||||||
)
|
|
||||||
conditions.append(query)
|
|
||||||
|
|
||||||
print('Writing forbids')
|
|
||||||
if len(tag_forbids) > 0:
|
|
||||||
# not any(tagid in forbids)
|
|
||||||
forbids = ['"%s"' % t.id for t in tag_forbids]
|
|
||||||
forbids = ', '.join(forbids)
|
|
||||||
query = base.format(
|
|
||||||
negator='NOT',
|
|
||||||
operator='IN',
|
|
||||||
value='(%s)' % forbids
|
|
||||||
)
|
|
||||||
conditions.append(query)
|
|
||||||
|
|
||||||
if len(conditions) == 0:
|
|
||||||
raise ValueError('No search query provided')
|
|
||||||
|
|
||||||
conditions = [query for query in conditions if query is not None]
|
|
||||||
conditions = ['(%s)' % c for c in conditions]
|
|
||||||
conditions = ' AND '.join(conditions)
|
|
||||||
conditions = 'WHERE %s' % conditions
|
|
||||||
|
|
||||||
query = 'SELECT * FROM photos %s' % conditions
|
|
||||||
query = query.replace('\n', ' ')
|
|
||||||
while ' ' in query:
|
|
||||||
query = query.replace(' ', ' ')
|
|
||||||
print(query)
|
|
||||||
|
|
||||||
temp_cur = self.sql.cursor()
|
|
||||||
temp_cur.execute(query)
|
|
||||||
|
|
||||||
for fetch in fetch_generator(temp_cur):
|
|
||||||
photo = Photo(self, fetch)
|
|
||||||
yield photo
|
|
||||||
|
|
||||||
end_time = time.time()
|
|
||||||
print(end_time - start_time)
|
|
27
etiquette/decorators.py
Normal file
27
etiquette/decorators.py
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
from flask import request
|
||||||
|
import uuid
|
||||||
|
|
||||||
|
|
||||||
|
def _generate_session_token():
|
||||||
|
token = str(uuid.uuid4())
|
||||||
|
#print('MAKE SESSION', token)
|
||||||
|
return token
|
||||||
|
def give_session_token(function):
|
||||||
|
@functools.wraps(function)
|
||||||
|
def wrapped(*args, **kwargs):
|
||||||
|
# Inject new token so the function doesn't know the difference
|
||||||
|
token = request.cookies.get('etiquette_session', None)
|
||||||
|
if not token:
|
||||||
|
token = _generate_session_token()
|
||||||
|
request.cookies = dict(request.cookies)
|
||||||
|
request.cookies['etiquette_session'] = token
|
||||||
|
|
||||||
|
ret = function(*args, **kwargs)
|
||||||
|
|
||||||
|
# Send the token back to the client
|
||||||
|
if not isinstance(ret, flask.Response):
|
||||||
|
ret = flask.Response(ret)
|
||||||
|
ret.set_cookie('etiquette_session', value=token, max_age=60)
|
||||||
|
|
||||||
|
return ret
|
||||||
|
return wrapped
|
|
@ -11,11 +11,20 @@ import re
|
||||||
import requests
|
import requests
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
import uuid
|
|
||||||
import warnings
|
import warnings
|
||||||
|
|
||||||
import phototagger
|
import phototagger
|
||||||
sys.path.append('C:\\git\\else\\Bytestring'); import bytestring
|
|
||||||
|
try:
|
||||||
|
sys.path.append('C:\\git\\else\\Bytestring')
|
||||||
|
sys.path.append('C:\\git\\else\\WebstreamZip')
|
||||||
|
import bytestring
|
||||||
|
import webstreamzip
|
||||||
|
except ImportError:
|
||||||
|
# pip install
|
||||||
|
# https://raw.githubusercontent.com/voussoir/else/master/_voussoirkit/voussoirkit.zip
|
||||||
|
from vousoirkit import bytestring
|
||||||
|
from vousoirkit import webstreamzip
|
||||||
|
|
||||||
site = flask.Flask(__name__)
|
site = flask.Flask(__name__)
|
||||||
site.config.update(
|
site.config.update(
|
||||||
|
@ -23,6 +32,7 @@ site.config.update(
|
||||||
TEMPLATES_AUTO_RELOAD=True,
|
TEMPLATES_AUTO_RELOAD=True,
|
||||||
)
|
)
|
||||||
site.jinja_env.add_extension('jinja2.ext.do')
|
site.jinja_env.add_extension('jinja2.ext.do')
|
||||||
|
#site.debug = True
|
||||||
|
|
||||||
P = phototagger.PhotoDB()
|
P = phototagger.PhotoDB()
|
||||||
|
|
||||||
|
@ -45,25 +55,7 @@ ERROR_NO_SUCH_TAG = 'Doesn\'t exist'
|
||||||
####################################################################################################
|
####################################################################################################
|
||||||
####################################################################################################
|
####################################################################################################
|
||||||
|
|
||||||
def give_session_token(function):
|
|
||||||
@functools.wraps(function)
|
|
||||||
def wrapped(*args, **kwargs):
|
|
||||||
# Inject new token so the function doesn't know the difference
|
|
||||||
token = request.cookies.get('etiquette_session', None)
|
|
||||||
if not token:
|
|
||||||
token = generate_session_token()
|
|
||||||
request.cookies = dict(request.cookies)
|
|
||||||
request.cookies['etiquette_session'] = token
|
|
||||||
|
|
||||||
ret = function(*args, **kwargs)
|
|
||||||
|
|
||||||
# Send the token back to the client
|
|
||||||
if not isinstance(ret, flask.Response):
|
|
||||||
ret = flask.Response(ret)
|
|
||||||
ret.set_cookie('etiquette_session', value=token, max_age=60)
|
|
||||||
|
|
||||||
return ret
|
|
||||||
return wrapped
|
|
||||||
|
|
||||||
def _helper_comma_split(s):
|
def _helper_comma_split(s):
|
||||||
if s is None:
|
if s is None:
|
||||||
|
@ -109,11 +101,6 @@ def edit_params(original, modifications):
|
||||||
new_params = '?' + new_params
|
new_params = '?' + new_params
|
||||||
return new_params
|
return new_params
|
||||||
|
|
||||||
def generate_session_token():
|
|
||||||
token = str(uuid.uuid4())
|
|
||||||
#print('MAKE SESSION', token)
|
|
||||||
return token
|
|
||||||
|
|
||||||
def make_json_response(j, *args, **kwargs):
|
def make_json_response(j, *args, **kwargs):
|
||||||
dumped = json.dumps(j)
|
dumped = json.dumps(j)
|
||||||
response = flask.Response(dumped, *args, **kwargs)
|
response = flask.Response(dumped, *args, **kwargs)
|
||||||
|
@ -124,7 +111,7 @@ def P_album(albumid):
|
||||||
try:
|
try:
|
||||||
return P.get_album(albumid)
|
return P.get_album(albumid)
|
||||||
except phototagger.NoSuchAlbum:
|
except phototagger.NoSuchAlbum:
|
||||||
flask.abort(404, 'That tag doesnt exist')
|
flask.abort(404, 'That album doesnt exist')
|
||||||
|
|
||||||
def P_photo(photoid):
|
def P_photo(photoid):
|
||||||
try:
|
try:
|
||||||
|
@ -329,6 +316,16 @@ def get_album_json(albumid):
|
||||||
album = get_album_core(albumid)
|
album = get_album_core(albumid)
|
||||||
return make_json_response(album)
|
return make_json_response(album)
|
||||||
|
|
||||||
|
@site.route('/album/<albumid>.tar')
|
||||||
|
def get_album_tar(albumid):
|
||||||
|
album = P_album(albumid)
|
||||||
|
photos = list(album.walk_photos())
|
||||||
|
zipname_map = {p.real_filepath: '%s - %s' % (p.id, p.basename) for p in photos}
|
||||||
|
streamed_zip = webstreamzip.stream_tar(zipname_map)
|
||||||
|
content_length = sum(p.bytes for p in photos)
|
||||||
|
outgoing_headers = {'Content-Type': 'application/octet-stream'}
|
||||||
|
return flask.Response(streamed_zip, headers=outgoing_headers)
|
||||||
|
|
||||||
@site.route('/albums')
|
@site.route('/albums')
|
||||||
@give_session_token
|
@give_session_token
|
||||||
def get_albums_html():
|
def get_albums_html():
|
||||||
|
@ -391,7 +388,7 @@ def get_photo_json(photoid):
|
||||||
return photo
|
return photo
|
||||||
|
|
||||||
def get_search_core():
|
def get_search_core():
|
||||||
print(request.args)
|
#print(request.args)
|
||||||
|
|
||||||
# FILENAME & EXTENSION
|
# FILENAME & EXTENSION
|
||||||
filename_terms = request.args.get('filename', None)
|
filename_terms = request.args.get('filename', None)
|
||||||
|
@ -480,7 +477,7 @@ def get_search_core():
|
||||||
|
|
||||||
'warn_bad_tags': True,
|
'warn_bad_tags': True,
|
||||||
}
|
}
|
||||||
print(search_kwargs)
|
#print(search_kwargs)
|
||||||
with warnings.catch_warnings(record=True) as catcher:
|
with warnings.catch_warnings(record=True) as catcher:
|
||||||
photos = list(P.search(**search_kwargs))
|
photos = list(P.search(**search_kwargs))
|
||||||
photos = [jsonify_photo(photo) for photo in photos]
|
photos = [jsonify_photo(photo) for photo in photos]
|
||||||
|
|
|
@ -15,8 +15,8 @@ if port == 443:
|
||||||
http = gevent.pywsgi.WSGIServer(
|
http = gevent.pywsgi.WSGIServer(
|
||||||
('', port),
|
('', port),
|
||||||
etiquette.site,
|
etiquette.site,
|
||||||
keyfile='etiquette.key',
|
keyfile='https\\etiquette.key',
|
||||||
certfile='etiquette.crt',
|
certfile='https\\etiquette.crt',
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
http = gevent.wsgi.WSGIServer(('', port), etiquette.site)
|
http = gevent.wsgi.WSGIServer(('', port), etiquette.site)
|
||||||
|
|
|
@ -220,6 +220,8 @@ def _helper_extension(ext):
|
||||||
|
|
||||||
def _helper_filenamefilter(subject, terms):
|
def _helper_filenamefilter(subject, terms):
|
||||||
basename = subject.lower()
|
basename = subject.lower()
|
||||||
|
#print(basename)
|
||||||
|
#print(terms)
|
||||||
return all(term in basename for term in terms)
|
return all(term in basename for term in terms)
|
||||||
|
|
||||||
def _helper_minmax(key, value, minimums, maximums):
|
def _helper_minmax(key, value, minimums, maximums):
|
||||||
|
@ -320,6 +322,8 @@ def _helper_unitconvert(value):
|
||||||
return None
|
return None
|
||||||
if ':' in value:
|
if ':' in value:
|
||||||
return hms_to_seconds(value)
|
return hms_to_seconds(value)
|
||||||
|
elif all(c in '0123456789.' for c in value):
|
||||||
|
return float(value)
|
||||||
else:
|
else:
|
||||||
return bytestring.parsebytes(value)
|
return bytestring.parsebytes(value)
|
||||||
|
|
||||||
|
@ -1638,10 +1642,10 @@ class Album(ObjectBase, GroupableMixin):
|
||||||
return 'Album:{id}'.format(id=self.id)
|
return 'Album:{id}'.format(id=self.id)
|
||||||
|
|
||||||
def add_photo(self, photo, commit=True):
|
def add_photo(self, photo, commit=True):
|
||||||
if self.has_photo(photo):
|
|
||||||
return
|
|
||||||
if self.photodb != photo.photodb:
|
if self.photodb != photo.photodb:
|
||||||
raise ValueError('Not the same PhotoDB')
|
raise ValueError('Not the same PhotoDB')
|
||||||
|
if self.has_photo(photo):
|
||||||
|
return
|
||||||
self.photodb.cur.execute('INSERT INTO album_photo_rel VALUES(?, ?)', [self.id, photo.id])
|
self.photodb.cur.execute('INSERT INTO album_photo_rel VALUES(?, ?)', [self.id, photo.id])
|
||||||
if commit:
|
if commit:
|
||||||
log.debug('Committing - add photo to album')
|
log.debug('Committing - add photo to album')
|
||||||
|
@ -1687,6 +1691,7 @@ class Album(ObjectBase, GroupableMixin):
|
||||||
'SELECT * FROM album_photo_rel WHERE albumid == ? AND photoid == ?',
|
'SELECT * FROM album_photo_rel WHERE albumid == ? AND photoid == ?',
|
||||||
[self.id, photo.id]
|
[self.id, photo.id]
|
||||||
)
|
)
|
||||||
|
return self.photodb.cur.fetchone() is not None
|
||||||
|
|
||||||
def photos(self):
|
def photos(self):
|
||||||
photos = []
|
photos = []
|
||||||
|
@ -1832,7 +1837,7 @@ class Photo(ObjectBase):
|
||||||
return_filepath = hopeful_filepath
|
return_filepath = hopeful_filepath
|
||||||
|
|
||||||
elif mime == 'video' and ffmpeg:
|
elif mime == 'video' and ffmpeg:
|
||||||
print('video')
|
#print('video')
|
||||||
probe = ffmpeg.probe(self.real_filepath)
|
probe = ffmpeg.probe(self.real_filepath)
|
||||||
try:
|
try:
|
||||||
if probe.video:
|
if probe.video:
|
||||||
|
|
|
@ -1,16 +0,0 @@
|
||||||
for p in P.get_photos():
|
|
||||||
g=P.cur.execute('UPDATE photos SET id==? WHERE id==?', [p.id[-12:], p.id])
|
|
||||||
g=P.cur.execute('UPDATE photo_tag_rel SET photoid==? WHERE photoid==?', [p.id[-12:], p.id])
|
|
||||||
g=P.cur.execute('UPDATE album_photo_rel SET photoid==? WHERE photoid==?', [p.id[-12:], p.id])
|
|
||||||
|
|
||||||
for t in P.get_tags():
|
|
||||||
g=P.cur.execute('UPDATE tags SET id==? WHERE id==?', [t.id[-12:], t.id])
|
|
||||||
g=P.cur.execute('UPDATE photo_tag_rel SET tagid==? WHERE tagid==?', [t.id[-12:], t.id])
|
|
||||||
g=P.cur.execute('UPDATE tag_group_rel SET parentid==? WHERE parentid==?', [t.id[-12:], t.id])
|
|
||||||
g=P.cur.execute('UPDATE tag_group_rel SET memberid==? WHERE memberid==?', [t.id[-12:], t.id])
|
|
||||||
|
|
||||||
for a in P.get_albums():
|
|
||||||
g=P.cur.execute('UPDATE albums SET id==? WHERE id==?', [a.id[-12:], a.id])
|
|
||||||
g=P.cur.execute('UPDATE tag_group_rel SET parentid==? WHERE parentid==?', [a.id[-12:], a.id])
|
|
||||||
g=P.cur.execute('UPDATE tag_group_rel SET memberid==? WHERE memberid==?', [a.id[-12:], a.id])
|
|
||||||
g=P.cur.execute('UPDATE album_photo_rel SET albumid==? WHERE albumid==?', [a.id[-12:], a.id])
|
|
|
@ -22,6 +22,8 @@
|
||||||
{% set parent=album["parent"] %}
|
{% set parent=album["parent"] %}
|
||||||
{% if parent %}
|
{% if parent %}
|
||||||
<h3>Parent: <a href="/album/{{parent["id"]}}">{{parent.title}}</a></h3>
|
<h3>Parent: <a href="/album/{{parent["id"]}}">{{parent.title}}</a></h3>
|
||||||
|
{% else %}
|
||||||
|
<h3>Parent: <a href="/albums">Albums</a></h3>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if child_albums %}
|
{% if child_albums %}
|
||||||
<h3>Sub-albums</h3>
|
<h3>Sub-albums</h3>
|
||||||
|
@ -37,6 +39,7 @@
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
<span><a href="/album/{{album["id"]}}.tar">(download .tar)</a></span>
|
||||||
{% if photos %}
|
{% if photos %}
|
||||||
<h3>Photos</h3>
|
<h3>Photos</h3>
|
||||||
<ul>
|
<ul>
|
||||||
|
|
|
@ -389,6 +389,8 @@ function submit_search()
|
||||||
var boxname = basic_inputs[index].name;
|
var boxname = basic_inputs[index].name;
|
||||||
var box = document.getElementsByName(boxname)[0];
|
var box = document.getElementsByName(boxname)[0];
|
||||||
var value = box.value;
|
var value = box.value;
|
||||||
|
value = value.split("&").join("%26");
|
||||||
|
console.log(value);
|
||||||
if (boxname == "has_tags" && has_tag_params && value == "no")
|
if (boxname == "has_tags" && has_tag_params && value == "no")
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
|
@ -401,7 +403,7 @@ function submit_search()
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
parameters.push(boxname + "=" + box.value);
|
parameters.push(boxname + "=" + value);
|
||||||
}
|
}
|
||||||
|
|
||||||
orderby_rows = document.getElementsByClassName("search_builder_orderby_li");
|
orderby_rows = document.getElementsByClassName("search_builder_orderby_li");
|
||||||
|
@ -425,6 +427,7 @@ function submit_search()
|
||||||
parameters = "?" + parameters;
|
parameters = "?" + parameters;
|
||||||
url = url + parameters;
|
url = url + parameters;
|
||||||
}
|
}
|
||||||
|
console.log(url);
|
||||||
window.location.href = url;
|
window.location.href = url;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue