Skip to content

Instantly share code, notes, and snippets.

@Moving-Electrons
Last active March 20, 2018 10:41
Show Gist options
  • Save Moving-Electrons/8d471055bb91929974733700aadbf78b to your computer and use it in GitHub Desktop.
Save Moving-Electrons/8d471055bb91929974733700aadbf78b to your computer and use it in GitHub Desktop.
Python 3.5 script for processing files exported from Ulysses in either .md format or .zip format (including images) to be used on Pelican static site generator. The script inserts HTML code, moves images to the appropriate folders in Pelican and expands markdown image links accordingly. Visit www.movingelectrons.net for more info.
import sys
import re
import os
import zipfile
import shutil
# Constant Definition
# -------------------
# Path to be prepended to image links in markdown file, like so: ![](IMAGE_LINK<image_filename>).
IMAGE_LNK = '/images/'
# Pelican Content Folders:
POSTS_FOLDER = 'Insert Path to Pelican markdown content folders.'
IMAGES_FOLDER = 'Insert Path to Pelican image content folders.'
FILES_FOLDER = 'Insert Path to Pelican files content folders. Not used in this version of the script.'
# -------------------
MD_EXT_LIST = ['.md', '.markdown']
IMG_EXT_LIST = ['.jpg', '.jpeg', '.png', '.JPG', '.JPEG', '.PNG']
def image_path(matchedObject):
'''
Adds the folder where Pelican outputs all blog images to the beginning of the in-line
referenced links. re.sub calls the function passing the result of the regex as argument.
:param matchedObject: String with the MD image code.
:return: Folder to be inserted on each MD image call.
'''
return matchedObject.group(1)+IMAGE_LNK+matchedObject.group(2)
def before_after(matchedObject):
'''
Inserts HTML code for "Before and After" effect.
:param matchedObject: Configuration parameters:
before filename|after filename
:return: HTML code.
'''
dataList = matchedObject.group(1).split('|')
code = '''<div id="twentyBox" class="twentytwenty-container">
<img src='/images/{}'>
<img src='/images/{}'>
</div>
<script>
$(window).load(function(){
$("#twentyBox").twentytwenty();
});
</script>'''.format(dataList[0], dataList[1])
return code
def process_markdown(linesList, mdFilePath):
'''
Updates markdown file by including needed HTML, updating image references and putting the
resulting markdown file in the right folder for Pelican to process it.
:param linesList: List of string lines with \n at the end. Usually the result of readlines().
:param MdFilePath: Full path of markdown file including extension.
:return: Nothing.
'''
mdFileName = os.path.basename(mdFilePath)
with open(os.path.join(POSTS_FOLDER,mdFileName), 'w') as newFile:
for line in linesList:
# Extracting filename from slug:
slugFound = re.match(r'^Slug\:.(.*)', line)
if slugFound != None:
fileName = re.sub('-', ' ', slugFound.group(1)) + '.md'
# In each of the following lines, **if** there is a match, the section of _line_ that
# matches the regex is substituted by the result of each of the called functions
# (e.g. quarks_rating, before_after, etc).
# If there is no match, that line doesn't change.
line = re.sub(r'(^\!\[.*\]\()(.*)', image_path, line)
line = re.sub(r'^<beforeafter>(.*)<\/beforeafter>', before_after, line)
newFile.write(line)
try:
os.rename(os.path.join(POSTS_FOLDER,mdFileName), os.path.join(POSTS_FOLDER,fileName))
except UnboundLocalError:
print('Error: "Slug" not detected in Markdown file. File could not be renamed.')
return
def main():
try:
mainFilePath = sys.argv[1]
mainFileExt = os.path.splitext(mainFilePath)[1]
if mainFileExt in MD_EXT_LIST:
# Processing MD File passed as argument.
# ---
with open(mainFilePath, 'r') as mdFile:
textFileList = mdFile.readlines()
process_markdown(textFileList, mainFilePath)
elif mainFileExt == '.zip':
with zipfile.ZipFile(mainFilePath, 'r') as myZip:
for zipItemPath in myZip.namelist():
fileExtension = os.path.splitext(zipItemPath)[1]
# Processing MD files inside the zip file:
# ---
if fileExtension in MD_EXT_LIST:
# Extracting MD file from zip drive (using io.TextIOWrapper was problematic):
with myZip.open(zipItemPath) as zpdMdFile, open(os.path.join(POSTS_FOLDER, os.path.basename(zipItemPath)), 'wb') as destMDFile:
shutil.copyfileobj(zpdMdFile, destMDFile)
# Opening and reading the unzipped MD file:
with open(os.path.join(POSTS_FOLDER, os.path.basename(zipItemPath)), 'r') as origMDFile:
textFileList = origMDFile.readlines()
process_markdown(textFileList, zipItemPath)
# Copying image files inside the zip file to the image content folder in Pelican:
# ---
elif fileExtension in IMG_EXT_LIST:
# Opening zipped item for reading and destination image file for writing:
with myZip.open(zipItemPath) as zpdImageFile, open(os.path.join(IMAGES_FOLDER, os.path.basename(zipItemPath)), 'wb') as destImageFile:
shutil.copyfileobj(zpdImageFile, destImageFile)
# For any other file type:
else:
# Todo > To be implemented: action to be taken if the argument when the zip file has
# file types othern than MD and images (as of today, those are the only files Ulysses
# exports.
pass
else:
# Parameter is not .md or .zip
print('File passed as an argument is not a markdown file (.md extension) or a zip file (.zip extension).')
except IndexError:
print ('No argument passed to the script.')
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment