Instant Note-Taking: Needs a Lightweight Sticky Note App for Obsidian

image

HiI created a python script just for my needs, is perfect if you just want to write anything directly to your vault without waiting for obsidian to open. I had the same issue. And I couldn’t find any solution for something that just accepts text and write it in a markdown file in a specific folder fast. The script is fired on startup and waits silently for a hotkey, it raises on top of all the windows to write a note, control enter and the window closes and the note is saved. It will take the first line as the title, excepts if there are too much words on the first line, in that case it will take only the first four words(customizable) and print all in the note.

# By Arturo Rebolledo Rosenstiehl from Barranquilla, Colombia
## Python packages to install
import keyboard
import customtkinter as ctk
from plyer import notification

from datetime import datetime
import os

# Configuration
SAVE_PATH = r"C:\Users\USUARIO\OneDrive\Knowledge Garden\00 - INBOX\MicroNotas"
## Hotkey to open the window
HOTKEY = "alt+."
## Save hotkey control enter
SAVE_HOTKEY = "ctrl+enter"
words_title_limit = 4
obsidian_icon_path = r"C:\Users\USUARIO\OneDrive\Descargas\obsidian-icon-_4_.ico"
app_name = "Obsidian Nota Rápida"

# Ensure the save directory exists
os.makedirs(SAVE_PATH, exist_ok=True)

def open_in_obsidian(filepath):
    """Open the note in Obsidian."""
    os.system(f'start "" "obsidian://open?path={filepath}"')

def delete_word(event):
    """Delete the word before the cursor, including spaces."""
    widget = event.widget
    index = widget.index("insert")
    if index == "1.0":
        return "break"
    while True:
        index = widget.index(f"{index} - 1 char")
        char = widget.get(index)
        widget.delete(index)
        if char.isspace() or index == "1.0":
            break
    return "break"

def save_note():
    """Open an enhanced dialog to take a note and save it as a Markdown file."""

    def save_and_close():
        note_content = text_box.get("0.0", "end").strip()
        if note_content:
            lines = note_content.split("\n")
            first_line_words = lines[0].strip().split()
            title = (
                lines[0].strip()
                if len(first_line_words) < words_title_limit
                else " ".join(first_line_words[:words_title_limit])
            )
            body = (
                "\n".join(lines[1:]).strip()
                if len(first_line_words) < words_title_limit
                else "\n".join(lines).strip()
            )

            date_property = datetime.now().strftime("%d/%m/%Y")
            filename = f"{title}.md".replace("/", "-").replace(
                "\\", "-"
            )  # Replace unsafe characters
            filepath = os.path.join(SAVE_PATH, filename)

            with open(filepath, "w", encoding="utf-8") as file:
                file.write(f"---\n")
                file.write(f"date: {date_property}\n")
                file.write(f"---\n\n")
                file.write(body)

            if os.path.exists(filepath):
                print(f"Nota guardada en {filepath}")
                notification.notify(
                    title="Nota Guardada",
                    message=f"Nota {title} guardada en Obsidian",
                    app_name=app_name,
                    app_icon=obsidian_icon_path,
                    timeout=4,
                )
            else:
                print("No se ingresó contenido. Nota no guardada.")
                notification.notify(
                    title="Nota No Guardada",
                    message=f"Hubo un error y no se ingresó el contenido.",
                    app_name=app_name,
                    app_icon=obsidian_icon_path,
                    timeout=4,
                )
        else:
            print("No se ingresó contenido. Nota no guardada.")
        root.destroy()

    # Create CustomTkinter window
    root = ctk.CTk()
    root.geometry("400x200")
    # Change window icon
    root.iconbitmap(obsidian_icon_path)
    root.title(app_name)
    root.attributes("-topmost", True)  # Ensure the window is always on top
    # Label and text box
    # label = ctk.CTkLabel(root, text="Write your note:", font=("Arial", 14))
    # label.pack(pady=10)

    # Detect system theme and apply the corresponding theme
    ctk.set_appearance_mode("system")

    text_box = ctk.CTkTextbox(root, width=380, height=180)
    text_box.pack(pady=10)

    root.update()  # Update the window to ensure it displays correctly
    root.focus_force()  # Force focus on the main window
    text_box.focus_set()

    # Button to save
    text_box.bind("<Control-Return>", lambda event: save_and_close())
    # save_button = ctk.CTkButton(root, text="Save", command=save_and_close)
    # save_button.pack(pady=10)

    # Binding to delete words with Ctrl+Backspace
    text_box.bind("<Control-BackSpace>", delete_word)

    root.mainloop()


if __name__ == "__main__":
    print(f"Listening for hotkey combination: {HOTKEY}")
    keyboard.add_hotkey(HOTKEY, save_note)

    # Keep the script running
    keyboard.wait()