Feld "Erstellt am" per Script füllen

:rofl:

So jetzt aber rekursiv:

function performsmartrule(records) {
const jetzt = new Date();
records.forEach(r => {
	r.date = jetzt;
	datumSetzen(r.children);
	})

function datumSetzen(records) {
const gruppen = records.whose({ _match: [ObjectSpecifier().type, "group"] })();
gruppen.forEach(g => {
	g.date = jetzt;
	datumSetzen(g.children);
	})
}

}

Oder, abgekürzt (und ungetestet):

function performsmartrule(records) {
const jetzt = new Date();
datumSetzen(records, jetzt);
}

function datumSetzen(records) {
const gruppen = records.whose({ _match: [ObjectSpecifier().type, "group"] })();
gruppen.forEach(g => {
	g.date = jetzt;
	datumSetzen(g.children, jetzt);
	})
}

Warum? Die Aufgabe war ursprünglich, nur das Datum von Gruppen zu ändern. Das macht Dein Code jetzt aber nicht mehr, denn performsmartrule setzt im forEach an allen records das date, ohne Rücksicht auf die Art des Datensatzes.

Die komplett rekursive Implementierung macht das wirklich nur für die Gruppen. Wenn du natürlich in der intelligenten Regel selbst nur Gruppen als records zulässt, würde es auch so funktionieren, wie du es hingeschrieben hast.

So habe ich das beabsichtigt.

In deiner Version wirft das Log leider bei:

const gruppen = records.whose ...

immer folgendes aus:

on performSmartRule (Error: TypeError: records.whose is not a function. (In 'records.whose({ _match: [ObjectSpecifier().type, "group"] })', 'records.whose' is undefined))

Das passiert allerdings immer, wenn man “records.whose…” im ersten Teil (function performsmartrule (records)) benutzt. Verstehe das Problem allerdings nicht…

Vermutlich könnte @cgrunenberg was dazu sagen. Ich bin davon ausgegangen, dass man whose auf alle Listen anwenden kann. Möglicherweise gilt das nicht für selectedRecords?

Nicht auf jede Liste, sondern nur auf sogenannte One-To-Many-Relationships. Bei Properties, die eine Liste zurück liefern wie selection funktioniert das zum Beispiel nicht, bei selected records, parents, children etc. schon.

Zumindest im Falle von AppleScript, keine Garantie für JXA :slight_smile:

Haha. No worries, tatsächlich geht es mit selectedRecords auch in JXA. Beispiel, das die Namen aller derjenigen ausgewählten Datensätze ausgibt, die vom Typ “Markdown” sind:

(() => {
  const app = Application("DEVONthink 3")
  app.includeStandardAdditions = true;
  const sel = app.selectedRecords.whose({ _match: [ObjectSpecifier().type, "markdown"] })();
  sel.forEach(g => console.log(g.name()))
})()

Allerdings geht es hier ja um performsmartrule und dessen Parameter records. Sollte mit dem whose funktionieren? Man kann ja nicht so recht sehen, ob das eine List-Property ist oder eine One-To-Many-Relation oder irgendwas anderes.

Und AppleScript

on performSmartRule(theRecords)
	tell application id "DNtp"
		set md to theRecords whose type is "markdown"
	end tell
end performSmartRule

wirft auch einen Fehler. Was entweder auf einen Fehler in meinem Code hinweist (wahrscheinlich) oder darauf, dass theRecords eben whose nicht versteht.

Edit: auch wenn ich in AppleScript whose auf a reference to theRecords loslasse,

set recs to a reference to theRecords
set md to recs whose type is "markdown"

bekomme ich einen Fehler. Aber einen anderen:

on performSmartRule („theRecords whose type = “markdown”“ kann nicht gelesen werden. Zugriff nicht erlaubt.)

Nachtrag: Offenbar ist selectedRecords ein JavaScript-Array (bzw. eine AppleScript-Liste?). Und das Array hat keine whose-Methode (wenig überraschend). Wie das mit der AppleScript-Liste (? wenn es eine ist) aussieht, weiß ich nicht.

Es sollte theoretisch so…

	set md to theRecords whose type is markdown

…oder so…

	set md to theRecords whose type as string is "markdown"

funktionieren. Allerdings kommt hier eine weitere Einschränkung zum Tragen, d.h. whose-Abfragen funktionieren meiner Erfahrung nach nur beim direkten Zugriff auf One-To-Relationships wie selected records, nicht bei zugewiesenen Variablen oder übergebenen Parametern.

1 Like

Ich denke, nicht, dass es das sollte, denn
class of theRecords in AppleScript liefert “list”
und (wenig überraschend)
typeof theRecords in JavaScript liefert “Array”

Weder eine AppleScript list noch ein JavaScript Array haben die Methode whose. Das scheint mir die simple Erklärung in diesem Fall zu sein.

Andererseits liefert
selected records whose type is "markdown" eine leere Liste als Ergebnis
während
selected records whose type is markdown korrekt eine Liste mit zwei Elementen liefert.

So steht es übrigens auch in der Dokumentation: Die Werte von type sind offenbar keine Strings, sondern Konstante (Enums? keine Ahnung, wie das in AppleScript heißt). In JavaScript sind es jedenfalls Strings.

Didn’t check but I think you need to remove the quotes.

1 Like

Yep, found that out in the meantime, too. JavaScript requires a string there

Deswegen schrieb ich theoretisch, gefolgt von einer Einschränkung :slight_smile:

