Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for attachments #15

Open
RhetTbull opened this issue Dec 5, 2022 · 10 comments
Open

Add support for attachments #15

RhetTbull opened this issue Dec 5, 2022 · 10 comments
Labels
enhancement New feature or request

Comments

@RhetTbull
Copy link
Owner

Attachments are not currently handled.

@RhetTbull RhetTbull added the enhancement New feature or request label Dec 5, 2022
@SKaplanOfficial
Copy link

You could use an AppleScript bridge such as appscript or my own PyXA for this, or interface with ScriptingBridge via pyobjc:

import ScriptingBridge
notes = ScriptingBridge.SBApplication.alloc().initWithBundleIdentifier_("com.apple.notes")
attachments = notes.attachments()
for attachment in attachments:
    print(attachment.URL())

I think the way you're handling AppleScripts now works well for one-off actions but is inefficient for bulk actions (e.g. getting the name of 100s of notes at a time). For reference, in PyXA you can do Application("Notes").notes().name() to list the name of every note almost instantaneously as it requests all note names in one Apple Event request instead of for each note successively.

Granted, PyXA is a larger library than you need here, so I'd recommend either using pyobjc-ScriptingBridge or implementing some logic to merge bulk requests into singular AppleScript calls.

@RhetTbull
Copy link
Owner Author

@SKaplanOfficial I wasn't aware of PyXa. Had played around with ScriptingBridge a bit on another project but got frustrated by lack of documentation. I just toyed around with PyXA -- amazing work! I may just rewrite macnotesapp to use PyXA as it is so much faster. I have a similar project photoscript that uses the same AppleScript techniques that might benefit from PyXA (though photoscript currently supports creating folders/albums, moving photos from one album to another, etc. that don't appear to be supported in PyXA yet).

@SKaplanOfficial
Copy link

SKaplanOfficial commented Dec 22, 2022

@RhetTbull Yeah, ScriptingBridge is a bit of a pain to work with, but I've found it to be robust enough for my needs. I wanted PyXA to serve as sort of an extended reference for ScriptingBridge/pyobjc as a whole since the existing documentation was... lacking. PyXA currently supports creating folders and albums, but moving photos is something I'm working on (moving AS objects in general, really, since the implementation varies slightly across different apps).

If you do use PyXA, let me know if you run into any problems -- I'd be happy to help!

@RhetTbull
Copy link
Owner Author

PyXA currently supports creating folders and albums

Great! I'll dive into the docs and source over the holiday break. I quickly skimmed the docs and thought I saw those as still "todo". Quick question: is it possible to access an existing album by path (e.g. Folder1/SubFolder1/AlbumName and get back an album object?) That's something I do a lot for another project and the current AppleScript implementation is awfully slow so I'm in the middle of a big refactor.

@SKaplanOfficial
Copy link

Quick question: is it possible to access an existing album by path (e.g. Folder1/SubFolder1/AlbumName and get back an album object?)

Yes and no; you can't access it by path in the form you specified, but you can use by_name() to get an album/folder object quickly. For example:

import PyXA
app = PyXA.Application("Photos")
print(app.folders().by_name("Folder1").folders().by_name("Folder2").albums().by_name("Album1"))
>>> <<class 'PyXA.apps.PhotosApp.XAPhotosAlbum'>Album1, id=F0DA93AB-CC92-23B2-9E16-973F6A062468/L0/040>

This should work near-instantly in most cases, unless your by_ call is to something that has to be queried per-object, e.g. for the body text (not plaintext) of notes.

@RhetTbull
Copy link
Owner Author

Perfect -- thanks!

@RhetTbull
Copy link
Owner Author

I'm able to add attachments (on Ventura at least, does not work on Catalina, not sure about Big Sur/Monterey) using the following AppleScript:

tell application "Notes"
	set theNote to note id "x-coredata://B36F4BF3-D2F0-4997-BD9B-96A608B6D5E0/IMAPNote/p40"
	set theFile to POSIX file "/Users/rhet/Downloads/debug.txt"
	make new attachment at theNote with data theFile
end tell

Can't figure out a way to do this via ScriptingBridge though.

@SKaplanOfficial
Copy link

This works for me to add an attachment on Ventura:

import AppKit
import ScriptingBridge

app = ScriptingBridge.SBApplication.alloc().initWithBundleIdentifier_("com.apple.notes")
note = app.notes()[0]
url = AppKit.NSURL.alloc().initFileURLWithPath_("/Users/exampleUser/Documents/Example.jpg")
new_attachment = app.classForScriptingClass_("attachment").alloc().initWithData_andProperties_(url, {})
note.attachments().addObject_(new_attachment)

But the AppleScript approach is probably good enough (and maybe better on other macOS versions).

@RhetTbull
Copy link
Owner Author

Thanks! Will give that a try! I've been digging through your PyXA source to figure out ScriptingBridge and its been immensely helpful but it's still a lot of trial and error. I did get most of macnotesapp rewritten to use ScriptingBridge though and it's much faster now. I'd like to contribute back to PyXA once I get through my current round of projects. (for example, I've got a partial interface to Photos via PhotoKit that's much faster than scripting)

@RhetTbull
Copy link
Owner Author

RhetTbull commented Jan 5, 2023

Out of curiosity I benchmarked both the ScriptingBridge implementation and the AppleScript version:

M1 Mac Mini running Ventura:

AppleScript: ~300ms to add an attachment
ScriptingBridge: ~80ms to add attachment

ScriptingBridge is the clear winner however, I stuck with AppleScript as the ScriptingBridge sometimes ended up in duplicate attachments being added. The formatting of the note (how the breaks were inserted between attachments) was also wonky with ScriptingBridge when inserting multiple attachments.

Also, calling .attachments() on the Note object resulted in duplicates regardless of which method was used to add the attachment. That is, the resulting SBElementArray always contained the same attachment twice (verified by looking at total number of attachments which was always 2x what it should be and also that each id was in the SBElementArray twice. No idea why but I'm filtering for those now to eliminate the dupes. This appears to happen only with attachments added via the ScriptingBridge or AppleScript, not with those added natively in the GUI.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants