diff --git a/file-explorer/file-explorer.py b/file-explorer/file-explorer.py new file mode 100644 index 0000000..0f5cf6b --- /dev/null +++ b/file-explorer/file-explorer.py @@ -0,0 +1,37 @@ +import tkinter as tk +from tkinter import filedialog + +def browse_file(): + file_path = filedialog.askopenfilename() + if file_path: + selected_file.set(file_path) + +def browse_directory(): + directory_path = filedialog.askdirectory() + if directory_path: + selected_directory.set(directory_path) + +# Create the main window +root = tk.Tk() +root.title("Cool File Explorer") + +# Create a label to display the selected file +selected_file = tk.StringVar() +file_label = tk.Label(root, textvariable=selected_file, font=('Helvetica', 12)) +file_label.pack(pady=10) + +# Create a button to browse for a file +file_button = tk.Button(root, text="Browse File", font=('Helvetica', 12), command=browse_file) +file_button.pack() + +# Create a label to display the selected directory +selected_directory = tk.StringVar() +directory_label = tk.Label(root, textvariable=selected_directory, font=('Helvetica', 12)) +directory_label.pack(pady=10) + +# Create a button to browse for a directory +directory_button = tk.Button(root, text="Browse Directory", font=('Helvetica', 12), command=browse_directory) +directory_button.pack() + +# Start the GUI main loop +root.mainloop() diff --git a/file-organizing/file_organizing.py b/file-organizing/file_organizing.py new file mode 100644 index 0000000..da71cc9 --- /dev/null +++ b/file-organizing/file_organizing.py @@ -0,0 +1,49 @@ +# file handling: navigate, rename, move, copy, remove +import os +import shutil +from pathlib import Path + +# change working directory +print(os.getcwd()) + +os.chdir("/Users/patrick/Desktop/video-files") +print(os.getcwd()) + +# rename files +for file in os.listdir(): + # This example changes filenames from + # 'dictionary - python-course-3.mov' + # to --> + # '03-python-course-dictionary.mov' + name, ext = os.path.splitext(file) + + splitted = name.split("-") + splitted = [s.strip() for s in splitted] + new_name = f"{splitted[3].zfill(2)}-{splitted[1]}-{splitted[2]}-{splitted[0]}{ext}" + + os.rename(file, new_name) + + # or + # f = Path(file) + # name, ext = f.stem, f.suffix + # f.rename(new_name) + +# create directory +Path("data").mkdir(exist_ok=True) + +# or +if not os.path.exists("data"): + os.mkdir("data") + +# move file and folder +shutil.move('f', 'd') # works for file and folder + +# copy file and folder +shutil.copy("src", "dest") +shutil.copy2("src", "dest") + +# remove file and folder +os.remove("filename") # error if not found +os.rmdir("folder") # error if not empty, or not found +shutil.rmtree("folder") # works for non empty directories + diff --git a/file-organizing/organize-desktop.py b/file-organizing/organize-desktop.py new file mode 100644 index 0000000..0f0c85e --- /dev/null +++ b/file-organizing/organize-desktop.py @@ -0,0 +1,47 @@ +# organize the desktop +# moves images, videos, screenshots, and audio files +# into corresponding folders +import os +import shutil + + +audio = (".3ga", ".aac", ".ac3", ".aif", ".aiff", + ".alac", ".amr", ".ape", ".au", ".dss", + ".flac", ".flv", ".m4a", ".m4b", ".m4p", + ".mp3", ".mpga", ".ogg", ".oga", ".mogg", + ".opus", ".qcp", ".tta", ".voc", ".wav", + ".wma", ".wv") + +video = (".webm", ".MTS", ".M2TS", ".TS", ".mov", + ".mp4", ".m4p", ".m4v", ".mxf") + +img = (".jpg", ".jpeg", ".jfif", ".pjpeg", ".pjp", ".png", + ".gif", ".webp", ".svg", ".apng", ".avif") + +def is_audio(file): + return os.path.splitext(file)[1] in audio + +def is_video(file): + return os.path.splitext(file)[1] in video + +def is_image(file): + return os.path.splitext(file)[1] in img + +def is_screenshot(file): + name, ext = os.path.splitext(file) + return (ext in img) and "screenshot" in name.lower() + +os.chdir("/Users/patrick/Desktop") + +for file in os.listdir(): + if is_audio(file): + shutil.move(file, "Users/patrick/Documents/audio") + elif is_video(file): + shutil.move(file, "Users/patrick/Documents/video") + elif is_image(file): + if is_screenshot(file): + shutil.move(file, "Users/patrick/Documents/screenshots") + else: + shutil.move(file, "Users/patrick/Documents/images") + else: + shutil.move(file, "Users/patrick/Documents") diff --git a/image-viewer/image-viewer.py b/image-viewer/image-viewer.py new file mode 100644 index 0000000..9419dca --- /dev/null +++ b/image-viewer/image-viewer.py @@ -0,0 +1,26 @@ +import tkinter as tk +from tkinter import filedialog +from PIL import Image, ImageTk + +def open_image(): + file_path = filedialog.askopenfilename(filetypes=[("Image files", "*.png;*.jpg;*.jpeg;*.gif;*.bmp")]) + if file_path: + image = Image.open(file_path) + photo = ImageTk.PhotoImage(image) + label.config(image=photo) + label.image = photo + +# Create the main window +root = tk.Tk() +root.title("Cool Image Viewer") + +# Create a label to display the image +label = tk.Label(root) +label.pack() + +# Create a button to open an image +open_button = tk.Button(root, text="Open Image", font=('Helvetica', 14), command=open_image) +open_button.pack() + +# Start the GUI main loop +root.mainloop() diff --git a/note-take/note-take.py b/note-take/note-take.py new file mode 100644 index 0000000..ec7b7b2 --- /dev/null +++ b/note-take/note-take.py @@ -0,0 +1,38 @@ +import tkinter as tk +from tkinter import scrolledtext +from tkinter import filedialog + +def save_note(): + note = text_widget.get("1.0", "end-1c") # Get text from the text widget + file_path = filedialog.asksaveasfilename(defaultextension=".txt", filetypes=[("Text files", "*.txt")]) + + if file_path: + with open(file_path, 'w') as file: + file.write(note) + +def open_note(): + file_path = filedialog.askopenfilename(filetypes=[("Text files", "*.txt")]) + + if file_path: + with open(file_path, 'r') as file: + note = file.read() + text_widget.delete("1.0", "end") # Clear existing text + text_widget.insert("1.0", note) # Insert the loaded note + +# Create the main window +root = tk.Tk() +root.title("Cool Note Taker") + +# Create a scrolled text widget +text_widget = scrolledtext.ScrolledText(root, font=('Helvetica', 14)) +text_widget.pack(expand=True, fill='both') + +# Create "Save" and "Open" buttons +save_button = tk.Button(root, text="Save Note", font=('Helvetica', 12), command=save_note) +save_button.pack(side="left", padx=10, pady=10) + +open_button = tk.Button(root, text="Open Note", font=('Helvetica', 12), command=open_note) +open_button.pack(side="right", padx=10, pady=10) + +# Start the GUI main loop +root.mainloop() diff --git a/paint/paint.py b/paint/paint.py new file mode 100644 index 0000000..efc7ae3 --- /dev/null +++ b/paint/paint.py @@ -0,0 +1,38 @@ +import tkinter as tk + +class PaintApp: + def __init__(self, root): + self.root = root + self.root.title("Cool Paint App") + + self.canvas = tk.Canvas(root, bg="white") + self.canvas.pack(fill=tk.BOTH, expand=True) + + self.button_clear = tk.Button(root, text="Clear", command=self.clear_canvas) + self.button_clear.pack() + + self.canvas.bind("", self.start_paint) + self.canvas.bind("", self.paint) + + self.old_x = None + self.old_y = None + + def start_paint(self, event): + self.old_x = event.x + self.old_y = event.y + + def paint(self, event): + new_x = event.x + new_y = event.y + if self.old_x and self.old_y: + self.canvas.create_line(self.old_x, self.old_y, new_x, new_y, fill="black", width=2) + self.old_x = new_x + self.old_y = new_y + + def clear_canvas(self): + self.canvas.delete("all") + +if __name__ == "__main__": + root = tk.Tk() + app = PaintApp(root) + root.mainloop() diff --git a/photo-restoration/.env b/photo-restoration/.env new file mode 100644 index 0000000..2d281eb --- /dev/null +++ b/photo-restoration/.env @@ -0,0 +1 @@ +REPLICATE_API_TOKEN=YOUR_TOKEN_HERE \ No newline at end of file diff --git a/photo-restoration/README.md b/photo-restoration/README.md new file mode 100644 index 0000000..9160f6f --- /dev/null +++ b/photo-restoration/README.md @@ -0,0 +1,22 @@ +# Flask app to restore photos + +Simple Flask app to restore old photos with AI. It uses the [GFPGAN](https://replicate.com/tencentarc/gfpgan) model on [Replicate](https://replicate.com/). + +![Screenshot](screenshot.png) +## Setup +```bash +pip install flask replicate python-dotenv +``` + +You need a [Replicate](https://replicate.com/) API Token (You can get started for free). Put the token in the `.env` file. + +Then start the app, upload a photo, and have fun! + +```bash +python main.py +``` + +## Resources + +- Inspired by [restorephotos.io](https://www.restorephotos.io/) +- [https://github.com/TencentARC/GFPGAN](https://github.com/TencentARC/GFPGAN) \ No newline at end of file diff --git a/photo-restoration/main.py b/photo-restoration/main.py new file mode 100644 index 0000000..84d9d41 --- /dev/null +++ b/photo-restoration/main.py @@ -0,0 +1,42 @@ +from flask import Flask, request, redirect, url_for, render_template +from werkzeug.utils import secure_filename +from photo_restorer import predict_image + +UPLOAD_FOLDER = '/static/images/' +ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg'} + +app = Flask(__name__) +app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER +app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024 + + +def allowed_file(filename): + return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS + +@app.route('/') +def home(): + return render_template('index.html') + + +@app.route('/', methods=['POST']) +def upload_image(): + if 'file' not in request.files: + return redirect(request.url) + + file = request.files['file'] + if file.filename == '': + return redirect(request.url) + + if file and allowed_file(file.filename): + filename = secure_filename(file.filename) + full_filepath = "." + url_for('static', filename='images/' + filename) + + file.save(full_filepath) + restored_img_url = predict_image(full_filepath) + return render_template('index.html', filename=filename, restored_img_url=restored_img_url) + else: + return redirect(request.url) + + +if __name__ == "__main__": + app.run(debug=True) \ No newline at end of file diff --git a/photo-restoration/photo_restorer.py b/photo-restoration/photo_restorer.py new file mode 100644 index 0000000..dacdb11 --- /dev/null +++ b/photo-restoration/photo_restorer.py @@ -0,0 +1,27 @@ +from dotenv import load_dotenv +load_dotenv() + +import replicate + +model = replicate.models.get("tencentarc/gfpgan") +version = model.versions.get("9283608cc6b7be6b65a8e44983db012355fde4132009bf99d976b2f0896856a3") + +def predict_image(filename): + # https://replicate.com/tencentarc/gfpgan/versions/9283608cc6b7be6b65a8e44983db012355fde4132009bf99d976b2f0896856a3#input + inputs = { + # Input + 'img': open(filename, "rb"), + + # GFPGAN version. v1.3: better quality. v1.4: more details and better + # identity. + 'version': "v1.4", + + # Rescaling factor + 'scale': 2, + } + print(inputs) + + # https://replicate.com/tencentarc/gfpgan/versions/9283608cc6b7be6b65a8e44983db012355fde4132009bf99d976b2f0896856a3#output-schema + output = version.predict(**inputs) + print(output) + return output \ No newline at end of file diff --git a/photo-restoration/screenshot.png b/photo-restoration/screenshot.png new file mode 100644 index 0000000..2f4acce Binary files /dev/null and b/photo-restoration/screenshot.png differ diff --git a/photo-restoration/static/images/example.jpeg b/photo-restoration/static/images/example.jpeg new file mode 100644 index 0000000..ebae03a Binary files /dev/null and b/photo-restoration/static/images/example.jpeg differ diff --git a/photo-restoration/templates/index.html b/photo-restoration/templates/index.html new file mode 100644 index 0000000..c2cecfe --- /dev/null +++ b/photo-restoration/templates/index.html @@ -0,0 +1,36 @@ + + + + + + + Document + + +

