Skip to content

Instantly share code, notes, and snippets.

@lyjia
Last active November 24, 2019 03:43
Show Gist options
  • Save lyjia/ca341d38388b6b1802eafcab0890fe31 to your computer and use it in GitHub Desktop.
Save lyjia/ca341d38388b6b1802eafcab0890fe31 to your computer and use it in GitHub Desktop.
A script for fixing broken plugin preview images for FL Studio.
#!/usr/bin/env python3
###############################################################################
# fixflpreviews.py
###############################################################################
# https://gist.github.com/lyjia/ca341d38388b6b1802eafcab0890fe31
#
# How to use:
# 1. download this file and save it in your FLStudio "Plugin Database" folder
# 2. Make sure you have python 3 installed
# 3. Run this script by double-clicking on it or navigating to your "Plugin
# Database" folder and running it with `python3 fixflpreviews.py`
#
# Note there are additional options available. Run this script with -h to find
# out more.
#
# This file made available under MIT License:
#
# Copyright 2019 Lyjia.
#
# 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 sys, os, glob, logging, argparse, re
from pathlib import Path
if sys.version_info[0] < 3:
raise Exception("Must be using Python 3")
def dir_path(string):
if os.path.isdir(string):
return string
else:
print(string+" is not a valid directory.")
sys.exit(-2)
# Constants
title=os.path.basename(__file__)
version="1.1"
url="https://gist.github.com/lyjia/ca341d38388b6b1802eafcab0890fe31"
desc = title+": A script for fixing broken plugin preview images for FL Studio. Version "+version+". More info/latest: "+url
# Handle arguments
parser = argparse.ArgumentParser(description=desc)
parser.add_argument("-d", "--debug", help="Show debug logging", action="store_true")
parser.add_argument("-s", "--silent", help="Show error logging only", action="store_true")
parser.add_argument("-v", "--version", help="Show script version", action="store_true")
parser.add_argument("-f", "--fake", help="Fake mode: don't actually do anything, just print results", action="store_true")
parser.add_argument("-n", "--nopause", help="Don't pause for user input when finished", action="store_true")
parser.add_argument("-p", "--path", help="Path to FLStudio's Plugin Database folder", type=dir_path)
args = parser.parse_args()
# Set up logger (yeesh...)
if args.debug:
loglevel = logging.DEBUG
elif args.silent:
loglevel = loggin.ERROR
else:
loglevel = logging.INFO
log = logging.getLogger()
log.setLevel(loglevel)
handler = logging.StreamHandler(sys.stdout)
handler.setLevel(loglevel)
handler.setFormatter( logging.Formatter("%(levelname)s %(message)s") )
log.addHandler( handler )
# Set up folder paths
mypath = os.path.abspath( os.path.dirname(sys.argv[0]) )
if args.path:
mypath = args.path
folders = ["Effects", "Generators"]
log.debug("Subfolders to scan: "+str(folders))
# Some functions
def maybeFixFile(file):
basename = os.path.splitext(file)[0]
fnfo = basename + ".nfo"
fpng = basename + ".png"
basepng = os.path.basename(fpng)
if os.path.exists(fnfo) and os.path.exists(fpng):
buf = None
changed = False
with open(fnfo, "r") as nfofile:
try:
buf = nfofile.readlines()
# fix empty nfo file
if os.stat(fnfo).st_size == 0:
log.info(" ...found empty nfo for "+file+".")
buf.append("Bitmap="+fpng)
changed = True
else:
for index,line in enumerate(buf):
# check if nfo file's Bitmap line doesnt match fpng and update if it does
if (line[0:6] == "Bitmap") and (line != "Bitmap="+basepng):
log.info("Found broken preview for "+file+".")
buf[index] = "Bitmap="+basepng
changed = True
except Exception as err:
log.error(" ...skipping "+file+" because "+err.__class__.__name__+": "+str(err))
if changed and not args.fake:
try:
with open(fnfo, "w") as nfofile:
nfofile.write( "\n".join(buf) )
log.info(" ...fixing!")
except Exception as err:
log.error(" ...couldn't update "+file+" because "+err.__class__.__name__+": "+str(err))
elif changed and args.fake:
log.info(" ...would have fixed "+file+" but didn't because fake mode is active!")
else:
log.error("Skipped because one of its sidecar files are missing: "+file)
# Script starts here
log.info(" ***** "+title+" version "+version+" by Lyjia *****")
log.info(" ***** For more info/updates: "+url+" *****")
# Fix all the shit
if args.fake:
log.info("Fake mode activated!")
log.debug("Starting from "+mypath)
for folder in folders:
fullpath = mypath + '/' + folder + '/'
if not os.path.exists(fullpath):
log.fatal("The Plugin Database folder I am looking for does not exist: "+fullpath)
log.fatal("Make sure you run me from within your Plugin Database folder or specify its path with the -p option!")
log.fatal("See `"+title+" -h` for more info.")
sys.exit(-1)
files = glob.glob(fullpath + r'/**/*.fst', recursive=True)
log.info("===> Globbed "+ str(len(files)) +" .fst files from "+str(fullpath)+"...")
for file in files:
maybeFixFile(file)
if not args.nopause:
log.info("All done! Press any key to terminate...")
input()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment