├── .gitignore ├── LICENSE.md ├── README.md ├── gallery.py ├── pcap.sh └── static.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 drduh 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # python-html-gallery 2 | 3 | Python script to generate basic HTML image gallery pages from jpgs. 4 | 5 | # Installation 6 | 7 | Requires Python Imaging Library - `PIL` or `Pillow` 8 | 9 | Install with `pip install PIL` or `easy_install PIL` or build and install it from [source](http://www.pythonware.com/products/pil/). 10 | 11 | Then `git clone https://github.com/drduh/python-html-gallery` 12 | 13 | # Use 14 | 15 | Put jpgs or folders of jpgs into a directory specified in `static.py` 16 | 17 | Then run `python gallery.py` to create thumbnails, gallery pages and an index page. 18 | 19 | `pcap.sh` is an example shell script for generating jpgs from `tcpflow`/`foremost` for gallery content. -------------------------------------------------------------------------------- /gallery.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Generates thumbnails and HTML gallery pages for jpgs in a directory. 4 | 5 | import datetime 6 | import glob 7 | import fnmatch 8 | import os 9 | import random 10 | import re 11 | import shutil 12 | import static 13 | import sys 14 | import time 15 | 16 | try: 17 | from PIL import Image 18 | except ImportError: 19 | try: 20 | import Image 21 | except ImportError: 22 | print 'Requires Python Imaging Library. See README.' 23 | sys.exit(1) 24 | 25 | 26 | def ListFiles(regex, path): 27 | """Returns list of matching files in path.""" 28 | rule = re.compile(fnmatch.translate(regex), re.IGNORECASE) 29 | return [name for name in os.listdir(path) if rule.match(name)] or None 30 | 31 | 32 | def ListDirs(path): 33 | """Returns list of directories in path.""" 34 | return [d for d in os.listdir(path) if os.path.isdir( 35 | os.path.join(path, d))] 36 | 37 | 38 | def Now(time=True): 39 | """Returns formatted current time.""" 40 | if time: 41 | return datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') 42 | else: 43 | return datetime.datetime.now().strftime('%Y%m%d') 44 | 45 | 46 | def RandomThumb(page): 47 | """Returns path to random thumbnail for a given page.""" 48 | return random.choice( 49 | glob.glob(os.path.join(page.split('/')[0], '*_thumb.jpg'))) 50 | 51 | 52 | def OrganizeRoot(): 53 | """Creates directories for images in root directory.""" 54 | try: 55 | os.chdir(static.root) 56 | except OSError: 57 | print 'Could not cd into %s' % static.root 58 | sys.exit(1) 59 | 60 | fs = ListFiles('*.jpg', '.') 61 | if fs: 62 | for jpg in fs: 63 | datehour = Now(time=False) 64 | if not os.path.exists(datehour): 65 | print 'Creating directory: %s' % datehour 66 | os.makedirs(datehour) 67 | if not os.path.exists(os.path.join(datehour, jpg)): 68 | shutil.move(jpg, datehour) 69 | else: 70 | print '%s already exists' % os.path.join(datehour, jpg) 71 | 72 | 73 | def GenerateThumbnails(page, jpgs): 74 | """Generates thumbnails for gallery pages. 75 | 76 | Args: 77 | page: str, name of page for thumbnails. 78 | jpgs: list, jpg files to create thumbnails for. 79 | Returns: 80 | url_imgs: list, image links to write. 81 | """ 82 | c_exist = 0 83 | c_save = 0 84 | c_small = 0 85 | pc = 0 86 | url_imgs = [] 87 | 88 | for jpg in jpgs: 89 | try: 90 | im = Image.open(jpg) 91 | if im.size > static.min_size: 92 | thumb = '%s_%s.%s' % (jpg.split('.')[0], 'thumb', 'jpg') 93 | if not os.path.exists(thumb): 94 | im.thumbnail(static.thumb_size, Image.ANTIALIAS) 95 | im.save(thumb, 'JPEG') 96 | c_save += 1 97 | 98 | if (pc == 100): # progress counter 99 | print '%s: wrote 100 thumbnails, continuing' % page 100 | pc = 0 101 | pc += 1 102 | 103 | else: 104 | c_exist += 1 105 | 106 | url_imgs.append(static.url_img % (jpg, jpg, thumb)) 107 | else: 108 | if '_thumb.jpg' not in jpg: 109 | c_small += 1 110 | except IOError as e: 111 | print 'Problem with %s: %s, moving to %s' % (jpg, e, static.tmp) 112 | try: 113 | shutil.move(jpg, static.tmp) 114 | except shutil.Error: 115 | print 'Could not move %s' % jpg 116 | pass 117 | 118 | print '%s: %d new thumbnails, %d already exist, %d too small' % ( 119 | page, c_save, c_exist, c_small) 120 | return url_imgs 121 | 122 | 123 | def WriteGalleryPage(page): 124 | """Writes a gallery page for jpgs in path. 125 | 126 | Args: 127 | page: str, name of page under root directory. 128 | """ 129 | os.chdir(os.path.join(static.root, page)) 130 | 131 | with open(static.index, 'w') as index_file: 132 | index_file.write(static.header % page) 133 | index_file.write(static.timestamp % Now()) 134 | 135 | try: 136 | jpgs = sorted(ListFiles('*.jpg', '.'))[::-1] 137 | except TypeError: 138 | print '%s: No images found' % page 139 | return 140 | 141 | for e in GenerateThumbnails(page, jpgs): 142 | index_file.write(e) 143 | 144 | index_file.write(static.footer) 145 | 146 | 147 | def WriteGalleryPages(): 148 | """Write gallery pages for directories in root path.""" 149 | for page in sorted(ListDirs(static.root), key=os.path.getmtime): 150 | WriteGalleryPage(page) 151 | 152 | 153 | def WriteIndex(): 154 | """Write index file with gallery links and thumbnails in root path.""" 155 | os.chdir(static.root) 156 | 157 | with open(static.index, 'w') as index_file: 158 | index_file.write(static.header % 'Good day to you, sir/madam!') 159 | index_file.write(static.timestamp % Now()) 160 | 161 | page_count = 0 162 | for page in sorted(glob.glob('*/%s' % static.index)): 163 | page_count += 1 164 | try: 165 | for _ in range(static.n_thumbs): 166 | index_file.write(static.img_src % RandomThumb(page)) 167 | index_file.write(static.url_dir % (page, page.split('/')[0])) 168 | except IndexError: 169 | print '%s: No thumbnails found, removing' % page 170 | os.unlink(page) 171 | 172 | index_file.write(static.footer) 173 | 174 | print 'Wrote %s with %s gallery link(s)' % ( 175 | os.path.join(static.root, static.index), page_count) 176 | 177 | 178 | def main(): 179 | """Main function.""" 180 | OrganizeRoot() 181 | WriteGalleryPages() 182 | WriteIndex() 183 | 184 | 185 | if __name__ == '__main__': 186 | main() 187 | -------------------------------------------------------------------------------- /pcap.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # Cycles tcpflow output through foremost to recover jpg files, 4 | # then executes python script to generate gallery pages and index. 5 | # 6 | # For example, capture HTTP traffic and pass it to tcpflow, 7 | # cd ~/pcap && tcpdump -U tcp port 80 -w - | tcpflow -r - 8 | # 9 | # Then in another shell, run this script, 10 | # ./pcap.sh 11 | # 12 | # You may need to use sudo if writing to a protected directory such as /var/www. 13 | 14 | set -o errtrace 15 | set -o nounset 16 | set -o pipefail 17 | 18 | foremost=$(command -v foremost) # path to foremost 19 | python=$(command -v python) # path to python 20 | gallery=/home/drduh/gallery.py # path to python gallery script 21 | output=/home/drduh/www # path to write jpgs 22 | tcpflow=/home/drduh/pcap # path to where tcpflow is writing 23 | pause=60 # seconds between each run 24 | 25 | 26 | sanity_check() { 27 | # Ensure foremost and required directories exist and are sane. 28 | 29 | if [[ -z ${foremost} && ! -x ${foremost} ]] ; then 30 | echo "foremost is not available" ; exit 1 31 | fi 32 | 33 | if [[ ! -d ${tcpflow} && "${tcpflow}" != "/" ]] ; then 34 | echo "${tcpflow} does not exist" ; exit 1 35 | fi 36 | 37 | if [[ ! -d ${output} ]] ; then 38 | echo "${output} does not exist" ; exit 1 39 | fi 40 | 41 | if [[ ! -f ${gallery} ]] ; then 42 | echo "${gallery} does not exist" ; exit 1 43 | fi 44 | } 45 | 46 | 47 | sanity_check 48 | 49 | 50 | while : ; do 51 | date 52 | 53 | # Clear out any previous foremost output 54 | rm -r "${tcpflow}/output" 2>/dev/null 55 | 56 | if [[ "$(ls -A ${tcpflow})" ]] ; then 57 | cd ${tcpflow} && \ 58 | ${foremost} -i * &>/dev/null 59 | 60 | if [[ -d ${tcpflow}/output/jpg ]] ; then 61 | echo "Found $(ls -l ${tcpflow} | wc -l) jpgs from foremost" 62 | 63 | for filename in $(find ${tcpflow}/output/jpg/ -type f -name "*.jpg") ; do 64 | # add random number to filename as it can repeat in foremost output 65 | cp $filename ${output}/$RANDOM-$(basename $filename) 66 | done 67 | 68 | echo "Updating gallery pages ..." 69 | ${python} ${gallery} 70 | 71 | else 72 | echo "No new jpgs from foremost" 73 | fi 74 | 75 | # Clear out any tcpflow for next run 76 | rm -r ${tcpflow}/* &>/dev/null 77 | else 78 | echo "No new input from tcpflow" 79 | fi 80 | 81 | echo "Sleeping for ${pause} seconds" ; sleep ${pause} 82 | echo "" 83 | done 84 | 85 | -------------------------------------------------------------------------------- /static.py: -------------------------------------------------------------------------------- 1 | """Variables for gallery.py.""" 2 | 3 | root = '/home/drduh/www' # path to jpgs or folders of jpgs and output root 4 | tmp = '/tmp' # temporary folder to move corrupt files to 5 | index = 'index.html' # filename for html files 6 | n_thumbs = 3 # number of thumbnails to display on index page 7 | min_size = 500,500 # minimum dimensions required to create thumbnail 8 | thumb_size = 250,250 # dimensions of thumbnail to create 9 | 10 | header = (""" 11 | 12 |
13 |This page was created on %s
' 55 | url_dir = '\n' 56 | url_img = '\n