"""
This script adds a new tiddler with an optional embedded image either to
an existing TiddlyWiki or to a new TiddlyWiki.
From the command line
---------------------
Example usage from the commandline (should all be on one line):
python addtiddler.py -i test.html --description "Test image. Code to
generate image was: {{{plot(x,y)}}}" --image figures/plot1.png --tags
"images timeseries depth temperature"
Or:
python addtiddler.py -i test.html -o new.html --description "Test
image" --image figures/plot1.png --tags "images
timeseries depth temperature" --resize
Use:
python addtiddler.py -h
to view additional help.
From another script
-------------------
>>> from addtiddler import addtiddler
>>> addtiddler('mywiki.html', image='figures/plot1.png',
tags='images timeseries depth temperature',
resize=True)
COPYRIGHT INFORMATION
Copyright (c) 2008 Ryan Dale
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
"""
import datetime
import sys
import os
import re
import shutil
from optparse import OptionParser
try:
from PIL import Image
PIL_imported = True
except ImportError:
print "Can't find installed Python Imaging Library (http://www.pythonware.com/products/pil/index.htm). Auto-resizing is now disabled."
PIL_imported = False
class TiddlyWikiChunk(object):
"""
A simple class that knows how to pull the title and tags out of a
block of code, and knows whether or not it's a
tiddler or just plain source code (check to see if the isTiddler
attribute is True).
The itertiddler function creates an iterator of these objects.
"""
title_regexp = re.compile('title="(.*?)"')
tags_regexp = re.compile('tags="(.*?)"')
def __init__(self, sourceCode):
"""Initialization for TiddlyWikiChunk"""
self.sourceCode = sourceCode
self.contents = None
self.tags = None
title_match = TiddlyWikiChunk.title_regexp.search(self.sourceCode)
if title_match:
self.title = title_match.group(1)
else:
self.title = None
tags_match = TiddlyWikiChunk.tags_regexp.search(self.sourceCode)
if tags_match:
self.tags = tags_match.group(1)
else:
self.tags = None
if self.title is not None:
self.isTiddler = True
else:
self.isTiddler = False
def __repr__(self):
"String representation of TiddlyWikiChunk."
if self.title is not None:
return 'TWChunk object: "%s"' % self.title
else:
return 'TWChunk object: Source = "%s..."' % self.sourceCode[:6]
def itertiddler(s):
"""
Given an open file, this function returns a generator of
TiddlyWikiChunk objects.
Thanks to Andrew Dalke,
http://www.dalkescientific.com/writings/NBN/iterators.html
for iterator ideas.
"""
saved = None
while 1:
# Enter this loop the first time, but not again until
# the inner loop sees another '
' in line:
saved = None
break
t = TiddlyWikiChunk(''.join(divs))
yield t
def addtiddler(infile, outfile=None, image=None, description='', tags='', author='author', title=None, resize=False, replace=False, UTC_offset=0):
"""
Function to add a new tiddler to an existing TiddlyWiki file.
:Parameters:
infile
Input file.
outfile
Output file. If unspecified, the input file will be overwritten.
image : string
The path name of the image file to embed. This path should be
relative to the output file (or to the input file, if no
output was specified).
description : string
The text that will be added to the tiddler
tags : string
Space-delimited string of tags
author : string
Author's name. Default is 'author'.
title : string
The title for the tiddler
resize : boolean
Resize the image to a max of 500px
replace : boolean
Automatically replace a tiddler of the same name with this tiddler.
UTC_offset : integer
Number of hours offset from UTC time, e.g., -5 for EST
"""
if outfile is None:
outfile = infile+'.tmp'
tempfile = True
if title is None:
if image is not None:
title = image
elif image is None:
title = 'New Tiddler'
# Change to output file dir so that image path will be relative to output file.
outfilepath = os.path.realpath(outfile)
outfiledir, outfilename = os.path.split(outfilepath)
original_cwd = os.getcwd() # save current working directory in order to get back here when done.
os.chdir(outfiledir) # change to the output file's directory so that the image path will be relative to the output.
# Now that we're here, strip the directory info off of outfile.
infile = os.path.basename(infile)
outfile = os.path.basename(outfile)
# Resize image if requested.
if resize and PIL_imported and image is not None:
filename, ext = os.path.splitext(image)
new_filename = filename + '.thumb.png'
im = Image.open(image)
sz = (500, 500)
im.thumbnail(sz, Image.ANTIALIAS)
im.save(new_filename, "PNG")
image = new_filename
# Create a new tiddler . . .
d = {} # d is a dictionary that will be used to fill in the tiddler content.
d['tags'] = tags
modification_time = datetime.datetime.now() + datetime.timedelta(0,UTC_offset)
d['modified'] = modification_time.strftime('%Y%m%d%H%M')
d['created'] = d['modified']
d['title'] = title
d['author'] = author
d['changecount'] = 1
if image is not None:
d['text'] = "[img[%s]]\n%s" % (image, description)
else:
d['text'] = description
# Tiddler creation:
# Create the text string for the complete tiddler (HTML tags and everything) by filling in dictionary d.
tiddler_source = """
""" % d
# Read everything in from infile as a list of TiddlyWikiChunks.
fin = open(infile)
twchunks = itertiddler(fin)
# Open output file for writing (if no output file was specified, this is the same as the input
# file that was just read in)
fout = open(outfile, 'w')
# As long as the current chunk does not represent a tiddler, write the contents of it to fout.
# When you reach one that IS a tiddler, then pause . . .
for chunk in twchunks:
if chunk.title == title:
if replace:
continue
elif not replace:
answer = raw_input('Another tiddler with the name "%s" was found. Delete it? (y/n) ' % chunk.title)
if answer == 'y':
continue
fout.write(chunk.sourceCode)
if '
' in chunk.sourceCode:
break # note that break is after it's already been written.
fout.write(tiddler_source) # . . . write the new tiddler to fout . . .
# . . . then continue copying the remaining chunks to the output file.
# Since twchunks is an iterator, it picks up where it left off last.
for chunk in twchunks:
# If the title of the tiddler just added is the same as an existing one,
# prompt the user for deletion.
if chunk.title == title:
if replace:
continue
elif not replace:
answer = raw_input('Another tiddler with the name "%s" was found. Delete it? (y/n) ' % chunk.title)
if answer == 'y':
continue
# Otherwise, write it out to file.
fout.write(chunk.sourceCode)
# Done.
fout.close()
fin.close()
# Overwrite input file with output file, if no output was specified. (tempfile was
# set at the beginning of this function)
if tempfile:
shutil.move(outfile, infile)
# Return from whence you came
os.chdir(original_cwd)
if __name__ == "__main__":
# Parse commandline arguments if this module is run as a script.
parser = OptionParser()
parser.add_option('-i',
action='store',
dest='infile',
help='Relative path to input TiddlyWiki file.')
parser.add_option('-o',
action='store',
dest='outfile',
help='Relative path to output TiddlyWiki file. If not specified, tiddler will be added to INPUT.')
parser.add_option('--title',
action='store',
dest='title',
help='Optional title for the new Tiddler. Default is image path (if provided), otherwise "New Tiddler".')
parser.add_option ('--description',
action='store',
default='',
dest='description',
help='Text to be added below the image in the tiddler. Can be any valid TiddlyWiki syntax.')
parser.add_option('--image',
action='store',
dest='image',
help='Path to image, relative to OUTPUT.')
parser.add_option('--tags',
action='store',
dest='tags',
default='',
help='Quoted space-delimited tags for this tiddler. Ex: --tags "images temperature depth"')
parser.add_option('--resize',
action='store_true',
dest='resize',
default=False,
help='Option to auto-resize the image to 400px. By default this is disabled. Will create a new image in the folder with "thumb" appended to filename, and will use that thumbnail as the image for the tiddler.')
(options, args) = parser.parse_args()
addtiddler(infile=options.infile,
outfile=options.outfile,
image=options.image,
description=options.description,
tags=options.tags,
title=options.title,
resize=options.resize)