Quickest route from Delicious Library 3 to Bookends ?

A place for users to ask each other questions, make suggestions, and discuss Bookends.
Post Reply
ComplexPoint
Posts: 9
Joined: Sun Jun 26, 2016 7:19 pm

Quickest route from Delicious Library 3 to Bookends ?

Post by ComplexPoint »

Before I draft a script to write out Bookends JSON from DL3 plists,
is there a better route that I have missed ?

(Delicious Library 3 doesn't seem to export BibTeX, which was a previous route)
Jon
Site Admin
Posts: 10048
Joined: Tue Jul 13, 2004 6:27 pm
Location: Bethesda, MD
Contact:

Re: Quickest route from Delicious Library 3 to Bookends ?

Post by Jon »

Yeah, they really dumbed it down. I'm afraid I don't see any easy route from DL3 -> Bookends.

If you happen to own Bookpedia, it seems it can import DL3 XML

https://www.bruji.com/forum/viewtopic.php?f=8&t=6995

which you can then export as BibTeX or Endnote.


Jon
Sonny Software
ComplexPoint
Posts: 9
Joined: Sun Jun 26, 2016 7:19 pm

Re: Quickest route from Delicious Library 3 to Bookends ?

Post by ComplexPoint »

This is what I did in the end (JavaScript for Automation)

(Probably a niche use case, so I haven't generalised it for others with file-choosing dialogs etc,
but certainly could, if anyone else might find that useful)

Code: Select all

(() => {
    "use strict";

    const main = () => {
        const
            fpDL3xml = "~/Desktop/Library Export 2021-09-24.xml",
            fpBookendsJSON = "~/Desktop/Library Export 2021-09-24.bex";

        return either(
            alert("Bookends JSON from Delicious 3 XML")
        )(
            json => (
                writeFile(fpBookendsJSON)(json),
                json
            )
        )(
            bindLR(
                readPlistArrayFileLR(fpDL3xml)
            )(
                xs => Right(showJSON(xs.map(x => ({
                    type: beTypeFromAzType(x.type),
                    title: x.title,
                    authors: x.creatorsCompositeString,
                    publisher: x.publishersCompositeString,
                    thedate: beDateFromISO8601(
                        x.publishDate || ""
                    )
                }))))
            )
        );
    };

    // ---------- BOOKENDS JSON FROM DL3 PLIST -----------

    // beTypeFromAzType :: String -> String
    const beTypeFromAzType = s =>
        ({
            "Book": "2"
        })[s] || "2";

    const beDateFromISO8601 = s =>
        Boolean(s) ? (
            "Date" !== s.constructor.name ? (
                `${s}`
            ) : s.toJSON().slice(0, 4)
        ) : "";

    // ---------------------- PLIST ----------------------

    // readPlistArrayFileLR :: FilePath -> Either String Object
    const readPlistArrayFileLR = fp =>
        bindLR(
            doesFileExist(fp) ? (
                Right(filePath(fp))
            ) : Left(`No file found at path:\n\t${fp}`)
        )(fpFull => {
            const
                e = $(),
                maybeDict = (
                    $.NSArray
                    .arrayWithContentsOfURLError(
                        $.NSURL.fileURLWithPath(fpFull),
                        e
                    )
                );

            return maybeDict.isNil() ? (() => {
                const msg = ObjC.unwrap(e.localizedDescription);

                return Left(`readPlistFileLR:\n\t${msg}`);
            })() : Right(ObjC.deepUnwrap(maybeDict));
        });

    // ----------------------- JXA -----------------------

    // alert :: String => String -> IO String
    const alert = title =>
        s => {
            const sa = Object.assign(
                Application("System Events"), {
                    includeStandardAdditions: true
                });

            return (
                sa.activate(),
                sa.displayDialog(s, {
                    withTitle: title,
                    buttons: ["OK"],
                    defaultButton: "OK"
                }),
                s
            );
        };

    // --------------------- GENERIC ---------------------

    // Left :: a -> Either a b
    const Left = x => ({
        type: "Either",
        Left: x
    });


    // Right :: b -> Either a b
    const Right = x => ({
        type: "Either",
        Right: x
    });


    // bindLR (>>=) :: Either a ->
    // (a -> Either b) -> Either b
    const bindLR = m =>
        mf => m.Left ? (
            m
        ) : mf(m.Right);


    // doesFileExist :: FilePath -> IO Bool
    const doesFileExist = fp => {
        const ref = Ref();

        return $.NSFileManager.defaultManager
            .fileExistsAtPathIsDirectory(
                $(fp)
                .stringByStandardizingPath, ref
            ) && 1 !== ref[0];
    };

    // either :: (a -> c) -> (b -> c) -> Either a b -> c
    const either = fl =>
        // Application of the function fl to the
        // contents of any Left value in e, or
        // the application of fr to its Right value.
        fr => e => "Left" in e ? (
            fl(e.Left)
        ) : fr(e.Right);

    // filePath :: String -> FilePath
    const filePath = s =>
        // The given file path with any tilde expanded
        // to the full user directory path.
        ObjC.unwrap(ObjC.wrap(s)
            .stringByStandardizingPath);


    // showJSON :: a -> String
    const showJSON = x =>
        // Indented JSON representation of the value x.
        JSON.stringify(x, null, 2);

    // writeFile :: FilePath -> String -> IO ()
    const writeFile = fp => s =>
        $.NSString.alloc.initWithUTF8String(s)
        .writeToFileAtomicallyEncodingError(
            $(fp)
            .stringByStandardizingPath, false,
            $.NSUTF8StringEncoding, null
        );

    // MAIN ---
    return main();
})();
Jon
Site Admin
Posts: 10048
Joined: Tue Jul 13, 2004 6:27 pm
Location: Bethesda, MD
Contact:

Re: Quickest route from Delicious Library 3 to Bookends ?

Post by Jon »

That's great. Would you please post the script in our AppleScript forum? Others who might find it useful would probably look for it there, not in the (much busier) general forum.

Jon
Sonny Software
Post Reply