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