Skip to content

Instantly share code, notes, and snippets.

@pjdietz
Last active January 15, 2024 15:24
Show Gist options
  • Save pjdietz/11400017 to your computer and use it in GitHub Desktop.
Save pjdietz/11400017 to your computer and use it in GitHub Desktop.
Rename a file to a URL-friendly version of the filename
#!/usr/bin/env python
import os
import os.path
import re
import shutil
import sys
# Help message
HELP = """Slugify
Rename a file to contain only lowercase letters, digits, -, _, and .
Usage: slugify [options] file
Options
-c, --copy Make a copy of source instead of renaming it.
-f, --force Overwrite existing file when renaming.
-h, --help Display this help.
-p, --preview Display the new filename for the slugified file.
-s, --string Output a slugifiged string instead of operating on a file.
"""
# Reg Ex pattern to match any non-slug-friendly character
PATTERN = re.compile("""[^0-9a-z\-\._]{1}""")
def slugify(str):
"""
Return a version of the string containing only lowercase letters, digits,
hyphens, underscores, and period.
"""
str = str.strip().lower()
str = PATTERN.sub("-", str)
return str
def help():
"""Output the help message and exit."""
print(HELP)
exit()
if __name__ == "__main__":
# Help. Display help if no arguments or if "-h" or "--help" is present.
if len(sys.argv) == 0 or "-h" in sys.argv or "--help" in sys.argv:
help()
exit()
# Read the last argument as the source.
source = sys.argv[-1]
# Defaults
copy = False
force = False
preview = False
string = False
# Read other arguments.
for arg in sys.argv[1:-1]:
if arg in ["-c", "--copy"]:
copy = True
elif arg in ["-f", "--force"]:
force = True
elif arg in ["-p", "--preview"]:
preview = True
elif arg in ["-s", "--string"]:
string = True
else:
print("Unrecognized option \"%s\"" % arg)
exit(1)
# String mode. Output the slugified version of the source only.
if string:
print(slugify(source))
exit()
# Check if the source file exists.
if os.path.exists(source):
# Determine the slugified name for the file by converting only the
# filename portion of the path.
source_directory, source_basename = os.path.split(source)
target_basename = slugify(source_basename)
target = os.path.join(source_directory, target_basename)
# Check if already slug friendly.
if source == target:
print("File \"%s\" is already slug-friendly." % source)
exit()
# Preview. Only show what the script would rename to and if that name
# is already taken.
if preview:
print(target)
if os.path.exists(target):
print("WARNING. File with the slugified name already exists.")
print("Use -f or --force option to overwrite.")
exit()
# Copy. Copy the file and exit.
if copy:
shutil.copyfile(source, target)
exit()
# Check if this new name is in use.
if os.path.exists(target):
if force:
os.remove(target)
else:
print("File \"%s\" already exists." %target)
exit(1)
# Rename the file.
os.rename(source, target)
# Source does not match a file. Exit with error.
else:
print("File \"%s\" not found." %source)
exit(1)
@pjdietz
Copy link
Author

pjdietz commented Apr 30, 2014

Mac OSX Automator Services

You can use this script from the Finder context menus by creating Automator services. (Replace the path used in the code sections below with the path to the executable slugify script on your system).

File renaming service

This service allows you to select a file or files and rename them from the context menu.

Settings

Service receives selected [files or folders] in [Finder]
Run Shell Script
Shell: /bin/bash
Pass input: [as arguments]

Code

for f in "$@"
do
    /Users/pjdietz/bin/slugify "$f"
done

Text replacement service

This service allows you to replace selected text with a slugified version of the text.

Settings

Service receives selected [text] in [any application]
Input is: [entire selection] [X] Output replaces selected text
Run Shell Script
Shell: /bin/bash
Pass input: [as arguments]

Code

/Users/pjdietz/bin/slugify -s "$*"

@JonasPoli
Copy link

hello. I thought your script was great, but I can't implement it on my Operating System. I'm using sonoma.
Please, could you create a more detailed tutorial on how to use your script?
I've already used Automator to create a tinypng script, which reduces the size of images, but I can't understand how to do it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment