Zettelkasten Forum


How to get the path to the archive

Hi, I am still seeking a clean way to get the path to my note, as requested here https://forum.zettelkasten.de/discussion/1401/request-some-way-of-getting-note-file-path#latest

To repeat my ask: apart from the current menu entry "Edit > Copy Link To Note", I request a "Edit > Copy Path to Note", which will give me enough information, and which will hopefully will be trivial for you to write.

Or, if the path to the archive is stored, perhaps somewhere in ~/Library, I can read from there...

Also, much less critical so feel free to ignore, is there yet a way to programmatically change the current folder?

Many thanks,
Abhijit

Comments

  • I see a path in "Group\ Containers/FRMDA3XRGC.de.zettelkasten.TheArchive.prefs/Library/Preferences/FRMDA3XRGC.de.zettelkasten.TheArchive.prefs.plist"

    Is that the right location

  • Abhijit, I use a two-step method when I want the full path of a note.

    /Users/will/Dropbox/zettelkasten/Cosmic Pastoral 202305170541.md

    I uploaded a gif showing how I do it. I'm not sure this is what you are asking. Do you want a note's full path or just the path to The Archive directory? I have a Python function for determining the full path to the active archive directory, but it doesn't return a specific path to a particular note.

    Right-click on the note in the note list, selecting "Reveal in finder," or use the shortcut. Then in Finder, "Copy the Pathname," which is available by pressing down the Option Key while right-clicking on the target file.

    The full pathname will be in the system clipboard.

    If you use Keyboard Maestro or Alfred, you set up a keyboard macro for this if you find yourself doing it a lot.

    The GIF turned out big and will take a minute to fully load, then it will run smoothly.

    Will Simpson
    I must keep doing my best even though I'm a failure. My peak cognition is behind me. One day soon I will read my last book, write my last note, eat my last meal, and kiss my sweetie for the last time.
    kestrelcreek.com

  • Thanks, Will.

    I do want both, and I figured it out now. The crucial thing is that this should happen via a program and fast (okay to use both Keyboard Maestro and Alfred). Now I get the Archive path by reading from that file (which is a plist), and I get the path from there to the note using Edit > Copy Link To Note.

    --Abhijit

  • edited May 2023

    @amahabal "Programmatic" inspection and modification is on my to-do list (via AppleScript) but not yet implemented.

    There's an undocumented trick, though :)

    Paste this into Script Editor:

    tell application "The Archive"
      «event TmngGpat»
    end tell
    

    This uses global system events to report the full path to the current note. That makes time tracking with Timing very accurate.

    Author at Zettelkasten.de • https://christiantietze.de/

  • Thanks, @ctietze! That is good to know. Do you have a document with other such "undocumented" tricks? That would be worth bookmarking...

  • If I had, that would be documenting them :)

    Some tips are on the help pages:
    https://zettelkasten.de/the-archive/help/

    Maybe I could add this one in case someone else looks for a way to ask The Archive for the currently open path (until AppleScript introspection works)

    Author at Zettelkasten.de • https://christiantietze.de/

  • In consultation with my ZK, I found a method/function that programmatically works with Python to find the currently active folder path to The Archive, using the plist. Special shout-out to @pryley for the insight. This may give you ideas for adaptation to the language you use.

    ---
    UUID:      ›[[202208021213]] 
    cdate:     08-02-2022 12:13 PM
    tags:      #code-snippet #python 
    ---
    # Get a Path from a Plist
    
    - Python [[202110091918]]
    
    from @pryley and works great in older versions of Python for finding the directory of The Archive.
    
    
    #!/usr/bin/env python3
    #encoding: utf-8
    
    from __future__ import absolute_import
    from Foundation import NSData
    from Foundation import NSPropertyListMutableContainers
    from Foundation import NSPropertyListSerialization
    import os
    import sys
    from urllib.parse import unquote
    
    
    class FoundationPlistException(Exception):
        """Basic exception for plist errors"""
        pass
    
    
    class NSPropertyListSerializationException(FoundationPlistException):
        """Read/parse error for plists"""
        pass
    
    
    class TheArchive:
        @staticmethod
        def path():
            archive_url = TheArchive.setting('archiveURL')
            path = unquote(archive_url[len("file://"):])
            return path
    
        @staticmethod
        def plist():
            bundle_id = "de.zettelkasten.TheArchive"
            team_id = "FRMDA3XRGC"
            filepath = os.path.expanduser(
                "~/Library/Group Containers/{0}.{1}.prefs/Library/Preferences/{0}.{1}.prefs.plist".format(team_id, bundle_id))
            if os.path.exists(filepath):
                plistData = NSData.dataWithContentsOfFile_(filepath)
                data, dummy_plistFormat, error = (
                    NSPropertyListSerialization.propertyListFromData_mutabilityOption_format_errorDescription_(
                        plistData, NSPropertyListMutableContainers, None, None
                    )
                )
                if data is None:
                    if error:
                        error = error.encode('ascii', 'ignore')
                    else:
                        error = "Unknown error"
                    raise NSPropertyListSerializationException(
                        "{0} in file {1}".format(error, filepath))
                else:
                    return data
            else:
                raise Exception("Error: Cannot find The Archive plist.")
    
        @staticmethod
        def setting(key):
            data = TheArchive.plist()
            try:
                return data[key]
            except KeyError:
                raise Exception(
                    u"Warning: Cannot get The Archive setting: {0}".format(key))
    
    
    path = TheArchive.path()
    sys.stdout.write(path)
    

    These are my modifications, and this is the function I currently use.

    ####
    # Function for finding the path to The Archive
    #####
    def TheArchivePath():
    #  Variables that ultimately revel The Archive's plist file.
        bundle_id = "de.zettelkasten.TheArchive"
        team_id = "FRMDA3XRGC"
        fileName = os.path.expanduser(
            "~/Library/Group Containers/{0}.{1}.prefs/Library/Preferences/{0}.{1}.prefs.plist".format(team_id, bundle_id))
        with open(fileName, 'rb') as fp:
            pl = load(fp) # load is a special function for use with a plist
            path = urlparse(pl['archiveURL']) # 'archiveURL' is the key that pairs with the zk path
        return (path.path) # path is the part of the path that is formatted for use as a path.
    
    if __name__ == "__main__":
        zettelkasten = pathlib.Path(TheArchivePath())
        print(f'The Current ZK Directory. {zettelkasten}')
        print(f'## {len(os.listdir(zettelkasten))} notes in the archive.')   
        subfolders = [ f.path for f in os.scandir(zettelkasten) if f.is_dir() ]
        for i in subfolders:
            print(f'## {len(os.listdir(i))} files in {i}.')
            print(f'## {sizeof_fmt(getFolderSize(i))} in {i}.')
            print('-'*40) 
    

    Output

    The Current ZK Directory. /Users/will/Dropbox/zettelkasten
    ## 3360 notes in the archive.
    ## 3 files in /Users/will/Dropbox/zettelkasten/link-previews.
    ## 774.7 Kilobytes in /Users/will/Dropbox/zettelkasten/link-previews.
    ----------------------------------------
    ## 15 files in /Users/will/Dropbox/zettelkasten/icons.
    ## 241.6 Kilobytes in /Users/will/Dropbox/zettelkasten/icons.
    ----------------------------------------
    ## 3 files in /Users/will/Dropbox/zettelkasten/export.
    ## 25.1 Kilobytes in /Users/will/Dropbox/zettelkasten/export.
    ----------------------------------------
    ## 8 files in /Users/will/Dropbox/zettelkasten/Writing.
    ## 7.1 Megabytes in /Users/will/Dropbox/zettelkasten/Writing.
    ----------------------------------------
    ## 600 files in /Users/will/Dropbox/zettelkasten/media.
    ## 1022.5 Megabytes in /Users/will/Dropbox/zettelkasten/media.
    ----------------------------------------
    

    Will Simpson
    I must keep doing my best even though I'm a failure. My peak cognition is behind me. One day soon I will read my last book, write my last note, eat my last meal, and kiss my sweetie for the last time.
    kestrelcreek.com

  • Hi @Will,

    I notice that in that code you are processing the plist with the NSData business. However, there is a standard plistlib module you could instead use. My code:

    import os
    import plistlib
    import sys
    
    def get_archive_directory():
        filenname = os.path.expanduser(
            "~/Library/Group Containers/FRMDA3XRGC.de.zettelkasten.TheArchive.prefs/"
            "Library/Preferences/FRMDA3XRGC.de.zettelkasten.TheArchive.prefs.plist")
        with open(filenname, 'rb') as fp:
            pl = plistlib.load(fp)
            return pl['archiveURL'] 
    
  • Hi @amahabal, the NSData business is from the Python 2.7 days. The function currently used is below. Mine returns the path as a path rather than a dictionary. I practiced adding some error handling in another version.

    Thanks for a look into your code, your function is a bit crisper.

    My code:

    from urllib.parse import urlparse
    import os, pathlib
    from plistlib import load
    
    def TheArchivePath():
    #  Variables that ultimately revel The Archive's plist file.
        bundle_id = "de.zettelkasten.TheArchive"
        team_id = "FRMDA3XRGC"
        #`fileName` is the path to the plist file that contains the path to the ZK.
        fileName = os.path.expanduser(
            "~/Library/Group Containers/{0}.{1}.prefs/Library/Preferences/{0}.{1}.prefs.plist".format(team_id, bundle_id))
        with open(fileName, 'rb') as fp:
            # load is a special function for use with a plist
            pl = load(fp) 
            # 'archiveURL' is the key that pairs with the zk path
            path = urlparse(pl['archiveURL']) 
        # path is the part of the path that is formatted for use as a path.
        return (path.path) 
    
    if __name__ == "__main__":
        zettelkasten = pathlib.Path(TheArchivePath())
        print(f'The Current ZK Directory. {zettelkasten}')
    

    Will Simpson
    I must keep doing my best even though I'm a failure. My peak cognition is behind me. One day soon I will read my last book, write my last note, eat my last meal, and kiss my sweetie for the last time.
    kestrelcreek.com

Sign In or Register to comment.