Try this script to batch modify all your files. Back them up first! This script does back up files to a “bak” directory, but it’s hard to catch every possible potential problem during testing.
To run it, put this code in a file called “add-creation-date.pl” in your logseq pages directory. If you’re on Windows, install Strawberry Perl and open the script with Strawberry Perl. (If it gives you an error about the path not being a “pages” directory, tell me and I will modify the script to prompt you for the path.)
You can also tell me if it fails on more than a few of your files, and give some examples of the files: I’ll need to see the first and second block (at least including the 1st line of the 2nd block).
This script does not do what is hoped, do not try it. However I am leaving it up as an example of how to add any property to a bunch of pages using a script, while preserving their data:
#!/usr/bin/env perl
# Add created-at property to markdown files, for Logseq.
# The date is the file's creation time as milliseconds since the Unix epoch.
use strict;
use warnings;
use v5.28;
use Cwd;
use File::Find;
use List::Util qw(any tail);
sub add_creation_date;
sub add_creation_date_to_block;
sub add_creation_date_as_property;
sub add_on_line;
if (substr(getcwd, -6) !~ qr<[/\\]pages>) {
say STDERR "For safety, this script must be run in a 'pages' directory";
exit(-1);
}
find(sub {
if (substr($File::Find::dir, -4) !~ qr<[/\\]bak> && -f && /\.md$/) {
add_creation_date $_;
}
}, '.');
our @contents;
our $file;
our $line_ending;
our $ctime;
sub add_creation_date {
our $file = $_[0];
open(my $fh, '<', $file) or die "Cannot open file. $!";
our $ctime = (stat _)[10] * 1000;
our @contents = <$fh>;
close $fh;
if (scalar @contents) {
if (substr($contents[0], -2) eq "\r\n") {
$line_ending = "\r\n";
} else {
$line_ending = "\n";
}
if ($contents[0] =~ /^[\w-]+::/) {
add_creation_date_as_property;
} elsif (substr($contents[0], 0, 1) eq '-') {
add_creation_date_to_block;
} else {
# We don't understand the format:
say STDERR "First line is not a block nor a properties list, skipping $file";
return;
}
}
}
sub backup_file {
our $file;
our @contents;
my $backup_path = "bak/$file";
if (-e $backup_path) {
say STDERR "Skipping file because backup file already exists: $backup_path";
return 0;
}
say "Backing up and adding creation date: $file";
mkdir "bak";
#rename $file, $backup_path or die "Cannot rename file. $!";
open(my $fh, '>', $backup_path) or die "Cannot open backup file. $!";
print $fh @contents;
1;
}
sub add_creation_date_as_property {
our $file;
our @contents;
our $line_ending;
# skip the first line as it is the block start:
my $first_block_len = 1;
while (1) {
if ($first_block_len == scalar @contents || $contents[$first_block_len] =~ /^\s*(-|$)/) {
last;
} elsif ($contents[$first_block_len] =~ /^\s*created-at::/) {
say STDERR "First block already contains a creation date, skipping $file";
return;
}
$first_block_len += 1;
}
add_on_line $first_block_len, "", "";
}
sub add_creation_date_to_block {
our $file;
our @contents;
our $line_ending;
# skip the first line as it is the block start:
my $first_block_len = 1;
while (1) {
if ($first_block_len == scalar @contents || $contents[$first_block_len] =~ /^\s*-/) {
last;
} elsif ($contents[$first_block_len] =~ /^\s*created-at::/) {
say STDERR "First block already contains a creation date, skipping $file";
return;
}
$first_block_len += 1;
}
my @first_block = @contents[0..$first_block_len - 1];
if (any { m/^\s*[\w-]::/ } @first_block) {
# This block contains a tag, so we should add it to the existing block
add_on_line $first_block_len, " ", "";
} else {
# We can add it as a new property block on the first line, with a new blank line
add_on_line 0, "", $line_ending;
}
}
sub add_on_line {
my ($first_block_len, $prefix, $suffix_line) = @_;
our @contents;
our $file;
our $ctime;
if (!backup_file) {
return;
}
# Overwrite the file with the modified version:
open(my $fh, '>', "$file") or die "Cannot open file for writing. $!";
# Print the whole first block, not including children:
print $fh @contents[0..$first_block_len-1];
# Print an extra line with the creation date:
print $fh "${prefix}created-at:: $ctime$line_ending";
print $fh $suffix_line;
print $fh @contents[$first_block_len..(scalar @contents - 1)];
close $fh;
}