forked from JustAnyone/random-file-picker
Add initial version
This commit is contained in:
Executable
+221
@@ -0,0 +1,221 @@
|
||||
"""
|
||||
A script to randomly select files from a directory, open them, and allow the user to upload them to a Discord webhook, delete them, or skip to the next file.
|
||||
|
||||
You can specify a file size limit, whether to descend into subdirectories, and provide blacklist/whitelist patterns for file selection.
|
||||
|
||||
Here's an example usage:
|
||||
./rand.py -fl 5 -d /path/to/directory --descend --blacklist "*.png" "*.mp4"
|
||||
"""
|
||||
|
||||
import io
|
||||
import os
|
||||
import random
|
||||
import requests
|
||||
import subprocess
|
||||
import argparse
|
||||
import sys
|
||||
import tty
|
||||
import termios
|
||||
import fnmatch
|
||||
|
||||
MEME_FOLDER = os.environ.get("RANDOM_FILE_PICKER_MEME_FOLDER", None)
|
||||
WEBHOOK_URL = os.environ.get("RANDOM_FILE_PICKER_WEBHOOK_URL", None)
|
||||
|
||||
ALLOWED_EXTENSIONS = [
|
||||
".jpg",
|
||||
".jpeg",
|
||||
".webp",
|
||||
".png",
|
||||
".gif",
|
||||
".mp4",
|
||||
".mov",
|
||||
".webm",
|
||||
]
|
||||
|
||||
IMG_EXTENSIONS = [
|
||||
".jpg",
|
||||
".jpeg",
|
||||
".webp",
|
||||
".png",
|
||||
".gif",
|
||||
]
|
||||
|
||||
|
||||
def send_file(file_path: str):
|
||||
if WEBHOOK_URL is None:
|
||||
print("Error: RANDOM_FILE_PICKER_WEBHOOK_URL environment variable is not set.")
|
||||
return
|
||||
|
||||
filename = os.path.basename(file_path)
|
||||
with open(file_path, "rb") as image_file:
|
||||
image_data = image_file.read()
|
||||
files = {'file': (filename, io.BytesIO(image_data))}
|
||||
response = requests.post(WEBHOOK_URL, files=files, data={})
|
||||
response.raise_for_status() # Raise HTTPError for bad responses
|
||||
print(f"\nSuccessfully uploaded {filename}")
|
||||
|
||||
def getch() -> str:
|
||||
fd = sys.stdin.fileno()
|
||||
old_settings = termios.tcgetattr(fd)
|
||||
try:
|
||||
tty.setcbreak(sys.stdin.fileno())
|
||||
ch = sys.stdin.read(1)
|
||||
finally:
|
||||
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
|
||||
return ch
|
||||
|
||||
|
||||
def open_with_gwenview(maybe_process: subprocess.Popen[bytes] | None, file_path: str) -> subprocess.Popen[bytes]:
|
||||
if maybe_process is not None:
|
||||
maybe_process.terminate()
|
||||
maybe_process.wait()
|
||||
|
||||
process = subprocess.Popen(["gwenview", file_path])
|
||||
return process
|
||||
|
||||
def open_in_folder(file_path: str):
|
||||
subprocess.Popen(["dolphin", "--select", file_path])
|
||||
#subprocess.run(["dolphin", "--select", file_path])
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Random File Sender")
|
||||
parser.add_argument('-fl', '--file-limit', type=int, default=10, help='Maximum file size in MB')
|
||||
parser.add_argument('-d', '--directory', type=str, default='.', help='Directory to search for files')
|
||||
parser.add_argument('--descend', action='store_true', help='Whether to descend into subdirectories')
|
||||
#parser.add_argument('--direct', action='store_true', help='Whether to open files directly without xdg-open')
|
||||
|
||||
parser._positionals.title = 'Positional arguments'
|
||||
parser._optionals.title = 'Optional arguments'
|
||||
|
||||
# Globs for blacklisting and whitelisting, --blacklist "*.png" "*.mp4"
|
||||
parser.add_argument('--blacklist', nargs='*', help='List of glob patterns to blacklist files')
|
||||
parser.add_argument('--whitelist', nargs='*', help='List of glob patterns to whitelist files')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
file_limit: int = args.file_limit
|
||||
#open_directly: bool = args.direct
|
||||
directory: str = args.directory
|
||||
descend: bool = args.descend
|
||||
blacklist_patterns: list[str] = args.blacklist if args.blacklist else []
|
||||
whitelist_patterns: list[str] = args.whitelist if args.whitelist else []
|
||||
print(f"File size limit set to {file_limit} MB")
|
||||
#print(f"Open files directly: {open_directly}")
|
||||
if not os.path.exists(directory) or not os.path.isdir(directory):
|
||||
print(f"Directory '{directory}' does not exist or is not a directory.")
|
||||
return
|
||||
|
||||
search_path = os.path.abspath(directory)
|
||||
|
||||
# Collect files from the current directory
|
||||
usable_files: list[str] = []
|
||||
for directory, _, files in os.walk(search_path):
|
||||
if directory != search_path and not descend:
|
||||
continue
|
||||
|
||||
for f in files:
|
||||
file_path = os.path.join(directory, f)
|
||||
|
||||
# Check against whitelist patterns
|
||||
if whitelist_patterns and not any(fnmatch.fnmatch(file_path, pattern) for pattern in whitelist_patterns):
|
||||
continue
|
||||
|
||||
# Check against blacklist patterns
|
||||
if any(fnmatch.fnmatch(file_path, pattern) for pattern in blacklist_patterns):
|
||||
continue
|
||||
|
||||
if not any(f.lower().endswith(ext) for ext in ALLOWED_EXTENSIONS):
|
||||
continue
|
||||
|
||||
stat_res = os.stat(file_path)
|
||||
if stat_res.st_size < 1024 * 1024 * file_limit:
|
||||
usable_files.append(file_path)
|
||||
|
||||
if not usable_files:
|
||||
print("No usable files found.")
|
||||
return
|
||||
|
||||
pickFile = True
|
||||
gwenview_process = None
|
||||
while pickFile:
|
||||
file = random.choice(usable_files)
|
||||
|
||||
print(f"Random file: {file}")
|
||||
|
||||
if file.lower().endswith(tuple(IMG_EXTENSIONS)):
|
||||
gwenview_process = open_with_gwenview(gwenview_process, file)
|
||||
else:
|
||||
subprocess.run(["xdg-open", file])
|
||||
|
||||
|
||||
selectionTime = True
|
||||
while selectionTime:
|
||||
print("Options: [u]pload, [n]ext, [d]elete, [f]older, [q]uit")
|
||||
choice = getch().lower()
|
||||
|
||||
|
||||
# Skip escape sequences (arrow keys)
|
||||
if choice.encode("utf-8") == b'\x1b':
|
||||
_ = getch() # Skip the next two characters
|
||||
_ = getch()
|
||||
continue
|
||||
|
||||
#print(choice.encode("utf-8")) # For debugging purposes
|
||||
|
||||
if choice == "u":
|
||||
print("\nUploading...")
|
||||
send_file(file)
|
||||
print("Upload complete.")
|
||||
#selectionTime = False
|
||||
elif choice == "d":
|
||||
print("\nDeleting...")
|
||||
os.remove(file)
|
||||
usable_files.remove(file)
|
||||
selectionTime = False
|
||||
elif choice == "n":
|
||||
print("\nNext file...")
|
||||
selectionTime = False
|
||||
usable_files.remove(file)
|
||||
elif choice == "f":
|
||||
open_in_folder(file)
|
||||
elif choice == "q":
|
||||
print("\nQuitting...")
|
||||
pickFile = False
|
||||
break
|
||||
elif choice == "m":
|
||||
print("\nMoving to meme folder...")
|
||||
|
||||
if MEME_FOLDER is None:
|
||||
print("Error: RANDOM_FILE_PICKER_MEME_FOLDER environment variable is not set.")
|
||||
continue
|
||||
|
||||
# First, make sure we're not in the meme folder already
|
||||
if os.path.abspath(os.path.dirname(file)) == os.path.abspath(MEME_FOLDER):
|
||||
print("File is already in the meme folder.")
|
||||
continue
|
||||
|
||||
# Also, ensure the meme folder exists
|
||||
if not os.path.exists(MEME_FOLDER):
|
||||
print(f"Meme folder '{MEME_FOLDER}' does not exist.")
|
||||
continue
|
||||
|
||||
base_name = os.path.basename(file)
|
||||
new_path = os.path.join(MEME_FOLDER, base_name)
|
||||
|
||||
# Avoid overwriting existing files
|
||||
if os.path.exists(new_path):
|
||||
name, ext = os.path.splitext(base_name)
|
||||
counter = 1
|
||||
while os.path.exists(new_path):
|
||||
new_path = os.path.join(MEME_FOLDER, f"{name}_{counter}{ext}")
|
||||
counter += 1
|
||||
|
||||
os.rename(file, new_path)
|
||||
usable_files.remove(file)
|
||||
selectionTime = False
|
||||
else:
|
||||
print(f"\n'{choice}' is an invalid option. Please choose again.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user