Append text file to another text file including timestamp

Hey guys,

I’m looking for a functionality that enables me to take text notes to DevonThink.
These notes have a special hashtag in the text and need to be handled on that basis.
I can create a smart group of filter that react on the existance of that tag in the text.

So far so good.

But now I need to add the content of such a note to a bigger file. Additionally I need the creation-timestamp of that note before the content in the bigger file.

Think of it as a big personal log file. That has a content like:

2023-06-25 18:53:22 my first note …
2023-06-25 22:04:43 my seconde note …
2023-06-26 08:12:55 my third note …

and so on.

I think I need a combination of a smart rule and AppleScript for this.
But I don’t know where to start on the AppleScript part.

If someone can point my to a good example, it would be really helpful.

Thanks in advance,
Mario

In JavaScript, I’d do something like this:

const app = Application('DEVONthink 3');
const theBiggerFile = app.getRecordWithUuid('the UUID of the record you want to append to');
function performsmartrule(records) {
  const oldTxt = theBiggerFile.plainText()
  records.forEach(r => {
    const date = r.creationDate() /* Or whatever date you need here */
    oldTxt += date.toString() + ` ${r.plainText()}`;
  })
}

This will append the creation date and the text from the records selected by a smart rule to a predefined record. It uses the default JavaScript date format, i.e. something like Mon Jun 26 2023 12:52:15 GMT+0200 (Mitteleuropäische Sommerzeit) (depending on your locale). If you want something like the date/time string you mentioned in your post, you could use a regular expression to modify the date or use methods like getMonth to build it from the ground up.
oldTxt += ${date.toString().replace(/.*(\d+) (\d+) (d+) (\d\d:\d\d:\d\d)/,“$1-$2-$3 $4”)`
might do the trick.
Note I did not test any of the code.

Hi,

yes in general that reads like something I want to achieve.
I know it’s untested and I got it running, but now I get an error-message.
“Attemt to assign to readonly property”

I assume it is not possible to set a new text for the plainText.

Any ideas how to circumwent this ?

My bad. It should say theBiggerFile.plaintext = theBiggerFile.plainText() + '\n' + date.toString() + r.plainText();
Forget about the oldTxt lines.

The error is not about assigning to plainText, since I completely forgot doing that in the script. It’s about modifying oldTxt, which was declared to be constant.

Welcome @m4r10

It’s unclear what you’re actually asking for.

  • A note. What kind of note? There is no singular note type in DEVONthink.
  • with a special hashtag? What hashtag and what’s the function?
  • What bigger note?

Hi @BLUEFROG,

a note is in my case always a simple text-file, caputred by the create note functionality of DevonThink. All these text-files containing a hashtag #Log should be taken into account.
I’ve already filtered these via a smart rule that looks into the inbox. The hashtag is only there to identify the files.

Whenever I create such a text-file with hashtag #Log in it’s content, its content should be appended to a file named for example “personal_log.txt”. It’s always the same log-file.

Ideally the hashtag #Log gets removed when the text is appended to the personal_log.txt file.

Think of it as a really poor mans personal Twitter :slight_smile:

  • Have you considered using a Log tag instead of the hashtag?
  • Have you considered adding the timestamp in the note, not the personal_log?

A Log tag is theoretically also possible.
But it would involve a mouse klick. With the hashtag-approach it’s more or less just typing.

I need the timestamp formatted in a certain way and I’m not sure if this can be achieved in the note itself when I enter the content.

There are many ways to accomplish things in DEVONthink.

Are you creating a note via the Sorter?

I use a keyboard shortcut or click on the symbol in the menu bar.

What’s the keyboard shortcut to?

Just to save the click in the menu bar.
It’s the shortcut to create a note in the Sorter.

There is more than one possibility. Hold the Option key and choose Help > Report bug to start a support ticket.

I’m interested in seeing your smart rule
The AppleScript would be something like

Untested Script
on performSmartRule(theRecords)
	tell application id "DNtp"
		set theLog to get record with uuid "D05029A9-11F3-4163-94A6-29BF6E84F905"
		repeat with theRecord in theRecords
			set theDate to creation date of theRecord  
			set theContents to plain text of theRecord
			set plain text of theLog to plain text of theLog & return & theDate & " " & theContents
		end repeat
	end tell
end performSmartRule

Code can be added to format the date and strip the hashtag

I’ve got it running. If someone is interested in the script.
I’m gonna put it here:

on performSmartRule(theRecords)
	tell application id "DNtp"
		set logFile to get record with uuid "INSERT UUID OF LOG FILE"
		repeat with theRecord in theRecords
			set cnt to get plain text of theRecord
			
			#replace log hashtag			
			set AppleScript's text item delimiters to "#Log"
			set theTextItems to every text item of cnt
			set AppleScript's text item delimiters to ""
			set cnt to theTextItems as string
			
			set cdate to get creation date of theRecord
			
			# format date to DD.MM.YYYY HH:MI:SS
			set cdate_fmt to texts -1 thru -2 of ("0" & (day of cdate as integer))
			set cdate_fmt to cdate_fmt & "."
			set cdate_fmt to cdate_fmt & texts -1 thru -2 of ("0" & (month of cdate as integer))
			set cdate_fmt to cdate_fmt & "."
			set cdate_fmt to cdate_fmt & (year of cdate as integer) as string
			set cdate_fmt to cdate_fmt & " "
			set cdate_fmt to cdate_fmt & texts -1 thru -2 of ("0" & (hours of cdate as integer))
			set cdate_fmt to cdate_fmt & ":"
			set cdate_fmt to cdate_fmt & texts -1 thru -2 of ("0" & (minutes of cdate as integer))
			set cdate_fmt to cdate_fmt & ":"
			set cdate_fmt to cdate_fmt & texts -1 thru -2 of ("0" & (seconds of cdate as integer))
			
			set plain text of logFile to plain text of logFile & return & cdate_fmt & " " & cnt
		end repeat
	end tell
end performSmartRule

Just for completeness (and to show the differences), my JS version

const app = Application('DEVONthink 3');
const theBiggerFile = app.getRecordWithUuid('the UUID of the record you want to append to');
function performsmartrule(records) {
  records.forEach(r => {
    const fixedDate = r.creationDate().toString().replace(/.*(\d+) (\d+) (d+) (\d\d:\d\d:\d\d)/,“$1-$2-$3 $4”);
    theBiggerFile.plainText = theBiggerFile.plainText() 
    + '\n' 
    + fixedDate 
    + r.plainText().replaceAll('/#Log/g','');
  })
}

11 lines of code, 451 characters. AppleScript: 31 LOC, 1410 characters. All because AS is lacking so many simple functions.

Also: Is this year of cdate as integer as string really necessary? Either the year is an integer, then why cast it to an integer? Or it’s a string already, then the whole casting orgy is pointless…

1 Like

Glad you have something working :slight_smile:

Here’s an alternate approach to handling the date/time string. For your edification…

property fullYear : true

set {year:y, month:mo, day:d, hours:h, minutes:m, seconds:s} to (current date)

if not fullYear then set y to ((characters 3 thru 4) of (y as string) as string)
set theDate to my zeropad({d, mo as integer, y as integer}, ".") -- Organize this as desired
set theTime to my zeropad({h, m, s}, ":")

return theDate & theTime
--> "27.06.2023 09:46:24 "

on zeropad(dateComponents, delim)
	set dateTemp to {}
	repeat with dc in dateComponents
		if dc < 10 then set dc to ("0" & dc as string)
		if (dc as string) is (last item of dateComponents as string) then set delim to " "
		copy dc & delim as string to end of dateTemp
	end repeat
	return dateTemp as string
end zeropad

16 lines, 124 words, 695 characters :wink:

2 Likes

When less is more…

set dateObj to (current date)

set dateISO to dateObj as «class isot» as string -- MUST be 'string', not 'text'
set {TIDs, AppleScript's text item delimiters} to {AppleScript's text item delimiters, "T"}
set dateISO to text items of dateISO
set AppleScript's text item delimiters to space
set dateISO to dateISO as text
set AppleScript's text item delimiters to TIDs
1 Like

Usually I would definitely agree as long as the readability doesn’t suffer (one of the big advantages of AppleScript).

1 Like

Only for formatting the date and time :wink: I’d rather start out with an ISO-formatted date because that’s already zero-padded anyway.