1
0

initial scripts

This commit is contained in:
2024-11-22 15:47:38 +01:00
commit 49e8af4271
3 changed files with 272 additions and 0 deletions
Executable
+87
View File
@@ -0,0 +1,87 @@
#!/bin/bash
# Watch this folder for incoming files
# Rename each file to a hash of some kind
# Put each file into a folder of the old name
# Check for .known-files which tracks hash history to prevent duplicates
# Will create if -f flag is used, otherwise exits to prevent accidental runs
if [[ ! -f .known-files ]]; then
if [[ "$1" != "-f" ]]; then
echo ".known-files not found. Use -f to override."
exit 1
fi
touch .known-files
fi
command -v file >/dev/null 2>&1 || { echo "file command not found"; exit 1; }
command -v magick >/dev/null 2>&1 || { echo "imagemagick not found"; exit 1; }
command -v dctfilename >/dev/null 2>&1 || { echo "dctfilename not found"; exit 1; }
command -v webpmux >/dev/null 2>&1 || { echo "webpmux not found"; exit 1; }
command -v gifski >/dev/null 2>&1 || { echo "gifski not found"; exit 1; }
while true; do
for f in *.*; do
# Check if we need to skip
[ -e "$f" ] || continue
[ -e "$f.part" ] && continue
[ ${f##*.} == "part" ] && continue
[ ${f##*.} == "sh" ] && continue
# Print some file info, and check file validity
FILEINFO=`file $f`
echo $FILEINFO
if echo "$FILEINFO" | grep -q empty; then
continue
fi
if ! echo "$FILEINFO" | grep -iq "image\|video"; then
continue
echo "skip"
fi
# Handle webp as a special case, and defer to next iteration
if [ ${f##*.} == "webp" ]
then
if [ `magick identify $f | wc -l` -gt 1 ]
then
echo "Animated webp. Converting to gif..."
TMPDIR=$(mktemp -d)
magick "$f" "$TMPDIR/frame-%d.png"
DELAYS=$(webpmux -info "$f" | tail -n+6 | awk '{print $7}')
FPS=$(echo "$DELAYS" | head -n1 | awk '{printf "%.0f", 1000/$1}')
gifski --fps $FPS "$TMPDIR"/frame-*.png -o "${f%.*}.gif"
rm -rf "$TMPDIR"
rm "$f"
continue
else
echo "Picture webp. Converting to jpg..."
magick "$f" "${f%.*}.jpg"
rm "$f"
continue
fi
fi
# Determine phash and destination folder
if command -v dctfilename >/dev/null 2>&1 && ! echo "$FILEINFO" | grep -iq "video"; then
NAME=`dctfilename $f`
else
NAME=`md5sum $f | awk '{print $1}'`
fi
FOLDER=${f%.*}
FOLDER=${FOLDER%\(*}
# Check if the file's hash already exists in .known-files
if grep -F -q $NAME .known-files; then
echo "$NAME is a duplicate file"
mkdir -p duplicates
mv -f $f "duplicates/$NAME.${f##*.}"
else
# For new files, add hash to .known-files and move to destination folder
echo $NAME >> .known-files
mkdir -p $FOLDER
echo "Moving '$f' to '$FOLDER/$NAME.${f##*.}'"
mv -f $f "$FOLDER/$NAME.${f##*.}"
fi
echo '------'
done
sleep 1
done
Executable
+66
View File
@@ -0,0 +1,66 @@
#!/bin/sh
# Script to send push notifications via Pushover API
# Usage: pushover -m|--message <message> [-t|--title <title>] [-a|--attachment <attachment>]
# Requires PUSHOVER_APP_TOKEN and PUSHOVER_USER_TOKEN environment variables
if [ -z "$PUSHOVER_APP_TOKEN" ] || [ -z "$PUSHOVER_USER_TOKEN" ]; then
echo "Error: Missing required environment variables"
echo "Please set PUSHOVER_APP_TOKEN and PUSHOVER_USER_TOKEN"
exit 1
fi
MESSAGE=""
TITLE=$HOSTNAME
ATTACHMENT=""
while [ $# -gt 0 ]; do
case $1 in
-m|--message)
MESSAGE="$2"
shift 2
;;
-t|--title)
TITLE="$2"
shift 2
;;
-a|--attachment)
ATTACHMENT="$2"
shift 2
;;
*)
echo "Invalid option: $1"
exit 1
;;
esac
done
if [ -z "$MESSAGE" ]; then
echo "Error: Message is required"
echo
echo "Usage: pushover -m|--message <message> [-t|--title <title>] [-a|--attachment <attachment>]"
echo "Options:"
echo " -m, --message <message> Message text to send (required)"
echo " -t, --title <title> Notification title (optional, defaults to hostname)"
echo " -a, --attachment <attachment> File to attach (optional, supports images, PDFs etc)"
echo
echo "Example:"
echo " pushover --message \"Backup complete\" --title \"Server Status\" --attachment /path/to/image.png"
exit 1
fi
if [ -n "$ATTACHMENT" ]; then
FILESIZE=$(stat -f%z "$ATTACHMENT" 2>/dev/null || stat -c%s "$ATTACHMENT" 2>/dev/null)
if [ "$FILESIZE" -gt 5242880 ]; then
echo "Error: Attachment size exceeds Pushover's 5MB limit"
exit 1
fi
fi
curl -s \
--form-string "token=${PUSHOVER_APP_TOKEN}" \
--form-string "user=${PUSHOVER_USER_TOKEN}" \
--form-string "message=${MESSAGE}" \
--form-string "title=${TITLE}" \
${ATTACHMENT:+ -F "attachment=@$ATTACHMENT"} \
https://api.pushover.net/1/messages.json
Executable
+119
View File
@@ -0,0 +1,119 @@
#! /usr/bin/python
"""Call ffmpeg with youtube-dl to convert files or youtube videos to mp4 or webp files."""
import subprocess, argparse
def get_input_args(input_path: str) -> list[str]:
"""Generate ffmpeg input arguments for either local files or YouTube URLs."""
f_args: list[str] = []
if "https" in input_path:
urls = subprocess.run(["yt-dlp", "--get-url", input_path], capture_output=True, encoding='utf-8')
for url in urls.stdout.split('\n'):
if len(url) > 10:
f_args += ["-i", url]
else:
f_args += ["-i", input_path]
return f_args
def get_webp_args(quality: str | None) -> list[str]:
"""Generate ffmpeg arguments for WebP output format.
Args:
quality (str): Output quality percentage, defaults to 70 if not specified
"""
args: list[str] = []
args += ["-vcodec", "libwebp"]
args += ["-preset", "default"]
args += ["-loop", "0", "-an", "-vsync", "0"]
args += ["-qscale", quality if quality else "70"]
return args
def get_mp4_args() -> list[str]:
"""Generate ffmpeg arguments for MP4 output format."""
args: list[str] = []
args += ["-c:v", "libx264"]
args += ["-preset", "veryfast"]
args += ["-crf", "26"]
args += ["-c:a", "aac"]
args += ["-b:a", "128k"]
args += ["-pix_fmt", "yuv420p"]
return args
def get_video_filter(crop_arg: str | None) -> str:
"""Generate ffmpeg video filter string for rescaling and optional cropping.
Rescales video height to 720p or original height if smaller, maintaining aspect ratio.
Supports standard, percentage-based, and edge-based cropping formats."""
vfilter = "scale=-2:'min(720,ih)'"
if crop_arg:
if crop_arg.endswith('%'):
# Percentage-based centered cropping (single percentage value)
percent = float(crop_arg.replace('%', ''))
vfilter += f",crop='in_w*{percent/100}:in_h*{percent/100}:(in_w-in_w*{percent/100})/2:(in_h-in_h*{percent/100})/2'"
elif crop_arg.startswith('edge:'):
# Edge-based cropping (edge:left:right:top:bottom or edge:width:height)
parts = crop_arg[5:].split(':')
if len(parts) == 1:
l = r = t = b = int(parts[0])
vfilter += f",crop='in_w-{l+r}:in_h-{t+b}:{l}:{t}'"
elif len(parts) == 2:
w, h = map(int, parts)
vfilter += f",crop='{w}:{h}:(in_w-{w})/2:(in_h-{h})/2'"
else:
l, r, t, b = map(int, parts)
vfilter += f",crop='in_w-{l+r}:in_h-{t+b}:{l}:{t}'"
else:
# Standard cropping (out_w:out_h:x:y or out_w:out_h for centered)
parts = crop_arg.split(':')
if len(parts) == 2:
w, h = parts
vfilter += f",crop={w}:{h}:(in_w-{w})/2:(in_h-{h})/2"
else:
vfilter += f",crop={crop_arg}"
return vfilter
def main():
parser = argparse.ArgumentParser(description='Call ffmpeg for converting small video files to mp4 or webp')
parser.add_argument('input', help='input file or url')
parser.add_argument('output', help='output filename')
parser.add_argument('-s', '--start', help='start time, if not 00:00')
parser.add_argument('-t', '--to', help='end time, if not end of file')
parser.add_argument('-q', '--quality', help='quality of output, as a percentage')
parser.add_argument('-S', '--silent', action='store_true', help='no audio')
parser.add_argument('-c', '--crop', help="""
Crop formats supported:
- Standard: "out_w:out_h:x:y" or "out_w:out_h" for centered
- Percentage: "NN%" for centered crop to NN percent
- Edge: "edge:left:right:top:bottom" or "edge:width:height" or single value for all""")
args = parser.parse_args()
f_args = get_input_args(args.input)
f_args += ["-vf", get_video_filter(args.crop)]
if args.start:
f_args += ["-ss", args.start] # -ss specifies the start timestamp
if args.to:
f_args += ["-to", args.to] # -to specifies the end timestamp
if args.silent:
f_args += ["-an"] # -an disables audio output
f_args += ["-sn"] # -sn removes subtitles
f_args += ["-dn"] # -dn removes data streams
f_args += ["-map_metadata:c", "-1"] # Remove metadata from the output
output_ext = args.output.split('.')[-1]
if output_ext == 'webp':
f_args += get_webp_args(args.quality)
elif output_ext == 'mp4':
f_args += get_mp4_args()
else:
print(f"Error: Output file must have either .mp4 or .webp extension, found: .{output_ext}")
exit(1)
print(f_args)
subprocess.run(["ffmpeg", "-y"] + f_args + [args.output if args.output else "output.mp4"])
if __name__ == "__main__":
main()