Moin zusammen,
ich bräuchte da mal Eure Hilfe, bitte…

Folgende Smart Rule habe ich versucht, nur leider funktioniert es nicht…

Ziel der Aktion soll sein, dass alle PDF-Dokumente überprüft werden, ob das “Erstellt”-Datum in DT von den ersten 8Stellen im Dateinamen abweichend ist.
In erster Instanz hätte ich dann gerne im Protokollfenster eine Listausgabe der Einträge, welche abweichend sind.
Wie oben schon beschrieben habe ich eine Liste von PDF´s, die mit YYYYMMDD_ beginnen.
Vereinzelt sind aber auch PDF´s dabei, wo kein Datum vorne gelistet ist, sondern irgendwie mit andern Bezeichnungen starten. Das habe ich versucht mit der IF - Schleife rauszufiltern.
Es scheitert bei mir aber schon daran, dass ich keinerlei Ausgabe im Protokollfenster bekomme, obwohl definitiv Einträge vorhanden sind, wo der beginnende Dateiname mit z.B 20000101_ beginnt und “Erstellt” 20220422 ist.
Ich habe versucht mich auch mit den app.logMessages ran zu tasten um zu sehen, was im Namen steht und was das creationDate dazu liefert… Aber ich habe nur eine leere Liste…

Der aktuelle Code:

function performsmartrule(records) {
  let app = Application('DEVONthink 3');
  records.forEach((r) => {
    let name = r.name();
    let dateFull = name.match(/^(\d{4})(\d\d)(\d\d)/);
    if (dateFull !== null && dateFull.length === 3) {
      let creationDate = new Date(dateFull[1], dateFull[2] - 1, dateFull[3]);
      r.creationDate = creationDate;
      app.logMessage(name); 
      app.logmessage(creationDate);
    }
  });
}
(() => {
  let app = Application('DEVONthink 3');
  performsmartrule(app.selectedRecords());
})();

Die Methode heißt logMessage mit einem großen M

1 Like

Danke schön, habe es korrigiert, aber hat leider keine Veränderung gebracht…

Ich habe hier mal einen kleinen Ausschnitt meiner Testliste aus der SmartRule.

Wie man sieht gibt es einige abweichende Dateinamen…
Der Rest unten stimmt wieder.
ich befürchte, ich habe irgendwo einen Fehler im Auslesen des Datums aus dem Dateinamen…

ohne diesen Zusatz wird das Datum korrekt herausgelöst und das createdDate korrekt gesetzt; allerdings funktioniert app.logMessage nicht, ich erhalte Error -50: Parameter error.

1 Like

Denkfehler: dateFull.length muss === 4 sein
Denn: match liefert ein Array zurück, dessen erstes Element der gesamte Treffer ist. Es folgen die einzelnen capturing groups. Das sind bei Dir drei Stück (Jahr, Monat, Tag).

Noch ein paar warme Worte zum Code:

  • let sollte man nur dann benutzen, wenn sich die Werte ändern können. Das ist hier in keinem Fall so, deshalb solltest Du const verwenden (ja, auch innerhalb des forEach).
  • die if-Bedingung ist zu kompliziert. dateFull kann überhaupt nur dann !== null sein, wenn der reguläre Ausdruck passte. Die Prüfung auf length ist überflüssig, und ich würde (Geschmacksfrage!) if (dateFull) { … } schreiben.
  • es heißt wirklich logMessage, nicht mal logMessage, mal logmessage.
  • die anonyme selbst ausführende Funktion am Ende solltest Du in einem Smart-Rule-Script nicht haben (ich weiß, ich habe das vor Monaten hier mal als tolle Idee vorgestellt) – damit wird performsmartrule zweimal ausgeführt, was man nicht unbedingt will.
1 Like

:rofl: :rofl: :rofl:
Sehr geil formuliert…

vielen lieben Dank für die warmen Worte… Ich werde jetzt versuchen deine gut gemeinten Ratschläge umzusetzen…

Ich habe den Code versucht zu verbessern…

function performsmartrule(records) {
const app = Application(‘DEVONthink 3’);
records.forEach((r) => {
const name = r.name();
const dateFull = name.match(/^(\d{4})(\d\d)(\d\d)/);
if (dateFull !== null && dateFull.length === 4)
{
const creationDate = new Date(dateFull[1], dateFull[2] - 1, dateFull[3]);
r.creationDate = creationDate;
app.logMessage(name);
app.logMessage(creationDate);
}
});
}

Jetzt erhalte ich folgendes Protokollfenster:

Den Namen scheint er rauszuschreiben, aber das Creation Date… Ist das evt. der gemeldete Fehler?

Blöderweise hat er jetzt auch eine Datei rausgeschrieben, wo das Datum “Erstellt” mit dem Dateinamen aber gepasst hat gruebel

Du hast ja auch keinen Code und keine Regel die das verhindern würde. Falls du dich jetzt entscheidest r.creationDate und creationDate in einer wenn/dann zu vergleichen, bin ich mir unsicher ob das funktionieren wird; r.creationDate müsste die Uhrzeit beinhalten, während creationDate das nicht tut.

Wie schon weiter oben aufgeführt, app.logMessage nimmt die Variable creationDate nicht an; entschuldigt meine JS-Ignoranz, gibt es hier eine “as string” Funktion für Variablen?

Möglicherweise konvertiert logMessage ein Date-Object nicht automatisch in einen String. Du könntest creationDate.toString() benutzen.

Oder einfach nur einen Aufruf von logMessage mit einem Template-String benutzen.