That’s the exact mentality which kicked up enshittification. We as a society prefer crappy things to nothing, so we eventually end up with a crappy world to live with. Have you ever seen one beautiful advertisement after the AI takeover in the last couple of years? When was your previous visit to a new website which is both aesthetically pleasing and not Tailwind-ish?
A single act of asking AI for a script is not directly consequential in its own, however it’s part of a society-wide pattern which is indeed consequential. We as individuals are responsible in so far as we have contributed to the pattern by being a part of it.
so, what am I supposed to do?
I have work I need to do.
Should I hire top talent for $10,000 an hour to produce something for my simple needs?
Am I supposed to go to Tibet and seek wisdom to help me figure out how to best approach this?
Should I post on upwork for the highest paid, and best?
Or just use some glue, some glitter, and polish up a turd that does what I want in 10 min… Even if it looks like frankenstein?
Should I hire top talent for $10,000 an hour to produce something for my simple needs?
You can only define your end product as “simple”, not necessarily the manufacturing leading to the end product.
It seems like you are imagining a system, not automating one you’re already working with. Is that the case? If so, that is rarely a good idea, especially as you may abandon the approach then have to start anew. Automation should be used to make an existing process more efficient, a process you can already do comfortably and manually. That way, when the automation breaks, you can continue the work manually.
I have work I need to do.
Which is what specifically? We don’t know anything about the nature of your work or use case. Well at least I don’t.
Once these pages are created, I plan to add item links to track how many notes are connected to each heading. Additionally, I would like to group these “heading pages” into a separate, dedicated group to make them easier to manage and distinguish from my regular notes. This grouping would serve as a catalog for the headings.
What do you plan to do about these things?
By the way, manually clicking the links to create WikiLinked documents provide more functionality than what you’re doing. Look at the template section in Settings > WikiLinks. That can be used to create documents with data already in them, e.g., a backlink to the originating document, dates, etc.
Thanks for the reply…
Yes, I can go through the notes one by one and click on the wikilink to create the page, then copy the item link to the created wikipage manually, but I’d rather throw the computer out the window. That will take ages.
The headings is like an “index” of sorts. I’m already using tags, but they’re specific for items in the text, whereas the headings are “overall” concepts in the text.
So, for example, if I’m exploring topic X, I can look at relevant tags, then go to a more broader heading section which should have more related ideas.
The steps are simple, but very tedious to do manually.
the wiki settings… If I have several notes with the same [[heading]] will they be linked through the process you just posted? Let me see if I can make your way work
Do you mean the document’s title is the heading?
If so, then WikiLinking wouldn’t work for your purpose anyways. A WikiLink points to a single document with a specific name, not to many nor to a choice of documents with the same name.
that’s what a note’s metadata looks like…
The notes are more specific to the text in the note, the headings are the concepts that will be shared amongst many more notes. Somewhat like an “index”…
You do what you want to do, of course. You are a free person.
Please do be aware, though, that even “obvious” things have their implications. It seems you’re keenly aware of the obstacles to writing a script yourself. I (and perhaps others who post human-written scripts on this forum, too) hope you be aware of the issues of AI-generated scripting as well. It’s up to you whether you will care about the implications. In the end, no option is perfect, so it’s essentially a choice between two evils.
It was an honest question. I have this problem, and I need to work through it. You suggested learn to code so that I don’t create crappy stuff with ai, but that just reminds me of people in the old times saying “n00b” and just ignore the person, or said, read the man pages. Not very helpful.
I can find a “guru” to tell me the best practices, or whatnot, but I need a tool now, not to learn to program…
I’m trying my best to come up with a tool I need, if I can’t get it quite right, then I ask here… for suggestions… not “be better – write by hand”
Yes, I can go get a degree in CS, and maybe I’ll be able to work through my programming needs, but that’s not my profession.
I use Wikilinks in DEVONthink to categorize and provide context for my notes. These Wikilinks act as “heading categories,” helping me organize and interconnect my ideas. Over time, I’ve accumulated a large number of these headings, but creating the corresponding Wikilink pages manually is time-consuming and tedious.
What I want is a way to automate the creation of Wikilink pages for all the links in my notes. Once the pages are created, I plan to take it a step further by:
Adding item links to track how many notes are connected to each heading.
Organizing these pages into a dedicated group in DEVONthink. This would make it easier to manage and distinguish these “heading pages” from my regular notes. The group would essentially act as a catalog for my headings.
This automation would save me a lot of time and effort.
My Current Situation
In my notes, headings look something like this:
[[Cognitive Aging]]
[[Performance Assessment]]
[[Speed-Accuracy Tradeoff]]
[[Baseline Performance]]
I want to ensure there’s a corresponding page in DEVONthink for each of these headings without having to create them one by one.
What I’m Looking For
I need a script or tool that can:
Find all the Wikilinks in my notes.
Automatically generate a new page in DEVONthink for each unique Wikilink that doesn’t already have a page.
Optionally: Add item links to track related notes, so I can see how many notes connect to each heading.
Organize all these created pages into a dedicated group, keeping them separate from my regular notes for easier navigation and management.
Fully scripted. No WikiLink settings used. Doesn’t create redundant documents. Processes WikiLinks inline, not just segregated in lists. And it’s pure vanilla AppleScript - no shell, not ASOC, not shenanigans (and trust me, it’s harder to accomplish in pure AS).
Half-asleep at the wheel so I don’t have the wherewithal to discuss formatting and frills. But this fulfils the requirements.
I like how you use Set to get unique linkNames. And at first I thought the match()?. was a typo, until I looked it up – thanks for teaching me something new!
A remark on
(what does the ? do after the match()?)
First, I’d use push instead of concat – that appends to the linkNames and makes the assignment unnecessary.
Second, since you’re using the g flag on the match anyway, why not use matchAll, too? And perhaps with a capturing group? Well, it might become a tad more unruly with that. linkNames.push([... r.plainText().matchAll(/\[\[(.*?)\]\]/gm)]?.map(item => item[1]) || []);
Not sure if ?. is needed in this case as matchAll should only return successful matches anyway.
matchAll produces an iterator instead of an array, which can’t be mapped directly. (Just tested that in Script Editor.) So I think match + slice and matchAll + spread are equal — both requiring two basic actions.
AFAIK array1 = array1.concat(array2) and array1.push(array2) does not produce the same result.
match() returns null if no match is found. Running null.map() will not work. Optional chaining avoids this potential error.
We keep learning — I picked up the [...new Set(array)] trick fresh last night from Stack Exchange
Ok, this one seems to work without crashing, and doing what I need…
use AppleScript version "2.4"
use scripting additions
tell application id "DNtp"
try
-- Get the current database and selected records
set theDB to current database
if theDB is missing value then error "Please open a database first."
set selectedRecords to selected records
if (count of selectedRecords) is 0 then error "Please select some documents to process."
-- Get or create the headings group
set headingsGroup to get record at "/Heading Pages" in theDB
if headingsGroup is missing value then
-- Create the Heading Pages group
set headingsGroup to create record with {name:"Heading Pages", type:group} in theDB
set comment of headingsGroup to "This group contains automatically generated pages for all wikilinks found in your documents. Each page tracks which documents reference that particular heading."
display alert "Created Heading Pages Group" message "Created a new group to store wikilink pages."
end if
-- Show progress
show progress indicator "Processing Records" steps (count of selectedRecords)
-- Process each selected record
repeat with theRecord in selectedRecords
if type of theRecord is in {markdown, txt, rtf, rtfd} then
step progress indicator ("Processing " & (name of theRecord as string))
-- Get content and look for wikilinks
set theContent to plain text of theRecord
-- Save original delimiters
set savedDelimiters to AppleScript's text item delimiters
-- Find all wikilinks in the content
set wikilinks to {}
set currentPos to 1
set contentLength to length of theContent
repeat while currentPos ≤ contentLength
-- Find next "[[" marker
set startPos to offset of "[[" in (texts currentPos thru contentLength of theContent)
if startPos is 0 then exit repeat
-- Adjust position to actual location
set startPos to currentPos + startPos + 1
-- Find closing "]]"
set remainingText to texts startPos thru contentLength of theContent
set endPos to offset of "]]" in remainingText
if endPos is 0 then exit repeat
-- Extract the wikilink text
set linkText to texts 1 thru (endPos - 1) of remainingText
-- Add to wikilinks if not empty and not already found
if linkText is not "" and linkText is not in wikilinks then
set end of wikilinks to linkText
end if
-- Move past this wikilink
set currentPos to startPos + endPos + 1
end repeat
-- Process found wikilinks
repeat with linkText in wikilinks
-- Create or get wikilink page
set wikiPage to get record at ("/Heading Pages/" & linkText) in theDB
if wikiPage is missing value then
set wikiPage to create record with {name:linkText, type:markdown} in headingsGroup
set plain text of wikiPage to "# " & linkText & return & return & "## Documents referencing this heading" & return
end if
-- Add reference only if it doesn't exist
set docURL to reference URL of theRecord
set docLink to "- [" & (name of theRecord as string) & "](" & docURL & ")"
set pageContent to plain text of wikiPage
if pageContent does not contain docLink then
if last character of pageContent is not return then
set pageContent to pageContent & return
end if
set plain text of wikiPage to pageContent & docLink & return
end if
end repeat
-- Restore delimiters
set AppleScript's text item delimiters to savedDelimiters
end if
end repeat
hide progress indicator
display alert "Complete" message "Finished processing selected documents."
on error error_message number error_number
-- Restore delimiters in case of error
set AppleScript's text item delimiters to savedDelimiters
hide progress indicator
if error_number is not -128 then
display alert "Error" message error_message
end if
end try
end tell
Correct. That’s why I used the array constructor [... matchAll(…)]. Alternatively, Array.from(matchAll(…)) does the same thing – build an Array from something else.
Correct. I overlooked that you’re concating arrays.
This one will even remove references to notes in the heading pages if you remove the wikilink [[ ]] from notes referencing a heading.
use AppleScript version "2.4"
use scripting additions
tell application id "DNtp"
try
-- Get the current database and selected records
set theDB to current database
if theDB is missing value then error "Please open a database first."
set selectedRecords to selected records
if (count of selectedRecords) is 0 then error "Please select some documents to process."
-- Get or create the headings group
set headingsGroup to get record at "/Heading Pages" in theDB
if headingsGroup is missing value then
-- Create the Heading Pages group
set headingsGroup to create record with {name:"Heading Pages", type:group} in theDB
set comment of headingsGroup to "This group contains automatically generated pages for all wikilinks found in your documents. Each page tracks which documents reference that particular heading."
display alert "Created Heading Pages Group" message "Created a new group to store wikilink pages."
end if
-- Show progress
show progress indicator "Processing Records" steps (count of selectedRecords)
-- Process each selected record
repeat with theRecord in selectedRecords
if type of theRecord is in {markdown, txt, rtf, rtfd} then
step progress indicator ("Processing " & (name of theRecord as string))
-- Get content and look for wikilinks
set theContent to plain text of theRecord
-- Save original delimiters
set savedDelimiters to AppleScript's text item delimiters
-- Find all wikilinks in the content
set wikilinks to {}
set currentPos to 1
set contentLength to length of theContent
repeat while currentPos ≤ contentLength
-- Find next "[[" marker
set startPos to offset of "[[" in (texts currentPos thru contentLength of theContent)
if startPos is 0 then exit repeat
-- Adjust position to actual location
set startPos to currentPos + startPos + 1
-- Find closing "]]"
set remainingText to texts startPos thru contentLength of theContent
set endPos to offset of "]]" in remainingText
if endPos is 0 then exit repeat
-- Extract the wikilink text
set linkText to texts 1 thru (endPos - 1) of remainingText
-- Add to wikilinks if not empty and not already found
if linkText is not "" and linkText is not in wikilinks then
set end of wikilinks to linkText
end if
-- Move past this wikilink
set currentPos to startPos + endPos + 1
end repeat
-- Process found wikilinks
repeat with linkText in wikilinks
-- Create or get wikilink page
set wikiPage to get record at ("/Heading Pages/" & linkText) in theDB
if wikiPage is missing value then
set wikiPage to create record with {name:linkText, type:markdown} in headingsGroup
set plain text of wikiPage to "# " & linkText & return & return & "## Documents referencing this heading" & return
end if
-- Add reference only if it doesn't exist
set docURL to reference URL of theRecord
set docLink to "- [" & (name of theRecord as string) & "](" & docURL & ")"
set pageContent to plain text of wikiPage
if pageContent does not contain docLink then
if last character of pageContent is not return then
set pageContent to pageContent & return
end if
set plain text of wikiPage to pageContent & docLink & return
end if
end repeat
-- Restore delimiters
set AppleScript's text item delimiters to savedDelimiters
end if
end repeat
-- After processing wikilinks, check all heading pages for orphaned references
repeat with theRecord in selectedRecords
if type of theRecord is in {markdown, txt, rtf, rtfd} then
-- Get content to check for wikilinks
set theContent to plain text of theRecord
set docURL to reference URL of theRecord
set docLink to "- [" & (name of theRecord as string) & "](" & docURL & ")"
-- Get all heading pages
set headingRecords to children of headingsGroup
-- Check each heading page
repeat with headingPage in headingRecords
set pageContent to plain text of headingPage
set headingName to name of headingPage
-- If page contains a reference to this document
if pageContent contains docLink then
-- Check if the document still contains this wikilink
set hasWikilink to false
set linkToFind to "[[" & headingName & "]]"
if theContent contains linkToFind then
set hasWikilink to true
end if
-- If wikilink is gone, remove the reference
if not hasWikilink then
-- Split content into lines
set AppleScript's text item delimiters to return
set contentLines to text items of pageContent
-- Remove the line containing the link
set newContent to {}
repeat with aLine in contentLines
if aLine does not contain docLink then
set end of newContent to aLine
end if
end repeat
-- Join lines back together
set newPageContent to ""
repeat with aLine in newContent
set newPageContent to newPageContent & aLine & return
end repeat
-- Update the heading page
set plain text of headingPage to newPageContent
end if
end if
end repeat
end if
end repeat
hide progress indicator
display alert "Complete" message "Finished processing selected documents."
on error error_message number error_number
-- Restore delimiters in case of error
set AppleScript's text item delimiters to savedDelimiters
hide progress indicator
if error_number is not -128 then
display alert "Error" message error_message
end if
end try
end tell
illustrates perfectly why AppleScript might not be the best tool for all tasks. Perhaps it’s just me, but this kind of string processing in the style of the 80’s BASIC dialects makes me cringe.
gets you all non-empty wikilinks in a single line. In another programming language, though. But aren’t computers and programming languages there to make our life easier?
Why do you use as string in the context of name of theRecord? What else would the name property be, if not a string?
Equally cringe-worthy. And proof that ChatGPT (or whatever wrote that code) has no idea of what the code means. It’s just stringing words together. Shudder.