Include album info as txt in zip; fix normalize_filepath bugs

This commit is contained in:
voussoir 2016-12-20 19:53:06 -08:00
parent e992b76db0
commit af40f24dd8
4 changed files with 62 additions and 34 deletions

View file

@ -279,11 +279,20 @@ def get_album_zip(albumid):
for (real_filepath, arcname) in arcnames.items(): for (real_filepath, arcname) in arcnames.items():
streamed_zip.write(real_filepath, arcname=arcname) streamed_zip.write(real_filepath, arcname=arcname)
#if album.description: directories = helpers.album_zip_directories(album, recursive=recursive)
# streamed_zip.writestr( for (inner_album, directory) in directories.items():
# arcname='%s.txt' % album.id, text = []
# data=album.description.encode('utf-8'), if inner_album.title:
# ) text.append(inner_album.title)
if inner_album.description:
text.append(inner_album.description)
if not text:
continue
text = '\r\n\r\n'.join(text)
streamed_zip.writestr(
arcname=os.path.join(directory, '%s.txt' % inner_album.id),
data=text.encode('utf-8'),
)
if album.title: if album.title:
download_as = '%s - %s.zip' % (album.id, album.title) download_as = '%s - %s.zip' % (album.id, album.title)

View file

@ -9,6 +9,27 @@ import exceptions
from voussoirkit import bytestring from voussoirkit import bytestring
def album_zip_directories(album, recursive=True):
'''
Given an album, produce a dictionary mapping Album objects to directory
names as they will appear inside the zip archive.
Sub-albums become subfolders.
'''
directories = {}
if album.title:
root_folder = '%s - %s' % (album.id, normalize_filepath(album.title))
else:
root_folder = '%s' % album.id
directories[album] = root_folder
if recursive:
for child_album in album.children():
child_directories = album_zip_directories(child_album, recursive=True)
for (child_album, child_directory) in child_directories.items():
child_directory = os.path.join(root_folder, child_directory)
directories[child_album] = child_directory
return directories
def album_zip_filenames(album, recursive=True): def album_zip_filenames(album, recursive=True):
''' '''
Given an album, produce a dictionary mapping local filepaths to the filenames Given an album, produce a dictionary mapping local filepaths to the filenames
@ -17,25 +38,16 @@ def album_zip_filenames(album, recursive=True):
If a photo appears in multiple albums, only the first is used. If a photo appears in multiple albums, only the first is used.
''' '''
if album.title:
root_folder = '%s - %s' % (album.id, normalize_filepath(album.title))
else:
root_folder = '%s' % album.id
photos = album.photos()
arcnames = {} arcnames = {}
for photo in photos: directories = album_zip_directories(album, recursive=recursive)
photo_name = '%s - %s' % (photo.id, photo.basename) for (album, directory) in directories.items():
arcnames[photo.real_filepath] = os.path.join(root_folder, photo_name) photos = album.photos()
for photo in photos:
if photo.real_filepath in arcnames:
continue
photo_name = '%s - %s' % (photo.id, photo.basename)
arcnames[photo.real_filepath] = os.path.join(directory, photo_name)
if recursive:
for child_album in album.children():
child_arcnames = album_zip_filenames(child_album)
for (filepath, arcname) in child_arcnames.items():
if filepath in arcnames:
continue
arcname = os.path.join(root_folder, arcname)
arcnames[filepath] = arcname
return arcnames return arcnames
def chunk_sequence(sequence, chunk_length, allow_incomplete=True): def chunk_sequence(sequence, chunk_length, allow_incomplete=True):
@ -165,13 +177,8 @@ def normalize_filepath(filepath, allowed=''):
''' '''
Remove some bad characters. Remove some bad characters.
''' '''
badchars = constants.FILENAME_BADCHARS badchars = remove_characters(constants.FILENAME_BADCHARS, allowed)
for character in allowed: filepath = remove_characters(filepath, badchars)
badchars = badchars.replace(allowed, '')
filepath = remove_control_characters(filepath)
badchars = dict.fromkeys(badchars)
filepath = filepath.translate(badchars)
filepath = filepath.replace('/', os.sep) filepath = filepath.replace('/', os.sep)
filepath = filepath.replace('\\', os.sep) filepath = filepath.replace('\\', os.sep)
@ -206,13 +213,18 @@ def read_filebytes(filepath, range_min, range_max, chunk_size=2 ** 20):
yield chunk yield chunk
sent_amount += len(chunk) sent_amount += len(chunk)
def remove_characters(text, characters):
translator = {ord(c): None for c in characters}
text = text.translate(translator)
return text
def remove_control_characters(text): def remove_control_characters(text):
''' '''
Thanks SilentGhost Thanks SilentGhost
http://stackoverflow.com/a/4324823 http://stackoverflow.com/a/4324823
''' '''
kill = dict.fromkeys(range(32)) translator = dict.fromkeys(range(32))
text = text.translate(kill) text = text.translate(translator)
return text return text
def seconds_to_hms(seconds): def seconds_to_hms(seconds):

View file

@ -175,6 +175,9 @@ class Album(ObjectBase, GroupableMixin):
self.name = 'Album %s' % self.id self.name = 'Album %s' % self.id
self.group_getter = self.photodb.get_album self.group_getter = self.photodb.get_album
def __hash__(self):
return hash(self.id)
def __repr__(self): def __repr__(self):
return 'Album:{id}'.format(id=self.id) return 'Album:{id}'.format(id=self.id)
@ -280,7 +283,7 @@ class Photo(ObjectBase):
self.id = row_tuple['id'] self.id = row_tuple['id']
self.real_filepath = row_tuple['filepath'] self.real_filepath = row_tuple['filepath']
self.real_filepath = helpers.normalize_filepath(self.real_filepath) self.real_filepath = helpers.normalize_filepath(self.real_filepath, allowed=':\\/')
self.real_path = pathclass.Path(self.real_filepath) self.real_path = pathclass.Path(self.real_filepath)
self.filepath = row_tuple['override_filename'] or self.real_filepath self.filepath = row_tuple['override_filename'] or self.real_filepath
self.basename = row_tuple['override_filename'] or os.path.basename(self.real_filepath) self.basename = row_tuple['override_filename'] or os.path.basename(self.real_filepath)
@ -572,7 +575,7 @@ class Photo(ObjectBase):
old_path = self.real_path old_path = self.real_path
old_path.correct_case() old_path.correct_case()
new_filename = helpers.normalize_filepath(new_filename) new_filename = helpers.normalize_filepath(new_filename, allowed=':\\/')
if os.path.dirname(new_filename) == '': if os.path.dirname(new_filename) == '':
new_path = old_path.parent.with_child(new_filename) new_path = old_path.parent.with_child(new_filename)
else: else:

View file

@ -47,7 +47,11 @@ p
{% endfor %} {% endfor %}
</ul> </ul>
{% endif %} {% endif %}
<span><a href="/album/{{album.id}}.zip">(download .zip)</a></span> <span>
Download:
<a href="/album/{{album.id}}.zip?recursive=no">These files</a>
{% if sub_albums %} | <a href="/album/{{album.id}}.zip?recursive=yes">Include children</a>{% endif %}
</span>
{% set photos = album.photos() %} {% set photos = album.photos() %}
{% if photos %} {% if photos %}
<h3>Photos</h3> <h3>Photos</h3>