RhetTbull / macnotesapp

Work with Apple MacOS Notes.app from the command line. Also includes python interface for scripting Notes.app from your own python code.
MIT License
128 stars 6 forks source link

first line should be style "title" (& markdown is ignored) #13

Open dmd opened 1 year ago

dmd commented 1 year ago

If I add a note using notes -e:

If I add a note using notes -e -m:

RhetTbull commented 1 year ago

Thanks -- I'll take a look. It's not possible to stylize the title via the Notes AppleScript interface so this is tricky to implement.

RhetTbull commented 1 year ago

I've been able to replicate this and did some testing via adding notes a number of different ways. If the name (title) of the note is blank, Notes sets the title to "Notes" which isn't helpful. Unfortunately, as annoying as this is, it may be something I can't fix as long as I'm stuck using the AppleScript interface to add notes. If I could find a private API that Apple uses and call that, I might be able to set the style for the title but at the moment, anything I try results in formatting being stripped from the title when added via AppleScript.

The first entry is the one created by Notes.app directly. The others were all created by macnotesapp.

[
    {
        "account": "iCloud",
        "id": "x-coredata://BA47E88C-3599-48BE-88DD-5CBC118E9CE6/ICNote/p1483",
        "name": "This is a brand new note",
        "body": "<div><h1>This is a brand new note</h1></div>\n<div><br></div>\n<div>This is body text.</div>\n",
        "creation_date": "2022-11-06T20:27:06",
        "modification_date": "2022-11-06T20:27:15",
        "password_protected": false,
        "folder": "Notes"
    },
    {
        "account": "iCloud",
        "id": "x-coredata://BA47E88C-3599-48BE-88DD-5CBC118E9CE6/ICNote/p1486",
        "name": "This is a brand new note added via `notes add -e -m`",
        "body": "<div><font face=\"Helvetica\">This is a brand new note added via `notes add -e -m`</font></div>\n<div><b><span style=\"font-size: 
24px\">This is markdown header 1</span></b></div>\n<div>This is some text</div>\n<div><b><span style=\"font-size: 18px\">This is a markdown header 
2</span></b></div>\n<div>This is more text</div>\n",
        "creation_date": "2022-11-06T20:32:13",
        "modification_date": "2022-11-06T20:32:13",
        "password_protected": false,
        "folder": "Notes"
    },
    {
        "account": "iCloud",
        "id": "x-coredata://BA47E88C-3599-48BE-88DD-5CBC118E9CE6/ICNote/p1487",
        "name": "This is a brand new note added via `notes add -e --html`",
        "body": "<div><font face=\"Helvetica\">This is a brand new note added via `notes add -e --html`</font></div>\n<div><b><span style=\"font-size: 
24px\">This is a heading</span></b></div>\n<div>This is a paragraph</div>\n<div>This is another paragraph</div>\n<div>This is a <b>bold</b> 
paragraph</div>\n",
        "creation_date": "2022-11-06T20:33:06",
        "modification_date": "2022-11-06T20:33:06",
        "password_protected": false,
        "folder": "Notes"
    },
    {
        "account": "iCloud",
        "id": "x-coredata://BA47E88C-3599-48BE-88DD-5CBC118E9CE6/ICNote/p1492",
        "name": "This is a brand new note added via `notes add -e --html` using same\u2026",
        "body": "<div><font face=\"Helvetica\">This is a brand new note added via `notes add -e --html` using same markup as 
Notes.app</font></div>\n<div><b><span style=\"font-size: 24px\">This is a brand new note added via `notes add -e --html` using same markup as 
Notes.app</span></b></div>\n<div>\\n</div>\n<div><br></div>\n<div>\\n</div>\n<div>This is body text.</div>\n<div>\\n&quot,</div>\n",
        "creation_date": "2022-11-06T20:44:57",
        "modification_date": "2022-11-06T20:44:57",
        "password_protected": false,
        "folder": "Notes"
    },
    {
        "account": "iCloud",
        "id": "x-coredata://BA47E88C-3599-48BE-88DD-5CBC118E9CE6/ICNote/p1488",
        "name": "<h1>This is a brand new note added via `notes add -e --html` but with\u2026",
        "body": "<div><font face=\"Helvetica\">&lth1&gtThis is a brand new note added via `notes add -e --html` but with header tags in the first 
line&lt/h1&gt</font></div>\n<div>This is some text</div>\n",
        "creation_date": "2022-11-06T20:34:15",
        "modification_date": "2022-11-06T20:34:15",
        "password_protected": false,
        "folder": "Notes"
    },
    {
        "account": "iCloud",
        "id": "x-coredata://BA47E88C-3599-48BE-88DD-5CBC118E9CE6/ICNote/p1485",
        "name": "This is a brand new note added via `notes add -e`",
        "body": "<div><font face=\"Helvetica\">This is a brand new note added via `notes add -e`</font></div>\n<div><br></div>\n<div>This is body 
text</div>\n",
        "creation_date": "2022-11-06T20:31:14",
        "modification_date": "2022-11-06T20:31:14",
        "password_protected": false,
        "folder": "Notes"
    }
]
dmd commented 1 year ago