Photo Restoration

+ +{% if filename %} +
+

Original Image:

+ +
+{% endif %} +{% if restored_img_url %} +
+

Restored Image:

+ + +
+{% endif %} + +
+

+ +

+

+ +

+
+ + + \ No newline at end of file diff --git a/stopwatch/stopwatch.py b/stopwatch/stopwatch.py new file mode 100644 index 0000000..8586859 --- /dev/null +++ b/stopwatch/stopwatch.py @@ -0,0 +1,53 @@ +import tkinter as tk +import time + +def start(): + global running + running = True + start_button['state'] = 'disabled' + stop_button['state'] = 'active' + update() + +def stop(): + global running + running = False + start_button['state'] = 'active' + stop_button['state'] = 'disabled' + +def reset(): + global running, elapsed_time + running = False + elapsed_time = 0 + time_label.config(text="00:00:00") + start_button['state'] = 'active' + stop_button['state'] = 'disabled' + +def update(): + if running: + global elapsed_time + elapsed_time += 1 + hours, remainder = divmod(elapsed_time, 3600) + minutes, seconds = divmod(remainder, 60) + time_str = f"{hours:02d}:{minutes:02d}:{seconds:02d}" + time_label.config(text=time_str) + time_label.after(1000, update) + +running = False +elapsed_time = 0 + +root = tk.Tk() +root.title("Cool Stopwatch") + +time_label = tk.Label(root, text="00:00:00", font=('Helvetica', 48)) +time_label.pack(padx=20, pady=20) + +start_button = tk.Button(root, text="Start", font=('Helvetica', 16), command=start) +start_button.pack(side="left", padx=10) +stop_button = tk.Button(root, text="Stop", font=('Helvetica', 16), command=stop) +stop_button.pack(side="left", padx=10) +reset_button = tk.Button(root, text="Reset", font=('Helvetica', 16), command=reset) +reset_button.pack(side="left", padx=10) + +stop_button['state'] = 'disabled' + +root.mainloop() diff --git a/text-editor/text-editor.py b/text-editor/text-editor.py new file mode 100644 index 0000000..3194bb6 --- /dev/null +++ b/text-editor/text-editor.py @@ -0,0 +1,40 @@ +import tkinter as tk +from tkinter import filedialog, scrolledtext + +def open_file(): + file_path = filedialog.askopenfilename(filetypes=[("Text files", "*.txt")]) + if file_path: + with open(file_path, 'r') as file: + text.delete(1.0, tk.END) + text.insert(tk.END, file.read()) + root.title(f"Cool Text Editor - {file_path}") + +def save_file(): + file_path = filedialog.asksaveasfilename(defaultextension=".txt", filetypes=[("Text files", "*.txt")]) + if file_path: + with open(file_path, 'w') as file: + file.write(text.get(1.0, tk.END)) + root.title(f"Cool Text Editor - {file_path}") + +# Create the main window +root = tk.Tk() +root.title("Cool Text Editor") + +# Create a scrolled text widget +text = scrolledtext.ScrolledText(root, font=('Helvetica', 14)) +text.pack(expand=True, fill='both') + +# Create the menu bar +menu_bar = tk.Menu(root) +root.config(menu=menu_bar) + +# File menu +file_menu = tk.Menu(menu_bar) +menu_bar.add_cascade(label="File", menu=file_menu) +file_menu.add_command(label="Open", command=open_file) +file_menu.add_command(label="Save", command=save_file) +file_menu.add_separator() +file_menu.add_command(label="Exit", command=root.quit) + +# Start the GUI main loop +root.mainloop() diff --git a/to-do/to-do.py b/to-do/to-do.py new file mode 100644 index 0000000..291eb75 --- /dev/null +++ b/to-do/to-do.py @@ -0,0 +1,35 @@ +import tkinter as tk + +def add_task(): + task = entry.get() + if task: + listbox.insert(tk.END, task) + entry.delete(0, tk.END) + +def remove_task(): + selected_task = listbox.curselection() + if selected_task: + listbox.delete(selected_task) + +# Create the main window +root = tk.Tk() +root.title("Cool To-Do List") + +# Entry widget for adding tasks +entry = tk.Entry(root, font=('Helvetica', 18)) +entry.grid(row=0, column=0, columnspan=2) + +# Button to add tasks +add_button = tk.Button(root, text="Add", font=('Helvetica', 14), command=add_task) +add_button.grid(row=0, column=2) + +# Button to remove tasks +remove_button = tk.Button(root, text="Remove", font=('Helvetica', 14), command=remove_task) +remove_button.grid(row=0, column=3) + +# Listbox to display tasks +listbox = tk.Listbox(root, font=('Helvetica', 18), selectmode=tk.SINGLE, selectbackground="#a5a5a5") +listbox.grid(row=1, column=0, columnspan=4) + +# Start the GUI main loop +root.mainloop() diff --git a/webapps/flask/app.py b/webapps/flask/app.py index 921c310..0bbf5ff 100755 --- a/webapps/flask/app.py +++ b/webapps/flask/app.py @@ -22,7 +22,7 @@ class Todo(db.Model): def home(): # todo_list = Todo.query.all() todo_list = db.session.query(Todo).all() - return "Hello, World!" + # return "Hello, World!" return render_template("base.html", todo_list=todo_list) @@ -51,4 +51,4 @@ def delete(todo_id): todo = db.session.query(Todo).filter(Todo.id == todo_id).first() db.session.delete(todo) db.session.commit() - return redirect(url_for("home")) \ No newline at end of file + return redirect(url_for("home"))