Jump to content
sballin

Search Apple/iCloud Notes (High Sierra, Mojave, and more)

Recommended Posts

@sballin You already know how much I love this workflow, so I won't bore you with more praise! Ha

 

If you're still accepting suggestions for tinkering with the workflow, is it possible to add another action modifier that allows users to open the selected note in its own window (i.e., instead of the default that always opens in the app's main window)? There are often times when I need to quickly look at something in a note while I'm working on another one, and I've love to be able to do that a little more quickly. Thanks!

Share this post


Link to post

Hi Sean, 

 

I've been a happy user of this workflow for a couple of months, thank you. But last week it mysteriously stopped searching notes and I''m not sure what's going on. I guess this is only me because I haven't heard anyone else on this thread have any issues. What's strange is the folder "fn" search works fine but not the general "n" search. 

 

Is there something I can do to get this workflow up and running again? 

 

Thanks

 

Reg

 

 

#!/usr/bin/python
import sqlite3
import zlib
import re
import os


def extractNoteBody(data):
    try:
        # Strip weird characters, title & weird header artifacts, 
        # and replace line breaks with spaces
        data = zlib.decompress(data, 16+zlib.MAX_WBITS).split('\x1a\x10', 1)[0]

        # Reference: https://github.com/threeplanetssoftware/apple_cloud_notes_parser
        # Find magic hex and remove it
        index = data.index('\x08\x00\x10\x00\x1a')
        index = data.index('\x12', index)

        # Read from the next byte after magic index
        data = data[index+1:]

        data = unicode(data, "utf8", errors="ignore")

        return re.sub('^.*\n|\n', ' ', data)
    except Exception as e:
        return 'Note body could not be extracted: {}'.format(e)
        
        
def readDatabase():
    # Open notes database
    home = os.path.expanduser('~')
    db = home + '/Library/Group Containers/group.com.apple.notes/NoteStore.sqlite'
    conn = sqlite3.connect(db)
    c = conn.cursor()

    # Get uuid string required in full id
    c.execute('SELECT z_uuid FROM z_metadata')
    uuid = str(c.fetchone()[0])

    # Get tuples of note title, folder code, modification date, & id#
    c.execute("""SELECT t1.ztitle1,t1.zfolder,t1.zmodificationdate1,
                        t1.z_pk,t1.znotedata,t2.zdata,t2.z_pk
                 FROM ziccloudsyncingobject AS t1
                 INNER JOIN zicnotedata AS t2
                 ON t1.znotedata = t2.z_pk
                 WHERE t1.ztitle1 IS NOT NULL 
                       AND t1.zmarkedfordeletion IS NOT 1""")
    # Get data and check for d[5] because a New Note with no body can trip us up
    dbItems = [d for d in c.fetchall() if d[5]]
    dbItems = sorted(dbItems, key=lambda d: d[sortId], reverse=sortInReverse)

    # Get ordered lists of folder codes and folder names
    c.execute("""SELECT z_pk,ztitle2 FROM ziccloudsyncingobject
                 WHERE ztitle2 IS NOT NULL 
                       AND zmarkedfordeletion IS NOT 1""")
    folderCodes, folderNames = zip(*c.fetchall())

    conn.close()
    return uuid, dbItems, folderCodes, folderNames


# Sort matches by title or modification date, option to search titles only.
# Edit with Alfred workflow environment variable.
sortId = 2 if os.getenv('sortByDate') == '1' else 0
searchTitlesOnly = (os.getenv('searchTitlesOnly') == '1')
sortInReverse = (sortId == 2)

if __name__ == '__main__':
    # Custom icons to look for in folder names
    icons = [u'\ud83d\udcd3', u'\ud83d\udcd5', u'\ud83d\udcd7', u'\ud83d\udcd8', 
             u'\ud83d\udcd9']

    # Read Notes database and get contents
    try:
        uuid, dbItems, folderCodes, folderNames = readDatabase()
        openedDatabase = True
    except:
        openedDatabase = False
             
    if openedDatabase:
        # Alfred results: title = note title, arg = id to pass on, subtitle = folder name, 
        # match = note contents from gzipped database entries after stripping footers.
        items = [{} for d in dbItems]
        gotOneRealNote = False
        for i, d in enumerate(dbItems):
            try:
                folderName = folderNames[folderCodes.index(d[1])]
                if folderName == 'Recently Deleted':
                    continue
                body = extractNoteBody(d[5])
                subtitle = folderName + '  |' + body[:100]
                match = u'{} {} {}'.format(d[0], folderName, '' if searchTitlesOnly else body)
                
                # Custom icons for folder names that start with corresponding emoji
                if any(x in subtitle[:2] for x in icons):
                    iconText = subtitle[:2].encode('raw_unicode_escape')
                    subtitle = subtitle[3:]
                    icon = {'type': 'image', 'path': 'icons/' + iconText + '.png'}
                else:
                    icon = {'type': 'default'}
                
                items = {'title': d[0],
                            'subtitle': subtitle,
                            'arg': 'x-coredata://' + uuid + '/ICNote/p' + str(d[3]),
                            'match': match,
                            'icon': icon}
                gotOneRealNote = True
            except Exception as e:
                items = {'title': 'Error getting note', 'subtitle': str(e)}
                
    if openedDatabase and gotOneRealNote:
        import json 
        print json.dumps({'items': items})
    else:
        import subprocess 
        print subprocess.check_output(os.path.dirname(__file__) 
                                      + '/searchNoteTitles.applescript')
 