I'd say submit this to https://feedbackassistant.apple.com/ but I have bugs of this caliber on there that are 8 years old that have never been looked at. I don't think anyone at Apple even knows it exists.

RhetTbull commented 1 year ago

I'm in the midst of a complete rewrite of this project to use ScriptingBridge (#16) and I've figured out how to apply style to the title of the note. I've not quite figured out how to replicate the default style Notes.app but think I can eventually do this. The new rewrite will be much faster and will enable a fully-interactive UI in the Terminal.

dmd commented 2 months ago

How's that going? :) I ran into this project again today - having completely forgotten about it - because a thing I'd really like is the ability to prepend some text to a specific note ("log") while retaining the note's title.

I ended up with

#!/bin/bash

input_text=$(cat|perl -pe 's/\n/<br>/g')

current_date=$(date +"%Y-%m-%d %H:%M:%S")

combined_text="<div><h3>$current_date</h3></div><div>$input_text</div>"

jxa_script=$(cat <<EOF
function run(inputText) {
    var Notes = Application("Notes");
    var logNote = Notes.notes.whose({ name: "log" })[0];
    var currentContent = logNote.body();

    var lines = currentContent.split(/<br>/);

    if (lines[0].includes("log")) {
        lines.shift();
    }

    var newContent = "<div><h1>log</h1></div><br>" + inputText + "<br>" + lines.join("<br>");
    logNote.body = newContent;
}

run("$combined_text");
EOF
)

# Execute the JXA script with the combined text
osascript -l JavaScript -e "$jxa_script"

Which works but I'm not especially happy with it.

And then I remembered your project, but your project doesn't allow editing existing notes.

RhetTbull commented 2 months ago

I've been busy with other projects. All I use this project for is adding new notes from Terminal. Unfortunately Notes.app doesn't provide any easy way to edit and preserve style. The current version of this tool creates the title in System Bold 24 which is what Notes uses for "H1" HTML tag and that's the best I can do as the API doesn't allow specifying fonts.

The majority of the code was rewritten to use ScriptingBridge so it is more performant (with exception of accessing folders which still require AppleScript).

I've thought about an editing feature but I'm not able to preserve any formatting which might come as a shock and result in data loss. For example, if you had a note that had tables, to-do lists, etc. and you rewrote that note with this package, all formatting would be lost including the tables and to-do list. I don't know of a way around this.

If you just want to prepend you could write yourself a python function to grab the old body of the note, prepend the new value then set the body to the new value. For example, this should be a good start:

"""Prepend text to the first selected note in Notes.app.

WARNING: this may result in loss of all formatting.
"""

import sys

import macnotesapp

def prepend(note: macnotesapp.Note, text: str):
    """Prepend text to the first selected note in Notes.app.

    Args:
        note: the note to prepend text to
        text: the text to prepend
    """

    # Note.body returns the HTML for the entire note including title
    # Note.plaintext returns the plain text for the entire note including title
    # This is a limitation of the Notes.app AppleScript API
    body = note.body
    name = body.split("\n")[0]
    body = f"{name}\n<div>{text}</div>\n" + "\n".join(body.split("\n")[1:])
    note.body = body

def main():
    """Prepend text to the first selected note in Notes.app.

    Usage:
        prepend.py TEXT
    """

    if len(sys.argv) < 2:
        print(__doc__)
        sys.exit(1)

    sel = macnotesapp.NotesApp().selection
    if not sel:
        print("No note selected")
        sys.exit(1)
    note = sel[0]
    prepend(note, sys.argv[1])

if __name__ == "__main__":
    main()

I'd love to offer more control over the content but Apple limits note editing / creation to plaintext or HTML and does not offer a native API for creating or editing notes except for the very limited AppleScript API.