Edited by Regluke
Grammar

Share this post


Link to post

Hi all! Opening notes in a new window and supporting folders are on my to-do list. 

 

@Regluke to debug, could you open the workflow in Alfred preferences and click on the bug icon on the top right corner? That will open a little white area for debug info. Then try searching for something with n and send me what shows up in the debug window. 

Share this post


Link to post

Hi @sballin

This is the first time I've done this and it shows a lot of data. I copied the first part which shows the error. Does this help?

 

[2019-01-27 20:34:03][ERROR: input.scriptfilter] JSON error: Unexpected end of file during string parse (expected low-surrogate code point but did not find one). in JSON:

{"items": [{"icon": {"type": "default"}, "arg": "x-coredata://6B56A1ED-C957-4AB0-931E-71C6EA9E972C/ICNote/p23847", "subtitle": "Notes  | 

 

 

 

Also I came across this other error when using the 'fn' search which usually works for me.

 

[2019-01-27 20:38:08][ERROR: action.applescript] {

    NSAppleScriptErrorAppName = Notes;

    NSAppleScriptErrorBriefMessage = "Can\U2019t get folder id \"x-coredata://6B56A1ED-C957-4AB0-931E-71C6EA9E972C/ICFolder/p4001\".";

    NSAppleScriptErrorMessage = "Notes got an error: Can\U2019t get folder id \"x-coredata://6B56A1ED-C957-4AB0-931E-71C6EA9E972C/ICFolder/p4001\".";

    NSAppleScriptErrorNumber = "-1728";

    NSAppleScriptErrorRange = "NSRange: {89, 25}";

}

 

 

 

Please let me know if you need any additional information. Thanks a lot.

 

 

Reg

 

 

 

 

Edited by Regluke
Added sballin to message.

Share this post


Link to post

@sballin Thank you, Thank you, Thank you!

 

I updated the app and it's working perfectly again!

 

This is really one of the few workflows which I depend upon every day. If there's a way for us to donate or something to support you, please let me know!

Share this post


Link to post

@Regluke that's very kind of you, you can donate here if you like but don't worry, it didn't take long to fix your issue and I think most people would have run into it at some point, so you've already done a service by reporting it.

 

@Jasondm007 I poked around with AppleScript to open a note in a new window and couldn't figure it out, so I don't think I'll be able to add this feature. I'll be happy to add it if anyone else figures it out.

Share this post


Link to post
36 minutes ago, sballin said:

It should be possible, but isn't that duplicating the functionality of Alfred snippets?

 

 

In some way yes. However, I keep all my code snippets in Notes, so simply searching and copying them to the clipboard would work very well.

Share this post


Link to post

This workflow isn't working for me, when I type 'n' I see a list of notes and if I type one letter it searches but when I type a 2nd it switches off to contacts instead of sticking with the Notes workflow.

 

I am using Catalina, which may be why, just wanted to report early!

 

Thanks for this fantastic workflow!

Share this post


Link to post
13 hours ago, keithah said:

This workflow isn't working for me, when I type 'n' I see a list of notes and if I type one letter it searches but when I type a 2nd it switches off to contacts instead of sticking with the Notes workflow.

 

I am using Catalina, which may be why, just wanted to report early!

 

Thanks for this fantastic workflow!

 

Thanks for the report! I tried it on Catalina just now and it worked for me. I think the issue is that you have contacts included in the default search results, so you could turn that (and the other defaults) off if you really want n[search string] to work for searching. An alternative that I've come to prefer is to map command-space to open Notes, and command-L to do the note search. The workflow includes empty hotkey boxes that you can set this way.

Share this post


Link to post

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...