Digested-Tile 2024-09-18
Authors:: Unknown License:: Unspecified Digest Root:: 2a1ad4884aa7 #MarkdownTile
Digested-Tile
Authors:: Unknown License:: Unspecified Digest Root:: d7b0087ae05a #MarkdownTile
Digested-Tile
Authors:: Unknown License:: Unspecified Digest Root:: 1a947079cd7c #MarkdownTile
Digested-Tile
Authors:: Unknown License:: Unspecified Digest Root:: 62f36b314bb7
MarkdownTile
DeformattedTile
EOT
Digested-Tile 2024-09-13
Authors:: Unknown License:: Unspecified Digest Root:: 62f36b314bb7
MarkdownTile
<%* // Doc Seal 0.9 for Obsidian Templater // Version 0.9.7
/* * Preserve Specs for Tile and Blockchain formats * * Tile Spec:
- Structure
###### #Digested-Tile #ds/{deformat-digest}/{YYYY-MM-DD}\nAuthors:: {authors}\nLicense:: {license}\nDigest Root:: {digestRootHash}\n###### #MarkdownTile\n{tile}\n###### #DeformattedTile\n{deformatted-tile}\n###### #EOT\n---\n - Location:
x/ds/tiles/{deformat-digest}.md - Upsert Logic: Skip (with Notice message) if
#ds/{deformat-digest}/{YYYY-MM-DD}exists, append otherwise Blockchain Spec: - Structure:
### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained to #ds/block/${previousBlockchainEntryDigest} on ${YYYY-MM-DDTHH:mm}\n${digestTags.join(' ')}\n#ds/block/{currentBlockchainEntryDigest} - Location:
x/ds/blockchains/wwbc-{YY-MM}.md - Blockchain Logic: {previousBlockchainEntryDigest} is a hash of {YY-MM} for initial block or the BlockchainEntryDigest of the previous entry; if there are no “wwbc-…md” files yet, use the hash of the YY-MM, if there are not blocks in this months file yet, use the last block from the previous month, otherwise, use the last block in the current month’s file Script Spec:
- use Obsidian Templater scripting language for the script
- use tp.user.updateFrontMatter to update frontmatter
- 15s Notice messages about updates, 3 messages: status, tiles, and blockchain
- tp.user scripts: computeSHA256(content, length = 12); splitIntoTiles(content); ensureDirectoryExists(path); upsertToFile(filePath, header, content); updateFrontMatter(file, updates); getPreviousBlockchainEntryDigest(app, computeSHA256);
- inline helper functions: createDigestTag(hash, date); createDigestRootHash(digestTags);
*/
function createDigestTag(hash, date) {
return #ds/${hash}/${date};
}
function createDigestRootHash(digestTags) { return tp.user.computeSHA256(digestTags.join(’ ’), 12); }
// Main function
async function dsTaggerChain() {
const version = “0.9.7”;
const startTime = Date.now();
const currentDate = new Date().toISOString().split(‘T’)[0];
const currentTimestamp = new Date().toISOString();
console.log([${currentDate}] DS Tagger Chain v${version} started);
// Configuration
const tileDirectoryPath = "x/ds/tiles";
const blockchainDirectoryPath = "x/ds/blockchains";
try {
// Ensure directories exist
await tp.user.ensureDirectoryExists(tileDirectoryPath);
await tp.user.ensureDirectoryExists(blockchainDirectoryPath);
let content = tp.file.content;
const fileName = tp.file.title;
const currentFile = tp.file.find_tfile(fileName);
if (typeof content !== 'string') {
throw new Error('Received non-string content');
}
const authors = tp.frontmatter.authors || 'Unknown';
const license = tp.frontmatter.license || 'Unspecified';
console.log(`[${currentDate}] Authors extracted: ${authors}`);
console.log(`[${currentDate}] License extracted: ${license}`);
console.log(`[${currentDate}] File content length: ${content.length} characters`);
const { frontmatter, tiles } = tp.user.splitIntoTiles(content);
console.log(`[${currentDate}] Number of tiles: ${tiles.length}`);
let processedTiles = [];
let digestedTiles = 0;
let nonDigestedTiles = 0;
let updatedTiles = 0;
let digestTags = [];
let tileFilesUpdated = {};
for (let i = 0; i < tiles.length; i++) {
let tile = tiles[i];
const tileHash = tp.user.computeSHA256(tile);
console.log(`\n[${currentDate}] Processing tile ${i + 1} (${tileHash})`);
let existingDigestMatch = tile.match(/\s*(#ds\/[a-f0-9]+\/\d{4}-\d{2}-\d{2})/);
let existingDigest = existingDigestMatch ? existingDigestMatch[1] : null;
console.log(`Existing Digest Tag: ${existingDigest || 'None'}`);
let cleanTile = tile.replace(/\s*#ds\/[a-f0-9]+\/\d{4}-\d{2}-\d{2}/, '').trim();
let { deformattedContent, charactersRemoved } = tp.user.deformatTile(cleanTile);
let digest = tp.user.computeSHA256(deformattedContent);
let digestTag = createDigestTag(digest, currentDate);
console.log(`New Digest Tag: ${digestTag}`);
if (existingDigest && existingDigest.includes(digest)) {
console.log(`Content unchanged for tile ${tileHash}. Keeping existing Digest Tag.`);
digestTag = existingDigest;
nonDigestedTiles++;
// new Notice(`Skipping unchanged tile: ${digestTag}`, 15000);
} else {
console.log(`Content changed or new for tile ${tileHash}. Updating Digest Tag.`);
if (existingDigest) {
updatedTiles++;
} else {
digestedTiles++;
}
}
let processedTile = `${cleanTile} ${digestTag}`;
processedTiles.push(processedTile);
digestTags.push(digestTag);
console.log(`Tile ${tileHash} stats: Characters removed: ${charactersRemoved}`);
const tileFilePath = `${tileDirectoryPath}/${digest}.md`;
const digestRootHash = createDigestRootHash(digestTags);
const tileFileContent = `###### #Digested-Tile ${digestTag}
Authors:: {license} Digest Root:: ${digestRootHash}
MarkdownTile
${cleanTile}
DeformattedTile
${deformattedContent}
EOT
---; const { status: tileUpdateStatus, file: tileFile } = await tp.user.upsertToFile(tileFilePath, Digested-Tile ${digestTag}`, tileFileContent);
tileFilesUpdated[tileFilePath] = tileUpdateStatus;
// Update tile file frontmatter
if (tileFile) {
await tp.user.updateFrontMatter(tileFile, {
aliases: [digestTag],
authors: authors,
license: license,
'digest-root': digestRootHash
});
}
}
let result = frontmatter + '\n' + processedTiles.join('\n\n');
const yearMonth = currentDate.slice(2, 7);
let digestRootHash = createDigestRootHash(digestTags);
console.log(`\n[${currentDate}] Digest Root hash created: ${digestRootHash}`);
// Modify the current file content
await app.vault.modify(currentFile, result);
// Update current file frontmatter using tp.user.updateFrontMatter after modifying content
await tp.user.updateFrontMatter(currentFile, {
aliases: [`#ds/root/${digestRootHash}`],
'blockchain_last_digest_root': `#ds/root/${digestRootHash}`,
'blockchain_digest_timestamp': currentTimestamp,
'blockchain_file': `[[wwbc-${yearMonth}]]`
});
// Update blockchain file
const blockchainFilePath = `${blockchainDirectoryPath}/wwbc-${yearMonth}.md`;
const previousBlockchainEntryDigest = await tp.user.getPreviousBlockchainEntryDigest(app, blockchainDirectoryPath, tp.user.computeSHA256);
console.log(`Previous blockchain entry digest: ${previousBlockchainEntryDigest}`);
// Create the blockchain content without the final hash
const blockchainContentWithoutHash = `### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained to #ds/block/${previousBlockchainEntryDigest} on ${currentTimestamp}
${digestTags.join(’ ’)}`.trim();
// Generate the hash for the blockchain entry
const blockchainEntryHash = tp.user.computeSHA256(blockchainContentWithoutHash);
// Create the final blockchain content
const blockchainFileContent = `${blockchainContentWithoutHash}
block/${blockchainEntryHash}`;
const { status: blockchainUpdateStatus, file: blockchainFile } = await tp.user.upsertToFile(blockchainFilePath, `### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained to #ds/block/${previousBlockchainEntryDigest} on ${currentTimestamp}`, blockchainFileContent);
if (blockchainFile) {
await tp.user.updateFrontMatter(blockchainFile, {
cssclasses: [`locked`]
});
}
if (blockchainUpdateStatus === 'updated') {
console.log(`Updated blockchain file: ${blockchainFilePath}`);
} else {
console.log(`Blockchain file already up to date: ${blockchainFilePath}`);
}
const endTime = Date.now();
const runtime = ((endTime - startTime) / 1000).toFixed(2);
console.log(`\n[${currentDate}] DS Tagger Chain process completed successfully`);
const statusMessage = `DS Tagger Chain v${version} completed:
Runtime: {runtime}s #ds/root/{digestRootHash} Tiles processed: {digestedTiles} Tiles not digested: {updatedTiles} Date: ${currentDate}`;
const tileFilesMessage = `Tile files updated (BUGY):
{Object.entries(tileFilesUpdated).map(([file, status]) => `{file}: ${status}).join('\n')};
const blockchainEntryMessage = `Blockchain entry (${blockchainUpdateStatus}):
${blockchainFileContent}`;
console.log(statusMessage);
console.log(tileFilesMessage);
console.log(blockchainEntryMessage);
new Notice(statusMessage, 15000);
new Notice(tileFilesMessage, 15000);
new Notice(blockchainEntryMessage, 15000);
} catch (error) {
console.error(`[${currentDate}] An error occurred:`, error);
new Notice(`Error in DS Tagger Chain v${version}: ${error.message}. Check console for details.`, 15000);
}
}
// Run the script and output the result await dsTaggerChain(); %>
DeformattedTile
<%* // Doc Seal 0.9 for Obsidian Templater // Version 0.9.7 /* * Preserve Specs for Tile and Blockchain formats * * Tile Spec:
-
Structure
###### #Digested-Tile #ds/{deformat-digest}/{YYYY-MM-DD}\nAuthors:: {authors}\nLicense:: {license}\nDigest Root:: {digestRootHash}\n###### #MarkdownTile\n{tile}\n###### #DeformattedTile\n{deformatted-tile}\n###### #EOT\n---\n -
Location:
x/ds/tiles/{deformat-digest}.md -
Upsert Logic: Skip (with Notice message) if
#ds/{deformat-digest}/{YYYY-MM-DD}exists, append otherwise Blockchain Spec: -
Structure:
### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained to #ds/block/${previousBlockchainEntryDigest} on ${YYYY-MM-DDTHH:mm}\n${digestTags.join(' ')}\n#ds/block/{currentBlockchainEntryDigest} -
Location:
x/ds/blockchains/wwbc-{YY-MM}.md -
Blockchain Logic: {previousBlockchainEntryDigest} is a hash of {YY-MM} for initial block or the BlockchainEntryDigest of the previous entry; if there are no “wwbc-…md” files yet, use the hash of the YY-MM, if there are not blocks in this months file yet, use the last block from the previous month, otherwise, use the last block in the current month’s file Script Spec:
-
use Obsidian Templater scripting language for the script
-
use tp.user.updateFrontMatter to update frontmatter
-
15s Notice messages about updates, 3 messages: status, tiles, and blockchain
-
tp.user scripts: computeSHA256(content, length = 12); splitIntoTiles(content); ensureDirectoryExists(path); upsertToFile(filePath, header, content); updateFrontMatter(file, updates); getPreviousBlockchainEntryDigest(app, computeSHA256);
-
inline helper functions: createDigestTag(hash, date); createDigestRootHash(digestTags);
/ function createDigestTag(hash, date) { return#ds/${hash}/${date}; } function createDigestRootHash(digestTags) { return tp.user.computeSHA256(digestTags.join(’ ’), 12); } // Main function async function dsTaggerChain() { const version = “0.9.7”; const startTime = Date.now(); const currentDate = new Date().toISOString().split(‘T’)[0]; const currentTimestamp = new Date().toISOString(); console.log([${currentDate}] DS Tagger Chain v${version} started); // Configuration const tileDirectoryPath = “x/ds/tiles”; const blockchainDirectoryPath = “x/ds/blockchains”; try { // Ensure directories exist await tp.user.ensureDirectoryExists(tileDirectoryPath); await tp.user.ensureDirectoryExists(blockchainDirectoryPath); let content = tp.file.content; const fileName = tp.file.title; const currentFile = tp.file.find_tfile(fileName); if (typeof content !== ‘string’) { throw new Error(‘Received non-string content’); } const authors = tp.frontmatter.authors || ‘Unknown’; const license = tp.frontmatter.license || ‘Unspecified’; console.log([${currentDate}] Authors extracted: ${authors}); console.log([${currentDate}] License extracted: ${license}); console.log([${currentDate}] File content length: ${content.length} characters); const { frontmatter, tiles } = tp.user.splitIntoTiles(content); console.log([${currentDate}] Number of tiles: ${tiles.length}); let processedTiles = []; let digestedTiles = 0; let nonDigestedTiles = 0; let updatedTiles = 0; let digestTags = []; let tileFilesUpdated = {}; for (let i = 0; i < tiles.length; i++) { let tile = tiles[i]; const tileHash = tp.user.computeSHA256(tile); console.log(\n[${currentDate}] Processing tile ${i + 1} (${tileHash})); let existingDigestMatch = tile.match(/\s(#ds/[a-f0-9]+/\d{4}-\d{2}-\d{2})/); let existingDigest = existingDigestMatch ? existingDigestMatch[1] : null; console.log(Existing Digest Tag: ${existingDigest || 'None'}); let cleanTile = tile.replace(/\s*#ds/[a-f0-9]+/\d{4}-\d{2}-\d{2}/, ”).trim(); let { deformattedContent, charactersRemoved } = tp.user.deformatTile(cleanTile); let digest = tp.user.computeSHA256(deformattedContent); let digestTag = createDigestTag(digest, currentDate); console.log(New Digest Tag: ${digestTag}); if (existingDigest && existingDigest.includes(digest)) { console.log(Content unchanged for tile ${tileHash}. Keeping existing Digest Tag.); digestTag = existingDigest; nonDigestedTiles++; // new Notice(Skipping unchanged tile: ${digestTag}, 15000); } else { console.log(Content changed or new for tile ${tileHash}. Updating Digest Tag.); if (existingDigest) { updatedTiles++; } else { digestedTiles++; } } let processedTile =${cleanTile} ${digestTag}; processedTiles.push(processedTile); digestTags.push(digestTag); console.log(Tile ${tileHash} stats: Characters removed: ${charactersRemoved}); const tileFilePath =${tileDirectoryPath}/${digest}.md; const digestRootHash = createDigestRootHash(digestTags); const tileFileContent =###### #Digested-Tile ${digestTag} Authors:: ${authors} License:: ${license} Digest Root:: ${digestRootHash} #MarkdownTile ${cleanTile} #DeformattedTile ${deformattedContent} #EOT ---; const { status: tileUpdateStatus, file: tileFile } = await tp.user.upsertToFile(tileFilePath,###### #Digested-Tile ${digestTag}, tileFileContent); tileFilesUpdated[tileFilePath] = tileUpdateStatus; // Update tile file frontmatter if (tileFile) { await tp.user.updateFrontMatter(tileFile, { aliases: [digestTag], authors: authors, license: license, ‘digest-root’: digestRootHash }); } } let result = frontmatter + ‘\n’ + processedTiles.join(‘\n\n’); const yearMonth = currentDate.slice(2, 7); let digestRootHash = createDigestRootHash(digestTags); console.log(\n[${currentDate}] Digest Root hash created: ${digestRootHash}); // Modify the current file content await app.vault.modify(currentFile, result); // Update current file frontmatter using tp.user.updateFrontMatter after modifying content await tp.user.updateFrontMatter(currentFile, { aliases: [#ds/root/${digestRootHash}], ‘blockchain_last_digest_root’:#ds/root/${digestRootHash}, ‘blockchain_digest_timestamp’: currentTimestamp, ‘blockchain_file’:[[wwbc-${yearMonth}]]}); // Update blockchain file const blockchainFilePath =${blockchainDirectoryPath}/wwbc-${yearMonth}.md; const previousBlockchainEntryDigest = await tp.user.getPreviousBlockchainEntryDigest(app, blockchainDirectoryPath, tp.user.computeSHA256); console.log(Previous blockchain entry digest: ${previousBlockchainEntryDigest}); // Create the blockchain content without the final hash const blockchainContentWithoutHash =### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained to #ds/block/${previousBlockchainEntryDigest} on ${currentTimestamp} ${digestTags.join(' ')}.trim(); // Generate the hash for the blockchain entry const blockchainEntryHash = tp.user.computeSHA256(blockchainContentWithoutHash); // Create the final blockchain content const blockchainFileContent =${blockchainContentWithoutHash} #ds/block/${blockchainEntryHash}; const { status: blockchainUpdateStatus, file: blockchainFile } = await tp.user.upsertToFile(blockchainFilePath,### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained to #ds/block/${previousBlockchainEntryDigest} on ${currentTimestamp}, blockchainFileContent); if (blockchainFile) { await tp.user.updateFrontMatter(blockchainFile, { cssclasses: [locked] }); } if (blockchainUpdateStatus === ‘updated’) { console.log(Updated blockchain file: ${blockchainFilePath}); } else { console.log(Blockchain file already up to date: ${blockchainFilePath}); } const endTime = Date.now(); const runtime = ((endTime - startTime) / 1000).toFixed(2); console.log(\n[${currentDate}] DS Tagger Chain process completed successfully);const statusMessage = `DS Tagger Chain v${version} completed:
Runtime: {runtime}s
#ds/root/{digestRootHash}
Tiles processed: {digestedTiles}
Tiles not digested: {updatedTiles}
Date: {Object.entries(tileFilesUpdated).map(([file, status]) ⇒ ${file}: ${status}).join(‘\n’)}; const blockchainEntryMessage = Blockchain entry ({blockchainFileContent}; console.log(statusMessage); console.log(tileFilesMessage); console.log(blockchainEntryMessage); new Notice(statusMessage, 15000); new Notice(tileFilesMessage, 15000); new Notice(blockchainEntryMessage, 15000); } catch (error) { console.error([{version}: ${error.message}. Check console for details.`, 15000);
}
}
// Run the script and output the result
await dsTaggerChain();
%>
EOT
DeformattedTile #Digested-Tile Authors:: Unknown License:: Unspecified Digest Root:: 62f36b314bb7 #MarkdownTile #DeformattedTile #EOT
Digested-Tile 2024-09-13 Authors:: Unknown License:: Unspecified Digest Root:: 62f36b314bb7 #MarkdownTile <%* // Doc Seal 0.9 for Obsidian Templater // Version 0.9.7 /* * Preserve Specs for Tile and Blockchain formats * * Tile Spec:
-
Structure
###### #Digested-Tile #ds/{deformat-digest}/{YYYY-MM-DD}\nAuthors:: {authors}\nLicense:: {license}\nDigest Root:: {digestRootHash}\n###### #MarkdownTile\n{tile}\n###### #DeformattedTile\n{deformatted-tile}\n###### #EOT\n---\n -
Location:
x/ds/tiles/{deformat-digest}.md -
Upsert Logic: Skip (with Notice message) if
#ds/{deformat-digest}/{YYYY-MM-DD}exists, append otherwise Blockchain Spec: -
Structure:
### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained to #ds/block/${previousBlockchainEntryDigest} on ${YYYY-MM-DDTHH:mm}\n${digestTags.join(' ')}\n#ds/block/{currentBlockchainEntryDigest} -
Location:
x/ds/blockchains/wwbc-{YY-MM}.md -
Blockchain Logic: {previousBlockchainEntryDigest} is a hash of {YY-MM} for initial block or the BlockchainEntryDigest of the previous entry; if there are no “wwbc-…md” files yet, use the hash of the YY-MM, if there are not blocks in this months file yet, use the last block from the previous month, otherwise, use the last block in the current month’s file Script Spec:
-
use Obsidian Templater scripting language for the script
-
use tp.user.updateFrontMatter to update frontmatter
-
15s Notice messages about updates, 3 messages: status, tiles, and blockchain
-
tp.user scripts: computeSHA256(content, length = 12); splitIntoTiles(content); ensureDirectoryExists(path); upsertToFile(filePath, header, content); updateFrontMatter(file, updates); getPreviousBlockchainEntryDigest(app, computeSHA256);
-
inline helper functions: createDigestTag(hash, date); createDigestRootHash(digestTags);
/ function createDigestTag(hash, date) { return#ds/${hash}/${date}; } function createDigestRootHash(digestTags) { return tp.user.computeSHA256(digestTags.join(’ ’), 12); } // Main function async function dsTaggerChain() { const version = “0.9.7”; const startTime = Date.now(); const currentDate = new Date().toISOString().split(‘T’)[0]; const currentTimestamp = new Date().toISOString(); console.log([${currentDate}] DS Tagger Chain v${version} started); // Configuration const tileDirectoryPath = “x/ds/tiles”; const blockchainDirectoryPath = “x/ds/blockchains”; try { // Ensure directories exist await tp.user.ensureDirectoryExists(tileDirectoryPath); await tp.user.ensureDirectoryExists(blockchainDirectoryPath); let content = tp.file.content; const fileName = tp.file.title; const currentFile = tp.file.find_tfile(fileName); if (typeof content !== ‘string’) { throw new Error(‘Received non-string content’); } const authors = tp.frontmatter.authors || ‘Unknown’; const license = tp.frontmatter.license || ‘Unspecified’; console.log([${currentDate}] Authors extracted: ${authors}); console.log([${currentDate}] License extracted: ${license}); console.log([${currentDate}] File content length: ${content.length} characters); const { frontmatter, tiles } = tp.user.splitIntoTiles(content); console.log([${currentDate}] Number of tiles: ${tiles.length}); let processedTiles = []; let digestedTiles = 0; let nonDigestedTiles = 0; let updatedTiles = 0; let digestTags = []; let tileFilesUpdated = {}; for (let i = 0; i < tiles.length; i++) { let tile = tiles[i]; const tileHash = tp.user.computeSHA256(tile); console.log(\n[${currentDate}] Processing tile ${i + 1} (${tileHash})); let existingDigestMatch = tile.match(/\s(#ds/[a-f0-9]+/\d{4}-\d{2}-\d{2})/); let existingDigest = existingDigestMatch ? existingDigestMatch[1] : null; console.log(Existing Digest Tag: ${existingDigest || 'None'}); let cleanTile = tile.replace(/\s*#ds/[a-f0-9]+/\d{4}-\d{2}-\d{2}/, ”).trim(); let { deformattedContent, charactersRemoved } = tp.user.deformatTile(cleanTile); let digest = tp.user.computeSHA256(deformattedContent); let digestTag = createDigestTag(digest, currentDate); console.log(New Digest Tag: ${digestTag}); if (existingDigest && existingDigest.includes(digest)) { console.log(Content unchanged for tile ${tileHash}. Keeping existing Digest Tag.); digestTag = existingDigest; nonDigestedTiles++; // new Notice(Skipping unchanged tile: ${digestTag}, 15000); } else { console.log(Content changed or new for tile ${tileHash}. Updating Digest Tag.); if (existingDigest) { updatedTiles++; } else { digestedTiles++; } } let processedTile =${cleanTile} ${digestTag}; processedTiles.push(processedTile); digestTags.push(digestTag); console.log(Tile ${tileHash} stats: Characters removed: ${charactersRemoved}); const tileFilePath =${tileDirectoryPath}/${digest}.md; const digestRootHash = createDigestRootHash(digestTags); const tileFileContent =###### #Digested-Tile ${digestTag} Authors:: ${authors} License:: ${license} Digest Root:: ${digestRootHash} #MarkdownTile ${cleanTile} #DeformattedTile ${deformattedContent} #EOT ---; const { status: tileUpdateStatus, file: tileFile } = await tp.user.upsertToFile(tileFilePath,###### #Digested-Tile ${digestTag}, tileFileContent); tileFilesUpdated[tileFilePath] = tileUpdateStatus; // Update tile file frontmatter if (tileFile) { await tp.user.updateFrontMatter(tileFile, { aliases: [digestTag], authors: authors, license: license, ‘digest-root’: digestRootHash }); } } let result = frontmatter + ‘\n’ + processedTiles.join(‘\n\n’); const yearMonth = currentDate.slice(2, 7); let digestRootHash = createDigestRootHash(digestTags); console.log(\n[${currentDate}] Digest Root hash created: ${digestRootHash}); // Modify the current file content await app.vault.modify(currentFile, result); // Update current file frontmatter using tp.user.updateFrontMatter after modifying content await tp.user.updateFrontMatter(currentFile, { aliases: [#ds/root/${digestRootHash}], ‘blockchain_last_digest_root’:#ds/root/${digestRootHash}, ‘blockchain_digest_timestamp’: currentTimestamp, ‘blockchain_file’:[[wwbc-${yearMonth}]]}); // Update blockchain file const blockchainFilePath =${blockchainDirectoryPath}/wwbc-${yearMonth}.md; const previousBlockchainEntryDigest = await tp.user.getPreviousBlockchainEntryDigest(app, blockchainDirectoryPath, tp.user.computeSHA256); console.log(Previous blockchain entry digest: ${previousBlockchainEntryDigest}); // Create the blockchain content without the final hash const blockchainContentWithoutHash =### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained to #ds/block/${previousBlockchainEntryDigest} on ${currentTimestamp} ${digestTags.join(' ')}.trim(); // Generate the hash for the blockchain entry const blockchainEntryHash = tp.user.computeSHA256(blockchainContentWithoutHash); // Create the final blockchain content const blockchainFileContent =${blockchainContentWithoutHash} #ds/block/${blockchainEntryHash}; const { status: blockchainUpdateStatus, file: blockchainFile } = await tp.user.upsertToFile(blockchainFilePath,### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained to #ds/block/${previousBlockchainEntryDigest} on ${currentTimestamp}, blockchainFileContent); if (blockchainFile) { await tp.user.updateFrontMatter(blockchainFile, { cssclasses: [locked] }); } if (blockchainUpdateStatus === ‘updated’) { console.log(Updated blockchain file: ${blockchainFilePath}); } else { console.log(Blockchain file already up to date: ${blockchainFilePath}); } const endTime = Date.now(); const runtime = ((endTime - startTime) / 1000).toFixed(2); console.log(\n[${currentDate}] DS Tagger Chain process completed successfully);const statusMessage = `DS Tagger Chain v${version} completed:
Runtime: {runtime}s
#ds/root/{digestRootHash}
Tiles processed: {digestedTiles}
Tiles not digested: {updatedTiles}
Date: {Object.entries(tileFilesUpdated).map(([file, status]) ⇒ ${file}: ${status}).join(‘\n’)}; const blockchainEntryMessage = Blockchain entry ({blockchainFileContent}; console.log(statusMessage); console.log(tileFilesMessage); console.log(blockchainEntryMessage); new Notice(statusMessage, 15000); new Notice(tileFilesMessage, 15000); new Notice(blockchainEntryMessage, 15000); } catch (error) { console.error([{version}: ${error.message}. Check console for details.`, 15000);
}
}
// Run the script and output the result
await dsTaggerChain();
%>
#DeformattedTile
<%*
// Doc Seal 0.9 for Obsidian Templater
// Version 0.9.7
/* * Preserve Specs for Tile and Blockchain formats * *
Tile Spec:
-
Structure
###### #Digested-Tile #ds/{deformat-digest}/{YYYY-MM-DD}\nAuthors:: {authors}\nLicense:: {license}\nDigest Root:: {digestRootHash}\n###### #MarkdownTile\n{tile}\n###### #DeformattedTile\n{deformatted-tile}\n###### #EOT\n---\n -
Location:
x/ds/tiles/{deformat-digest}.md -
Upsert Logic: Skip (with Notice message) if
#ds/{deformat-digest}/{YYYY-MM-DD}exists, append otherwise Blockchain Spec: -
Structure:
### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained to #ds/block/${previousBlockchainEntryDigest} on ${YYYY-MM-DDTHH:mm}\n${digestTags.join(' ')}\n#ds/block/{currentBlockchainEntryDigest} -
Location:
x/ds/blockchains/wwbc-{YY-MM}.md -
Blockchain Logic: {previousBlockchainEntryDigest} is a hash of {YY-MM} for initial block or the BlockchainEntryDigest of the previous entry; if there are no “wwbc-…md” files yet, use the hash of the YY-MM, if there are not blocks in this months file yet, use the last block from the previous month, otherwise, use the last block in the current month’s file Script Spec:
-
use Obsidian Templater scripting language for the script
-
use tp.user.updateFrontMatter to update frontmatter
-
15s Notice messages about updates, 3 messages: status, tiles, and blockchain
-
tp.user scripts: computeSHA256(content, length = 12); splitIntoTiles(content); ensureDirectoryExists(path); upsertToFile(filePath, header, content); updateFrontMatter(file, updates); getPreviousBlockchainEntryDigest(app, computeSHA256);
-
inline helper functions: createDigestTag(hash, date); createDigestRootHash(digestTags);
/ function createDigestTag(hash, date) { return#ds/${hash}/${date}; } function createDigestRootHash(digestTags) { return tp.user.computeSHA256(digestTags.join(’ ’), 12); } // Main function async function dsTaggerChain() { const version = “0.9.7”; const startTime = Date.now(); const currentDate = new Date().toISOString().split(‘T’)[0]; const currentTimestamp = new Date().toISOString(); console.log([${currentDate}] DS Tagger Chain v${version} started); // Configuration const tileDirectoryPath = “x/ds/tiles”; const blockchainDirectoryPath = “x/ds/blockchains”; try { // Ensure directories exist await tp.user.ensureDirectoryExists(tileDirectoryPath); await tp.user.ensureDirectoryExists(blockchainDirectoryPath); let content = tp.file.content; const fileName = tp.file.title; const currentFile = tp.file.find_tfile(fileName); if (typeof content !== ‘string’) { throw new Error(‘Received non-string content’); } const authors = tp.frontmatter.authors || ‘Unknown’; const license = tp.frontmatter.license || ‘Unspecified’; console.log([${currentDate}] Authors extracted: ${authors}); console.log([${currentDate}] License extracted: ${license}); console.log([${currentDate}] File content length: ${content.length} characters); const { frontmatter, tiles } = tp.user.splitIntoTiles(content); console.log([${currentDate}] Number of tiles: ${tiles.length}); let processedTiles = []; let digestedTiles = 0; let nonDigestedTiles = 0; let updatedTiles = 0; let digestTags = []; let tileFilesUpdated = {}; for (let i = 0; i < tiles.length; i++) { let tile = tiles[i]; const tileHash = tp.user.computeSHA256(tile); console.log(\n[${currentDate}] Processing tile ${i + 1} (${tileHash})); let existingDigestMatch = tile.match(/\s(#ds/[a-f0-9]+/\d{4}-\d{2}-\d{2})/); let existingDigest = existingDigestMatch ? existingDigestMatch[1] : null; console.log(Existing Digest Tag: ${existingDigest || 'None'}); let cleanTile = tile.replace(/\s*#ds/[a-f0-9]+/\d{4}-\d{2}-\d{2}/, ”).trim(); let { deformattedContent, charactersRemoved } = tp.user.deformatTile(cleanTile); let digest = tp.user.computeSHA256(deformattedContent); let digestTag = createDigestTag(digest, currentDate); console.log(New Digest Tag: ${digestTag}); if (existingDigest && existingDigest.includes(digest)) { console.log(Content unchanged for tile ${tileHash}. Keeping existing Digest Tag.); digestTag = existingDigest; nonDigestedTiles++; // new Notice(Skipping unchanged tile: ${digestTag}, 15000); } else { console.log(Content changed or new for tile ${tileHash}. Updating Digest Tag.); if (existingDigest) { updatedTiles++; } else { digestedTiles++; } } let processedTile =${cleanTile} ${digestTag}; processedTiles.push(processedTile); digestTags.push(digestTag); console.log(Tile ${tileHash} stats: Characters removed: ${charactersRemoved}); const tileFilePath =${tileDirectoryPath}/${digest}.md; const digestRootHash = createDigestRootHash(digestTags); const tileFileContent =###### #Digested-Tile ${digestTag} Authors:: ${authors} License:: ${license} Digest Root:: ${digestRootHash} #MarkdownTile ${cleanTile} #DeformattedTile ${deformattedContent} #EOT ---; const { status: tileUpdateStatus, file: tileFile } = await tp.user.upsertToFile(tileFilePath,###### #Digested-Tile ${digestTag}, tileFileContent); tileFilesUpdated[tileFilePath] = tileUpdateStatus; // Update tile file frontmatter if (tileFile) { await tp.user.updateFrontMatter(tileFile, { aliases: [digestTag], authors: authors, license: license, ‘digest-root’: digestRootHash }); } } let result = frontmatter + ‘\n’ + processedTiles.join(‘\n\n’); const yearMonth = currentDate.slice(2, 7); let digestRootHash = createDigestRootHash(digestTags); console.log(\n[${currentDate}] Digest Root hash created: ${digestRootHash}); // Modify the current file content await app.vault.modify(currentFile, result); // Update current file frontmatter using tp.user.updateFrontMatter after modifying content await tp.user.updateFrontMatter(currentFile, { aliases: [#ds/root/${digestRootHash}], ‘blockchain_last_digest_root’:#ds/root/${digestRootHash}, ‘blockchain_digest_timestamp’: currentTimestamp, ‘blockchain_file’:[[wwbc-${yearMonth}]]}); // Update blockchain file const blockchainFilePath =${blockchainDirectoryPath}/wwbc-${yearMonth}.md; const previousBlockchainEntryDigest = await tp.user.getPreviousBlockchainEntryDigest(app, blockchainDirectoryPath, tp.user.computeSHA256); console.log(Previous blockchain entry digest: ${previousBlockchainEntryDigest}); // Create the blockchain content without the final hash const blockchainContentWithoutHash =### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained to #ds/block/${previousBlockchainEntryDigest} on ${currentTimestamp} ${digestTags.join(' ')}.trim(); // Generate the hash for the blockchain entry const blockchainEntryHash = tp.user.computeSHA256(blockchainContentWithoutHash); // Create the final blockchain content const blockchainFileContent =${blockchainContentWithoutHash} #ds/block/${blockchainEntryHash}; const { status: blockchainUpdateStatus, file: blockchainFile } = await tp.user.upsertToFile(blockchainFilePath,### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained to #ds/block/${previousBlockchainEntryDigest} on ${currentTimestamp}, blockchainFileContent); if (blockchainFile) { await tp.user.updateFrontMatter(blockchainFile, { cssclasses: [locked] }); } if (blockchainUpdateStatus === ‘updated’) { console.log(Updated blockchain file: ${blockchainFilePath}); } else { console.log(Blockchain file already up to date: ${blockchainFilePath}); } const endTime = Date.now(); const runtime = ((endTime - startTime) / 1000).toFixed(2); console.log(\n[${currentDate}] DS Tagger Chain process completed successfully);const statusMessage = `DS Tagger Chain v${version} completed:
Runtime: {runtime}s
#ds/root/{digestRootHash}
Tiles processed: {digestedTiles}
Tiles not digested: {updatedTiles}
Date: {Object.entries(tileFilesUpdated).map(([file, status]) ⇒ ${file}: ${status}).join(‘\n’)}; const blockchainEntryMessage = Blockchain entry ({blockchainFileContent}; console.log(statusMessage); console.log(tileFilesMessage); console.log(blockchainEntryMessage); new Notice(statusMessage, 15000); new Notice(tileFilesMessage, 15000); new Notice(blockchainEntryMessage, 15000); } catch (error) { console.error([{version}: ${error.message}. Check console for details.`, 15000);
}
}
// Run the script and output the result
await dsTaggerChain();
%>
#EOT
EOT
DeformattedTile #Digested-Tile Authors:: Unknown License:: Unspecified Digest Root:: 1a947079cd7c #MarkdownTile #Digested-Tile Authors:: Unknown License:: Unspecified Digest Root:: 62f36b314bb7 #MarkdownTile #DeformattedTile #EOT
Digested-Tile 2024-09-13 Authors:: Unknown License:: Unspecified Digest Root:: 62f36b314bb7 #MarkdownTile <%* // Doc Seal 0.9 for Obsidian Templater // Version 0.9.7 /* * Preserve Specs for Tile and Blockchain formats * * Tile Spec:
-
Structure
###### #Digested-Tile #ds/{deformat-digest}/{YYYY-MM-DD}\nAuthors:: {authors}\nLicense:: {license}\nDigest Root:: {digestRootHash}\n###### #MarkdownTile\n{tile}\n###### #DeformattedTile\n{deformatted-tile}\n###### #EOT\n---\n -
Location:
x/ds/tiles/{deformat-digest}.md -
Upsert Logic: Skip (with Notice message) if
#ds/{deformat-digest}/{YYYY-MM-DD}exists, append otherwise Blockchain Spec: -
Structure:
### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained to #ds/block/${previousBlockchainEntryDigest} on ${YYYY-MM-DDTHH:mm}\n${digestTags.join(' ')}\n#ds/block/{currentBlockchainEntryDigest} -
Location:
x/ds/blockchains/wwbc-{YY-MM}.md -
Blockchain Logic: {previousBlockchainEntryDigest} is a hash of {YY-MM} for initial block or the BlockchainEntryDigest of the previous entry; if there are no “wwbc-…md” files yet, use the hash of the YY-MM, if there are not blocks in this months file yet, use the last block from the previous month, otherwise, use the last block in the current month’s file Script Spec:
-
use Obsidian Templater scripting language for the script
-
use tp.user.updateFrontMatter to update frontmatter
-
15s Notice messages about updates, 3 messages: status, tiles, and blockchain
-
tp.user scripts: computeSHA256(content, length = 12); splitIntoTiles(content); ensureDirectoryExists(path); upsertToFile(filePath, header, content); updateFrontMatter(file, updates); getPreviousBlockchainEntryDigest(app, computeSHA256);
-
inline helper functions: createDigestTag(hash, date); createDigestRootHash(digestTags);
/ function createDigestTag(hash, date) { return#ds/${hash}/${date}; } function createDigestRootHash(digestTags) { return tp.user.computeSHA256(digestTags.join(’ ’), 12); } // Main function async function dsTaggerChain() { const version = “0.9.7”; const startTime = Date.now(); const currentDate = new Date().toISOString().split(‘T’)[0]; const currentTimestamp = new Date().toISOString(); console.log([${currentDate}] DS Tagger Chain v${version} started); // Configuration const tileDirectoryPath = “x/ds/tiles”; const blockchainDirectoryPath = “x/ds/blockchains”; try { // Ensure directories exist await tp.user.ensureDirectoryExists(tileDirectoryPath); await tp.user.ensureDirectoryExists(blockchainDirectoryPath); let content = tp.file.content; const fileName = tp.file.title; const currentFile = tp.file.find_tfile(fileName); if (typeof content !== ‘string’) { throw new Error(‘Received non-string content’); } const authors = tp.frontmatter.authors || ‘Unknown’; const license = tp.frontmatter.license || ‘Unspecified’; console.log([${currentDate}] Authors extracted: ${authors}); console.log([${currentDate}] License extracted: ${license}); console.log([${currentDate}] File content length: ${content.length} characters); const { frontmatter, tiles } = tp.user.splitIntoTiles(content); console.log([${currentDate}] Number of tiles: ${tiles.length}); let processedTiles = []; let digestedTiles = 0; let nonDigestedTiles = 0; let updatedTiles = 0; let digestTags = []; let tileFilesUpdated = {}; for (let i = 0; i < tiles.length; i++) { let tile = tiles[i]; const tileHash = tp.user.computeSHA256(tile); console.log(\n[${currentDate}] Processing tile ${i + 1} (${tileHash})); let existingDigestMatch = tile.match(/\s(#ds/[a-f0-9]+/\d{4}-\d{2}-\d{2})/); let existingDigest = existingDigestMatch ? existingDigestMatch[1] : null; console.log(Existing Digest Tag: ${existingDigest || 'None'}); let cleanTile = tile.replace(/\s*#ds/[a-f0-9]+/\d{4}-\d{2}-\d{2}/, ”).trim(); let { deformattedContent, charactersRemoved } = tp.user.deformatTile(cleanTile); let digest = tp.user.computeSHA256(deformattedContent); let digestTag = createDigestTag(digest, currentDate); console.log(New Digest Tag: ${digestTag}); if (existingDigest && existingDigest.includes(digest)) { console.log(Content unchanged for tile ${tileHash}. Keeping existing Digest Tag.); digestTag = existingDigest; nonDigestedTiles++; // new Notice(Skipping unchanged tile: ${digestTag}, 15000); } else { console.log(Content changed or new for tile ${tileHash}. Updating Digest Tag.); if (existingDigest) { updatedTiles++; } else { digestedTiles++; } } let processedTile =${cleanTile} ${digestTag}; processedTiles.push(processedTile); digestTags.push(digestTag); console.log(Tile ${tileHash} stats: Characters removed: ${charactersRemoved}); const tileFilePath =${tileDirectoryPath}/${digest}.md; const digestRootHash = createDigestRootHash(digestTags); const tileFileContent =###### #Digested-Tile ${digestTag} Authors:: ${authors} License:: ${license} Digest Root:: ${digestRootHash} #MarkdownTile ${cleanTile} #DeformattedTile ${deformattedContent} #EOT ---; const { status: tileUpdateStatus, file: tileFile } = await tp.user.upsertToFile(tileFilePath,###### #Digested-Tile ${digestTag}, tileFileContent); tileFilesUpdated[tileFilePath] = tileUpdateStatus; // Update tile file frontmatter if (tileFile) { await tp.user.updateFrontMatter(tileFile, { aliases: [digestTag], authors: authors, license: license, ‘digest-root’: digestRootHash }); } } let result = frontmatter + ‘\n’ + processedTiles.join(‘\n\n’); const yearMonth = currentDate.slice(2, 7); let digestRootHash = createDigestRootHash(digestTags); console.log(\n[${currentDate}] Digest Root hash created: ${digestRootHash}); // Modify the current file content await app.vault.modify(currentFile, result); // Update current file frontmatter using tp.user.updateFrontMatter after modifying content await tp.user.updateFrontMatter(currentFile, { aliases: [#ds/root/${digestRootHash}], ‘blockchain_last_digest_root’:#ds/root/${digestRootHash}, ‘blockchain_digest_timestamp’: currentTimestamp, ‘blockchain_file’:[[wwbc-${yearMonth}]]}); // Update blockchain file const blockchainFilePath =${blockchainDirectoryPath}/wwbc-${yearMonth}.md; const previousBlockchainEntryDigest = await tp.user.getPreviousBlockchainEntryDigest(app, blockchainDirectoryPath, tp.user.computeSHA256); console.log(Previous blockchain entry digest: ${previousBlockchainEntryDigest}); // Create the blockchain content without the final hash const blockchainContentWithoutHash =### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained to #ds/block/${previousBlockchainEntryDigest} on ${currentTimestamp} ${digestTags.join(' ')}.trim(); // Generate the hash for the blockchain entry const blockchainEntryHash = tp.user.computeSHA256(blockchainContentWithoutHash); // Create the final blockchain content const blockchainFileContent =${blockchainContentWithoutHash} #ds/block/${blockchainEntryHash}; const { status: blockchainUpdateStatus, file: blockchainFile } = await tp.user.upsertToFile(blockchainFilePath,### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained to #ds/block/${previousBlockchainEntryDigest} on ${currentTimestamp}, blockchainFileContent); if (blockchainFile) { await tp.user.updateFrontMatter(blockchainFile, { cssclasses: [locked] }); } if (blockchainUpdateStatus === ‘updated’) { console.log(Updated blockchain file: ${blockchainFilePath}); } else { console.log(Blockchain file already up to date: ${blockchainFilePath}); } const endTime = Date.now(); const runtime = ((endTime - startTime) / 1000).toFixed(2); console.log(\n[${currentDate}] DS Tagger Chain process completed successfully);const statusMessage = `DS Tagger Chain v${version} completed:
Runtime: {runtime}s
#ds/root/{digestRootHash}
Tiles processed: {digestedTiles}
Tiles not digested: {updatedTiles}
Date: {Object.entries(tileFilesUpdated).map(([file, status]) ⇒ ${file}: ${status}).join(‘\n’)}; const blockchainEntryMessage = Blockchain entry ({blockchainFileContent}; console.log(statusMessage); console.log(tileFilesMessage); console.log(blockchainEntryMessage); new Notice(statusMessage, 15000); new Notice(tileFilesMessage, 15000); new Notice(blockchainEntryMessage, 15000); } catch (error) { console.error([{version}: ${error.message}. Check console for details.`, 15000);
}
}
// Run the script and output the result
await dsTaggerChain();
%>
#DeformattedTile
<%*
// Doc Seal 0.9 for Obsidian Templater
// Version 0.9.7
/* * Preserve Specs for Tile and Blockchain formats * *
Tile Spec:
-
Structure
###### #Digested-Tile #ds/{deformat-digest}/{YYYY-MM-DD}\nAuthors:: {authors}\nLicense:: {license}\nDigest Root:: {digestRootHash}\n###### #MarkdownTile\n{tile}\n###### #DeformattedTile\n{deformatted-tile}\n###### #EOT\n---\n -
Location:
x/ds/tiles/{deformat-digest}.md -
Upsert Logic: Skip (with Notice message) if
#ds/{deformat-digest}/{YYYY-MM-DD}exists, append otherwise Blockchain Spec: -
Structure:
### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained to #ds/block/${previousBlockchainEntryDigest} on ${YYYY-MM-DDTHH:mm}\n${digestTags.join(' ')}\n#ds/block/{currentBlockchainEntryDigest} -
Location:
x/ds/blockchains/wwbc-{YY-MM}.md -
Blockchain Logic: {previousBlockchainEntryDigest} is a hash of {YY-MM} for initial block or the BlockchainEntryDigest of the previous entry; if there are no “wwbc-…md” files yet, use the hash of the YY-MM, if there are not blocks in this months file yet, use the last block from the previous month, otherwise, use the last block in the current month’s file Script Spec:
-
use Obsidian Templater scripting language for the script
-
use tp.user.updateFrontMatter to update frontmatter
-
15s Notice messages about updates, 3 messages: status, tiles, and blockchain
-
tp.user scripts: computeSHA256(content, length = 12); splitIntoTiles(content); ensureDirectoryExists(path); upsertToFile(filePath, header, content); updateFrontMatter(file, updates); getPreviousBlockchainEntryDigest(app, computeSHA256);
-
inline helper functions: createDigestTag(hash, date); createDigestRootHash(digestTags);
/ function createDigestTag(hash, date) { return#ds/${hash}/${date}; } function createDigestRootHash(digestTags) { return tp.user.computeSHA256(digestTags.join(’ ’), 12); } // Main function async function dsTaggerChain() { const version = “0.9.7”; const startTime = Date.now(); const currentDate = new Date().toISOString().split(‘T’)[0]; const currentTimestamp = new Date().toISOString(); console.log([${currentDate}] DS Tagger Chain v${version} started); // Configuration const tileDirectoryPath = “x/ds/tiles”; const blockchainDirectoryPath = “x/ds/blockchains”; try { // Ensure directories exist await tp.user.ensureDirectoryExists(tileDirectoryPath); await tp.user.ensureDirectoryExists(blockchainDirectoryPath); let content = tp.file.content; const fileName = tp.file.title; const currentFile = tp.file.find_tfile(fileName); if (typeof content !== ‘string’) { throw new Error(‘Received non-string content’); } const authors = tp.frontmatter.authors || ‘Unknown’; const license = tp.frontmatter.license || ‘Unspecified’; console.log([${currentDate}] Authors extracted: ${authors}); console.log([${currentDate}] License extracted: ${license}); console.log([${currentDate}] File content length: ${content.length} characters); const { frontmatter, tiles } = tp.user.splitIntoTiles(content); console.log([${currentDate}] Number of tiles: ${tiles.length}); let processedTiles = []; let digestedTiles = 0; let nonDigestedTiles = 0; let updatedTiles = 0; let digestTags = []; let tileFilesUpdated = {}; for (let i = 0; i < tiles.length; i++) { let tile = tiles[i]; const tileHash = tp.user.computeSHA256(tile); console.log(\n[${currentDate}] Processing tile ${i + 1} (${tileHash})); let existingDigestMatch = tile.match(/\s(#ds/[a-f0-9]+/\d{4}-\d{2}-\d{2})/); let existingDigest = existingDigestMatch ? existingDigestMatch[1] : null; console.log(Existing Digest Tag: ${existingDigest || 'None'}); let cleanTile = tile.replace(/\s*#ds/[a-f0-9]+/\d{4}-\d{2}-\d{2}/, ”).trim(); let { deformattedContent, charactersRemoved } = tp.user.deformatTile(cleanTile); let digest = tp.user.computeSHA256(deformattedContent); let digestTag = createDigestTag(digest, currentDate); console.log(New Digest Tag: ${digestTag}); if (existingDigest && existingDigest.includes(digest)) { console.log(Content unchanged for tile ${tileHash}. Keeping existing Digest Tag.); digestTag = existingDigest; nonDigestedTiles++; // new Notice(Skipping unchanged tile: ${digestTag}, 15000); } else { console.log(Content changed or new for tile ${tileHash}. Updating Digest Tag.); if (existingDigest) { updatedTiles++; } else { digestedTiles++; } } let processedTile =${cleanTile} ${digestTag}; processedTiles.push(processedTile); digestTags.push(digestTag); console.log(Tile ${tileHash} stats: Characters removed: ${charactersRemoved}); const tileFilePath =${tileDirectoryPath}/${digest}.md; const digestRootHash = createDigestRootHash(digestTags); const tileFileContent =###### #Digested-Tile ${digestTag} Authors:: ${authors} License:: ${license} Digest Root:: ${digestRootHash} #MarkdownTile ${cleanTile} #DeformattedTile ${deformattedContent} #EOT ---; const { status: tileUpdateStatus, file: tileFile } = await tp.user.upsertToFile(tileFilePath,###### #Digested-Tile ${digestTag}, tileFileContent); tileFilesUpdated[tileFilePath] = tileUpdateStatus; // Update tile file frontmatter if (tileFile) { await tp.user.updateFrontMatter(tileFile, { aliases: [digestTag], authors: authors, license: license, ‘digest-root’: digestRootHash }); } } let result = frontmatter + ‘\n’ + processedTiles.join(‘\n\n’); const yearMonth = currentDate.slice(2, 7); let digestRootHash = createDigestRootHash(digestTags); console.log(\n[${currentDate}] Digest Root hash created: ${digestRootHash}); // Modify the current file content await app.vault.modify(currentFile, result); // Update current file frontmatter using tp.user.updateFrontMatter after modifying content await tp.user.updateFrontMatter(currentFile, { aliases: [#ds/root/${digestRootHash}], ‘blockchain_last_digest_root’:#ds/root/${digestRootHash}, ‘blockchain_digest_timestamp’: currentTimestamp, ‘blockchain_file’:[[wwbc-${yearMonth}]]}); // Update blockchain file const blockchainFilePath =${blockchainDirectoryPath}/wwbc-${yearMonth}.md; const previousBlockchainEntryDigest = await tp.user.getPreviousBlockchainEntryDigest(app, blockchainDirectoryPath, tp.user.computeSHA256); console.log(Previous blockchain entry digest: ${previousBlockchainEntryDigest}); // Create the blockchain content without the final hash const blockchainContentWithoutHash =### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained to #ds/block/${previousBlockchainEntryDigest} on ${currentTimestamp} ${digestTags.join(' ')}.trim(); // Generate the hash for the blockchain entry const blockchainEntryHash = tp.user.computeSHA256(blockchainContentWithoutHash); // Create the final blockchain content const blockchainFileContent =${blockchainContentWithoutHash} #ds/block/${blockchainEntryHash}; const { status: blockchainUpdateStatus, file: blockchainFile } = await tp.user.upsertToFile(blockchainFilePath,### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained to #ds/block/${previousBlockchainEntryDigest} on ${currentTimestamp}, blockchainFileContent); if (blockchainFile) { await tp.user.updateFrontMatter(blockchainFile, { cssclasses: [locked] }); } if (blockchainUpdateStatus === ‘updated’) { console.log(Updated blockchain file: ${blockchainFilePath}); } else { console.log(Blockchain file already up to date: ${blockchainFilePath}); } const endTime = Date.now(); const runtime = ((endTime - startTime) / 1000).toFixed(2); console.log(\n[${currentDate}] DS Tagger Chain process completed successfully);const statusMessage = `DS Tagger Chain v${version} completed:
Runtime: {runtime}s
#ds/root/{digestRootHash}
Tiles processed: {digestedTiles}
Tiles not digested: {updatedTiles}
Date: {Object.entries(tileFilesUpdated).map(([file, status]) ⇒ ${file}: ${status}).join(‘\n’)}; const blockchainEntryMessage = Blockchain entry ({blockchainFileContent}; console.log(statusMessage); console.log(tileFilesMessage); console.log(blockchainEntryMessage); new Notice(statusMessage, 15000); new Notice(tileFilesMessage, 15000); new Notice(blockchainEntryMessage, 15000); } catch (error) { console.error([{version}: ${error.message}. Check console for details.`, 15000);
}
}
// Run the script and output the result
await dsTaggerChain();
%>
#EOT
DeformattedTile #Digested-Tile Authors:: Unknown License:: Unspecified Digest Root:: 62f36b314bb7 #MarkdownTile #DeformattedTile #EOT
Digested-Tile 2024-09-13 Authors:: Unknown License:: Unspecified Digest Root:: 62f36b314bb7 #MarkdownTile <%* // Doc Seal 0.9 for Obsidian Templater // Version 0.9.7 /* * Preserve Specs for Tile and Blockchain formats * * Tile Spec:
-
Structure
###### #Digested-Tile #ds/{deformat-digest}/{YYYY-MM-DD}\nAuthors:: {authors}\nLicense:: {license}\nDigest Root:: {digestRootHash}\n###### #MarkdownTile\n{tile}\n###### #DeformattedTile\n{deformatted-tile}\n###### #EOT\n---\n -
Location:
x/ds/tiles/{deformat-digest}.md -
Upsert Logic: Skip (with Notice message) if
#ds/{deformat-digest}/{YYYY-MM-DD}exists, append otherwise Blockchain Spec: -
Structure:
### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained to #ds/block/${previousBlockchainEntryDigest} on ${YYYY-MM-DDTHH:mm}\n${digestTags.join(' ')}\n#ds/block/{currentBlockchainEntryDigest} -
Location:
x/ds/blockchains/wwbc-{YY-MM}.md -
Blockchain Logic: {previousBlockchainEntryDigest} is a hash of {YY-MM} for initial block or the BlockchainEntryDigest of the previous entry; if there are no “wwbc-…md” files yet, use the hash of the YY-MM, if there are not blocks in this months file yet, use the last block from the previous month, otherwise, use the last block in the current month’s file Script Spec:
-
use Obsidian Templater scripting language for the script
-
use tp.user.updateFrontMatter to update frontmatter
-
15s Notice messages about updates, 3 messages: status, tiles, and blockchain
-
tp.user scripts: computeSHA256(content, length = 12); splitIntoTiles(content); ensureDirectoryExists(path); upsertToFile(filePath, header, content); updateFrontMatter(file, updates); getPreviousBlockchainEntryDigest(app, computeSHA256);
-
inline helper functions: createDigestTag(hash, date); createDigestRootHash(digestTags);
/ function createDigestTag(hash, date) { return#ds/${hash}/${date}; } function createDigestRootHash(digestTags) { return tp.user.computeSHA256(digestTags.join(’ ’), 12); } // Main function async function dsTaggerChain() { const version = “0.9.7”; const startTime = Date.now(); const currentDate = new Date().toISOString().split(‘T’)[0]; const currentTimestamp = new Date().toISOString(); console.log([${currentDate}] DS Tagger Chain v${version} started); // Configuration const tileDirectoryPath = “x/ds/tiles”; const blockchainDirectoryPath = “x/ds/blockchains”; try { // Ensure directories exist await tp.user.ensureDirectoryExists(tileDirectoryPath); await tp.user.ensureDirectoryExists(blockchainDirectoryPath); let content = tp.file.content; const fileName = tp.file.title; const currentFile = tp.file.find_tfile(fileName); if (typeof content !== ‘string’) { throw new Error(‘Received non-string content’); } const authors = tp.frontmatter.authors || ‘Unknown’; const license = tp.frontmatter.license || ‘Unspecified’; console.log([${currentDate}] Authors extracted: ${authors}); console.log([${currentDate}] License extracted: ${license}); console.log([${currentDate}] File content length: ${content.length} characters); const { frontmatter, tiles } = tp.user.splitIntoTiles(content); console.log([${currentDate}] Number of tiles: ${tiles.length}); let processedTiles = []; let digestedTiles = 0; let nonDigestedTiles = 0; let updatedTiles = 0; let digestTags = []; let tileFilesUpdated = {}; for (let i = 0; i < tiles.length; i++) { let tile = tiles[i]; const tileHash = tp.user.computeSHA256(tile); console.log(\n[${currentDate}] Processing tile ${i + 1} (${tileHash})); let existingDigestMatch = tile.match(/\s(#ds/[a-f0-9]+/\d{4}-\d{2}-\d{2})/); let existingDigest = existingDigestMatch ? existingDigestMatch[1] : null; console.log(Existing Digest Tag: ${existingDigest || 'None'}); let cleanTile = tile.replace(/\s*#ds/[a-f0-9]+/\d{4}-\d{2}-\d{2}/, ”).trim(); let { deformattedContent, charactersRemoved } = tp.user.deformatTile(cleanTile); let digest = tp.user.computeSHA256(deformattedContent); let digestTag = createDigestTag(digest, currentDate); console.log(New Digest Tag: ${digestTag}); if (existingDigest && existingDigest.includes(digest)) { console.log(Content unchanged for tile ${tileHash}. Keeping existing Digest Tag.); digestTag = existingDigest; nonDigestedTiles++; // new Notice(Skipping unchanged tile: ${digestTag}, 15000); } else { console.log(Content changed or new for tile ${tileHash}. Updating Digest Tag.); if (existingDigest) { updatedTiles++; } else { digestedTiles++; } } let processedTile =${cleanTile} ${digestTag}; processedTiles.push(processedTile); digestTags.push(digestTag); console.log(Tile ${tileHash} stats: Characters removed: ${charactersRemoved}); const tileFilePath =${tileDirectoryPath}/${digest}.md; const digestRootHash = createDigestRootHash(digestTags); const tileFileContent =###### #Digested-Tile ${digestTag} Authors:: ${authors} License:: ${license} Digest Root:: ${digestRootHash} #MarkdownTile ${cleanTile} #DeformattedTile ${deformattedContent} #EOT ---; const { status: tileUpdateStatus, file: tileFile } = await tp.user.upsertToFile(tileFilePath,###### #Digested-Tile ${digestTag}, tileFileContent); tileFilesUpdated[tileFilePath] = tileUpdateStatus; // Update tile file frontmatter if (tileFile) { await tp.user.updateFrontMatter(tileFile, { aliases: [digestTag], authors: authors, license: license, ‘digest-root’: digestRootHash }); } } let result = frontmatter + ‘\n’ + processedTiles.join(‘\n\n’); const yearMonth = currentDate.slice(2, 7); let digestRootHash = createDigestRootHash(digestTags); console.log(\n[${currentDate}] Digest Root hash created: ${digestRootHash}); // Modify the current file content await app.vault.modify(currentFile, result); // Update current file frontmatter using tp.user.updateFrontMatter after modifying content await tp.user.updateFrontMatter(currentFile, { aliases: [#ds/root/${digestRootHash}], ‘blockchain_last_digest_root’:#ds/root/${digestRootHash}, ‘blockchain_digest_timestamp’: currentTimestamp, ‘blockchain_file’:[[wwbc-${yearMonth}]]}); // Update blockchain file const blockchainFilePath =${blockchainDirectoryPath}/wwbc-${yearMonth}.md; const previousBlockchainEntryDigest = await tp.user.getPreviousBlockchainEntryDigest(app, blockchainDirectoryPath, tp.user.computeSHA256); console.log(Previous blockchain entry digest: ${previousBlockchainEntryDigest}); // Create the blockchain content without the final hash const blockchainContentWithoutHash =### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained to #ds/block/${previousBlockchainEntryDigest} on ${currentTimestamp} ${digestTags.join(' ')}.trim(); // Generate the hash for the blockchain entry const blockchainEntryHash = tp.user.computeSHA256(blockchainContentWithoutHash); // Create the final blockchain content const blockchainFileContent =${blockchainContentWithoutHash} #ds/block/${blockchainEntryHash}; const { status: blockchainUpdateStatus, file: blockchainFile } = await tp.user.upsertToFile(blockchainFilePath,### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained to #ds/block/${previousBlockchainEntryDigest} on ${currentTimestamp}, blockchainFileContent); if (blockchainFile) { await tp.user.updateFrontMatter(blockchainFile, { cssclasses: [locked] }); } if (blockchainUpdateStatus === ‘updated’) { console.log(Updated blockchain file: ${blockchainFilePath}); } else { console.log(Blockchain file already up to date: ${blockchainFilePath}); } const endTime = Date.now(); const runtime = ((endTime - startTime) / 1000).toFixed(2); console.log(\n[${currentDate}] DS Tagger Chain process completed successfully);const statusMessage = `DS Tagger Chain v${version} completed:
Runtime: {runtime}s
#ds/root/{digestRootHash}
Tiles processed: {digestedTiles}
Tiles not digested: {updatedTiles}
Date: {Object.entries(tileFilesUpdated).map(([file, status]) ⇒ ${file}: ${status}).join(‘\n’)}; const blockchainEntryMessage = Blockchain entry ({blockchainFileContent}; console.log(statusMessage); console.log(tileFilesMessage); console.log(blockchainEntryMessage); new Notice(statusMessage, 15000); new Notice(tileFilesMessage, 15000); new Notice(blockchainEntryMessage, 15000); } catch (error) { console.error([{version}: ${error.message}. Check console for details.`, 15000);
}
}
// Run the script and output the result
await dsTaggerChain();
%>
#DeformattedTile
<%*
// Doc Seal 0.9 for Obsidian Templater
// Version 0.9.7
/* * Preserve Specs for Tile and Blockchain formats * *
Tile Spec:
-
Structure
###### #Digested-Tile #ds/{deformat-digest}/{YYYY-MM-DD}\nAuthors:: {authors}\nLicense:: {license}\nDigest Root:: {digestRootHash}\n###### #MarkdownTile\n{tile}\n###### #DeformattedTile\n{deformatted-tile}\n###### #EOT\n---\n -
Location:
x/ds/tiles/{deformat-digest}.md -
Upsert Logic: Skip (with Notice message) if
#ds/{deformat-digest}/{YYYY-MM-DD}exists, append otherwise Blockchain Spec: -
Structure:
### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained to #ds/block/${previousBlockchainEntryDigest} on ${YYYY-MM-DDTHH:mm}\n${digestTags.join(' ')}\n#ds/block/{currentBlockchainEntryDigest} -
Location:
x/ds/blockchains/wwbc-{YY-MM}.md -
Blockchain Logic: {previousBlockchainEntryDigest} is a hash of {YY-MM} for initial block or the BlockchainEntryDigest of the previous entry; if there are no “wwbc-…md” files yet, use the hash of the YY-MM, if there are not blocks in this months file yet, use the last block from the previous month, otherwise, use the last block in the current month’s file Script Spec:
-
use Obsidian Templater scripting language for the script
-
use tp.user.updateFrontMatter to update frontmatter
-
15s Notice messages about updates, 3 messages: status, tiles, and blockchain
-
tp.user scripts: computeSHA256(content, length = 12); splitIntoTiles(content); ensureDirectoryExists(path); upsertToFile(filePath, header, content); updateFrontMatter(file, updates); getPreviousBlockchainEntryDigest(app, computeSHA256);
-
inline helper functions: createDigestTag(hash, date); createDigestRootHash(digestTags);
/ function createDigestTag(hash, date) { return#ds/${hash}/${date}; } function createDigestRootHash(digestTags) { return tp.user.computeSHA256(digestTags.join(’ ’), 12); } // Main function async function dsTaggerChain() { const version = “0.9.7”; const startTime = Date.now(); const currentDate = new Date().toISOString().split(‘T’)[0]; const currentTimestamp = new Date().toISOString(); console.log([${currentDate}] DS Tagger Chain v${version} started); // Configuration const tileDirectoryPath = “x/ds/tiles”; const blockchainDirectoryPath = “x/ds/blockchains”; try { // Ensure directories exist await tp.user.ensureDirectoryExists(tileDirectoryPath); await tp.user.ensureDirectoryExists(blockchainDirectoryPath); let content = tp.file.content; const fileName = tp.file.title; const currentFile = tp.file.find_tfile(fileName); if (typeof content !== ‘string’) { throw new Error(‘Received non-string content’); } const authors = tp.frontmatter.authors || ‘Unknown’; const license = tp.frontmatter.license || ‘Unspecified’; console.log([${currentDate}] Authors extracted: ${authors}); console.log([${currentDate}] License extracted: ${license}); console.log([${currentDate}] File content length: ${content.length} characters); const { frontmatter, tiles } = tp.user.splitIntoTiles(content); console.log([${currentDate}] Number of tiles: ${tiles.length}); let processedTiles = []; let digestedTiles = 0; let nonDigestedTiles = 0; let updatedTiles = 0; let digestTags = []; let tileFilesUpdated = {}; for (let i = 0; i < tiles.length; i++) { let tile = tiles[i]; const tileHash = tp.user.computeSHA256(tile); console.log(\n[${currentDate}] Processing tile ${i + 1} (${tileHash})); let existingDigestMatch = tile.match(/\s(#ds/[a-f0-9]+/\d{4}-\d{2}-\d{2})/); let existingDigest = existingDigestMatch ? existingDigestMatch[1] : null; console.log(Existing Digest Tag: ${existingDigest || 'None'}); let cleanTile = tile.replace(/\s*#ds/[a-f0-9]+/\d{4}-\d{2}-\d{2}/, ”).trim(); let { deformattedContent, charactersRemoved } = tp.user.deformatTile(cleanTile); let digest = tp.user.computeSHA256(deformattedContent); let digestTag = createDigestTag(digest, currentDate); console.log(New Digest Tag: ${digestTag}); if (existingDigest && existingDigest.includes(digest)) { console.log(Content unchanged for tile ${tileHash}. Keeping existing Digest Tag.); digestTag = existingDigest; nonDigestedTiles++; // new Notice(Skipping unchanged tile: ${digestTag}, 15000); } else { console.log(Content changed or new for tile ${tileHash}. Updating Digest Tag.); if (existingDigest) { updatedTiles++; } else { digestedTiles++; } } let processedTile =${cleanTile} ${digestTag}; processedTiles.push(processedTile); digestTags.push(digestTag); console.log(Tile ${tileHash} stats: Characters removed: ${charactersRemoved}); const tileFilePath =${tileDirectoryPath}/${digest}.md; const digestRootHash = createDigestRootHash(digestTags); const tileFileContent =###### #Digested-Tile ${digestTag} Authors:: ${authors} License:: ${license} Digest Root:: ${digestRootHash} #MarkdownTile ${cleanTile} #DeformattedTile ${deformattedContent} #EOT ---; const { status: tileUpdateStatus, file: tileFile } = await tp.user.upsertToFile(tileFilePath,###### #Digested-Tile ${digestTag}, tileFileContent); tileFilesUpdated[tileFilePath] = tileUpdateStatus; // Update tile file frontmatter if (tileFile) { await tp.user.updateFrontMatter(tileFile, { aliases: [digestTag], authors: authors, license: license, ‘digest-root’: digestRootHash }); } } let result = frontmatter + ‘\n’ + processedTiles.join(‘\n\n’); const yearMonth = currentDate.slice(2, 7); let digestRootHash = createDigestRootHash(digestTags); console.log(\n[${currentDate}] Digest Root hash created: ${digestRootHash}); // Modify the current file content await app.vault.modify(currentFile, result); // Update current file frontmatter using tp.user.updateFrontMatter after modifying content await tp.user.updateFrontMatter(currentFile, { aliases: [#ds/root/${digestRootHash}], ‘blockchain_last_digest_root’:#ds/root/${digestRootHash}, ‘blockchain_digest_timestamp’: currentTimestamp, ‘blockchain_file’:[[wwbc-${yearMonth}]]}); // Update blockchain file const blockchainFilePath =${blockchainDirectoryPath}/wwbc-${yearMonth}.md; const previousBlockchainEntryDigest = await tp.user.getPreviousBlockchainEntryDigest(app, blockchainDirectoryPath, tp.user.computeSHA256); console.log(Previous blockchain entry digest: ${previousBlockchainEntryDigest}); // Create the blockchain content without the final hash const blockchainContentWithoutHash =### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained to #ds/block/${previousBlockchainEntryDigest} on ${currentTimestamp} ${digestTags.join(' ')}.trim(); // Generate the hash for the blockchain entry const blockchainEntryHash = tp.user.computeSHA256(blockchainContentWithoutHash); // Create the final blockchain content const blockchainFileContent =${blockchainContentWithoutHash} #ds/block/${blockchainEntryHash}; const { status: blockchainUpdateStatus, file: blockchainFile } = await tp.user.upsertToFile(blockchainFilePath,### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained to #ds/block/${previousBlockchainEntryDigest} on ${currentTimestamp}, blockchainFileContent); if (blockchainFile) { await tp.user.updateFrontMatter(blockchainFile, { cssclasses: [locked] }); } if (blockchainUpdateStatus === ‘updated’) { console.log(Updated blockchain file: ${blockchainFilePath}); } else { console.log(Blockchain file already up to date: ${blockchainFilePath}); } const endTime = Date.now(); const runtime = ((endTime - startTime) / 1000).toFixed(2); console.log(\n[${currentDate}] DS Tagger Chain process completed successfully);const statusMessage = `DS Tagger Chain v${version} completed:
Runtime: {runtime}s
#ds/root/{digestRootHash}
Tiles processed: {digestedTiles}
Tiles not digested: {updatedTiles}
Date: {Object.entries(tileFilesUpdated).map(([file, status]) ⇒ ${file}: ${status}).join(‘\n’)}; const blockchainEntryMessage = Blockchain entry ({blockchainFileContent}; console.log(statusMessage); console.log(tileFilesMessage); console.log(blockchainEntryMessage); new Notice(statusMessage, 15000); new Notice(tileFilesMessage, 15000); new Notice(blockchainEntryMessage, 15000); } catch (error) { console.error([{version}: ${error.message}. Check console for details.`, 15000);
}
}
// Run the script and output the result
await dsTaggerChain();
%>
#EOT
EOT
EOT
DeformattedTile #Digested-Tile Authors:: Unknown License:: Unspecified Digest Root:: d7b0087ae05a #MarkdownTile #Digested-Tile Authors:: Unknown License:: Unspecified Digest Root:: 1a947079cd7c #MarkdownTile #Digested-Tile Authors:: Unknown License:: Unspecified Digest Root:: 62f36b314bb7 #MarkdownTile #DeformattedTile #EOT
Digested-Tile 2024-09-13 Authors:: Unknown License:: Unspecified Digest Root:: 62f36b314bb7 #MarkdownTile <%* // Doc Seal 0.9 for Obsidian Templater // Version 0.9.7 /* * Preserve Specs for Tile and Blockchain formats * * Tile Spec:
-
Structure
###### #Digested-Tile #ds/{deformat-digest}/{YYYY-MM-DD}\nAuthors:: {authors}\nLicense:: {license}\nDigest Root:: {digestRootHash}\n###### #MarkdownTile\n{tile}\n###### #DeformattedTile\n{deformatted-tile}\n###### #EOT\n---\n -
Location:
x/ds/tiles/{deformat-digest}.md -
Upsert Logic: Skip (with Notice message) if
#ds/{deformat-digest}/{YYYY-MM-DD}exists, append otherwise Blockchain Spec: -
Structure:
### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained to #ds/block/${previousBlockchainEntryDigest} on ${YYYY-MM-DDTHH:mm}\n${digestTags.join(' ')}\n#ds/block/{currentBlockchainEntryDigest} -
Location:
x/ds/blockchains/wwbc-{YY-MM}.md -
Blockchain Logic: {previousBlockchainEntryDigest} is a hash of {YY-MM} for initial block or the BlockchainEntryDigest of the previous entry; if there are no “wwbc-…md” files yet, use the hash of the YY-MM, if there are not blocks in this months file yet, use the last block from the previous month, otherwise, use the last block in the current month’s file Script Spec:
-
use Obsidian Templater scripting language for the script
-
use tp.user.updateFrontMatter to update frontmatter
-
15s Notice messages about updates, 3 messages: status, tiles, and blockchain
-
tp.user scripts: computeSHA256(content, length = 12); splitIntoTiles(content); ensureDirectoryExists(path); upsertToFile(filePath, header, content); updateFrontMatter(file, updates); getPreviousBlockchainEntryDigest(app, computeSHA256);
-
inline helper functions: createDigestTag(hash, date); createDigestRootHash(digestTags);
/ function createDigestTag(hash, date) { return#ds/${hash}/${date}; } function createDigestRootHash(digestTags) { return tp.user.computeSHA256(digestTags.join(’ ’), 12); } // Main function async function dsTaggerChain() { const version = “0.9.7”; const startTime = Date.now(); const currentDate = new Date().toISOString().split(‘T’)[0]; const currentTimestamp = new Date().toISOString(); console.log([${currentDate}] DS Tagger Chain v${version} started); // Configuration const tileDirectoryPath = “x/ds/tiles”; const blockchainDirectoryPath = “x/ds/blockchains”; try { // Ensure directories exist await tp.user.ensureDirectoryExists(tileDirectoryPath); await tp.user.ensureDirectoryExists(blockchainDirectoryPath); let content = tp.file.content; const fileName = tp.file.title; const currentFile = tp.file.find_tfile(fileName); if (typeof content !== ‘string’) { throw new Error(‘Received non-string content’); } const authors = tp.frontmatter.authors || ‘Unknown’; const license = tp.frontmatter.license || ‘Unspecified’; console.log([${currentDate}] Authors extracted: ${authors}); console.log([${currentDate}] License extracted: ${license}); console.log([${currentDate}] File content length: ${content.length} characters); const { frontmatter, tiles } = tp.user.splitIntoTiles(content); console.log([${currentDate}] Number of tiles: ${tiles.length}); let processedTiles = []; let digestedTiles = 0; let nonDigestedTiles = 0; let updatedTiles = 0; let digestTags = []; let tileFilesUpdated = {}; for (let i = 0; i < tiles.length; i++) { let tile = tiles[i]; const tileHash = tp.user.computeSHA256(tile); console.log(\n[${currentDate}] Processing tile ${i + 1} (${tileHash})); let existingDigestMatch = tile.match(/\s(#ds/[a-f0-9]+/\d{4}-\d{2}-\d{2})/); let existingDigest = existingDigestMatch ? existingDigestMatch[1] : null; console.log(Existing Digest Tag: ${existingDigest || 'None'}); let cleanTile = tile.replace(/\s*#ds/[a-f0-9]+/\d{4}-\d{2}-\d{2}/, ”).trim(); let { deformattedContent, charactersRemoved } = tp.user.deformatTile(cleanTile); let digest = tp.user.computeSHA256(deformattedContent); let digestTag = createDigestTag(digest, currentDate); console.log(New Digest Tag: ${digestTag}); if (existingDigest && existingDigest.includes(digest)) { console.log(Content unchanged for tile ${tileHash}. Keeping existing Digest Tag.); digestTag = existingDigest; nonDigestedTiles++; // new Notice(Skipping unchanged tile: ${digestTag}, 15000); } else { console.log(Content changed or new for tile ${tileHash}. Updating Digest Tag.); if (existingDigest) { updatedTiles++; } else { digestedTiles++; } } let processedTile =${cleanTile} ${digestTag}; processedTiles.push(processedTile); digestTags.push(digestTag); console.log(Tile ${tileHash} stats: Characters removed: ${charactersRemoved}); const tileFilePath =${tileDirectoryPath}/${digest}.md; const digestRootHash = createDigestRootHash(digestTags); const tileFileContent =###### #Digested-Tile ${digestTag} Authors:: ${authors} License:: ${license} Digest Root:: ${digestRootHash} #MarkdownTile ${cleanTile} #DeformattedTile ${deformattedContent} #EOT ---; const { status: tileUpdateStatus, file: tileFile } = await tp.user.upsertToFile(tileFilePath,###### #Digested-Tile ${digestTag}, tileFileContent); tileFilesUpdated[tileFilePath] = tileUpdateStatus; // Update tile file frontmatter if (tileFile) { await tp.user.updateFrontMatter(tileFile, { aliases: [digestTag], authors: authors, license: license, ‘digest-root’: digestRootHash }); } } let result = frontmatter + ‘\n’ + processedTiles.join(‘\n\n’); const yearMonth = currentDate.slice(2, 7); let digestRootHash = createDigestRootHash(digestTags); console.log(\n[${currentDate}] Digest Root hash created: ${digestRootHash}); // Modify the current file content await app.vault.modify(currentFile, result); // Update current file frontmatter using tp.user.updateFrontMatter after modifying content await tp.user.updateFrontMatter(currentFile, { aliases: [#ds/root/${digestRootHash}], ‘blockchain_last_digest_root’:#ds/root/${digestRootHash}, ‘blockchain_digest_timestamp’: currentTimestamp, ‘blockchain_file’:[[wwbc-${yearMonth}]]}); // Update blockchain file const blockchainFilePath =${blockchainDirectoryPath}/wwbc-${yearMonth}.md; const previousBlockchainEntryDigest = await tp.user.getPreviousBlockchainEntryDigest(app, blockchainDirectoryPath, tp.user.computeSHA256); console.log(Previous blockchain entry digest: ${previousBlockchainEntryDigest}); // Create the blockchain content without the final hash const blockchainContentWithoutHash =### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained to #ds/block/${previousBlockchainEntryDigest} on ${currentTimestamp} ${digestTags.join(' ')}.trim(); // Generate the hash for the blockchain entry const blockchainEntryHash = tp.user.computeSHA256(blockchainContentWithoutHash); // Create the final blockchain content const blockchainFileContent =${blockchainContentWithoutHash} #ds/block/${blockchainEntryHash}; const { status: blockchainUpdateStatus, file: blockchainFile } = await tp.user.upsertToFile(blockchainFilePath,### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained to #ds/block/${previousBlockchainEntryDigest} on ${currentTimestamp}, blockchainFileContent); if (blockchainFile) { await tp.user.updateFrontMatter(blockchainFile, { cssclasses: [locked] }); } if (blockchainUpdateStatus === ‘updated’) { console.log(Updated blockchain file: ${blockchainFilePath}); } else { console.log(Blockchain file already up to date: ${blockchainFilePath}); } const endTime = Date.now(); const runtime = ((endTime - startTime) / 1000).toFixed(2); console.log(\n[${currentDate}] DS Tagger Chain process completed successfully);const statusMessage = `DS Tagger Chain v${version} completed:
Runtime: {runtime}s
#ds/root/{digestRootHash}
Tiles processed: {digestedTiles}
Tiles not digested: {updatedTiles}
Date: {Object.entries(tileFilesUpdated).map(([file, status]) ⇒ ${file}: ${status}).join(‘\n’)}; const blockchainEntryMessage = Blockchain entry ({blockchainFileContent}; console.log(statusMessage); console.log(tileFilesMessage); console.log(blockchainEntryMessage); new Notice(statusMessage, 15000); new Notice(tileFilesMessage, 15000); new Notice(blockchainEntryMessage, 15000); } catch (error) { console.error([{version}: ${error.message}. Check console for details.`, 15000);
}
}
// Run the script and output the result
await dsTaggerChain();
%>
#DeformattedTile
<%*
// Doc Seal 0.9 for Obsidian Templater
// Version 0.9.7
/* * Preserve Specs for Tile and Blockchain formats * *
Tile Spec:
-
Structure
###### #Digested-Tile #ds/{deformat-digest}/{YYYY-MM-DD}\nAuthors:: {authors}\nLicense:: {license}\nDigest Root:: {digestRootHash}\n###### #MarkdownTile\n{tile}\n###### #DeformattedTile\n{deformatted-tile}\n###### #EOT\n---\n -
Location:
x/ds/tiles/{deformat-digest}.md -
Upsert Logic: Skip (with Notice message) if
#ds/{deformat-digest}/{YYYY-MM-DD}exists, append otherwise Blockchain Spec: -
Structure:
### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained to #ds/block/${previousBlockchainEntryDigest} on ${YYYY-MM-DDTHH:mm}\n${digestTags.join(' ')}\n#ds/block/{currentBlockchainEntryDigest} -
Location:
x/ds/blockchains/wwbc-{YY-MM}.md -
Blockchain Logic: {previousBlockchainEntryDigest} is a hash of {YY-MM} for initial block or the BlockchainEntryDigest of the previous entry; if there are no “wwbc-…md” files yet, use the hash of the YY-MM, if there are not blocks in this months file yet, use the last block from the previous month, otherwise, use the last block in the current month’s file Script Spec:
-
use Obsidian Templater scripting language for the script
-
use tp.user.updateFrontMatter to update frontmatter
-
15s Notice messages about updates, 3 messages: status, tiles, and blockchain
-
tp.user scripts: computeSHA256(content, length = 12); splitIntoTiles(content); ensureDirectoryExists(path); upsertToFile(filePath, header, content); updateFrontMatter(file, updates); getPreviousBlockchainEntryDigest(app, computeSHA256);
-
inline helper functions: createDigestTag(hash, date); createDigestRootHash(digestTags);
/ function createDigestTag(hash, date) { return#ds/${hash}/${date}; } function createDigestRootHash(digestTags) { return tp.user.computeSHA256(digestTags.join(’ ’), 12); } // Main function async function dsTaggerChain() { const version = “0.9.7”; const startTime = Date.now(); const currentDate = new Date().toISOString().split(‘T’)[0]; const currentTimestamp = new Date().toISOString(); console.log([${currentDate}] DS Tagger Chain v${version} started); // Configuration const tileDirectoryPath = “x/ds/tiles”; const blockchainDirectoryPath = “x/ds/blockchains”; try { // Ensure directories exist await tp.user.ensureDirectoryExists(tileDirectoryPath); await tp.user.ensureDirectoryExists(blockchainDirectoryPath); let content = tp.file.content; const fileName = tp.file.title; const currentFile = tp.file.find_tfile(fileName); if (typeof content !== ‘string’) { throw new Error(‘Received non-string content’); } const authors = tp.frontmatter.authors || ‘Unknown’; const license = tp.frontmatter.license || ‘Unspecified’; console.log([${currentDate}] Authors extracted: ${authors}); console.log([${currentDate}] License extracted: ${license}); console.log([${currentDate}] File content length: ${content.length} characters); const { frontmatter, tiles } = tp.user.splitIntoTiles(content); console.log([${currentDate}] Number of tiles: ${tiles.length}); let processedTiles = []; let digestedTiles = 0; let nonDigestedTiles = 0; let updatedTiles = 0; let digestTags = []; let tileFilesUpdated = {}; for (let i = 0; i < tiles.length; i++) { let tile = tiles[i]; const tileHash = tp.user.computeSHA256(tile); console.log(\n[${currentDate}] Processing tile ${i + 1} (${tileHash})); let existingDigestMatch = tile.match(/\s(#ds/[a-f0-9]+/\d{4}-\d{2}-\d{2})/); let existingDigest = existingDigestMatch ? existingDigestMatch[1] : null; console.log(Existing Digest Tag: ${existingDigest || 'None'}); let cleanTile = tile.replace(/\s*#ds/[a-f0-9]+/\d{4}-\d{2}-\d{2}/, ”).trim(); let { deformattedContent, charactersRemoved } = tp.user.deformatTile(cleanTile); let digest = tp.user.computeSHA256(deformattedContent); let digestTag = createDigestTag(digest, currentDate); console.log(New Digest Tag: ${digestTag}); if (existingDigest && existingDigest.includes(digest)) { console.log(Content unchanged for tile ${tileHash}. Keeping existing Digest Tag.); digestTag = existingDigest; nonDigestedTiles++; // new Notice(Skipping unchanged tile: ${digestTag}, 15000); } else { console.log(Content changed or new for tile ${tileHash}. Updating Digest Tag.); if (existingDigest) { updatedTiles++; } else { digestedTiles++; } } let processedTile =${cleanTile} ${digestTag}; processedTiles.push(processedTile); digestTags.push(digestTag); console.log(Tile ${tileHash} stats: Characters removed: ${charactersRemoved}); const tileFilePath =${tileDirectoryPath}/${digest}.md; const digestRootHash = createDigestRootHash(digestTags); const tileFileContent =###### #Digested-Tile ${digestTag} Authors:: ${authors} License:: ${license} Digest Root:: ${digestRootHash} #MarkdownTile ${cleanTile} #DeformattedTile ${deformattedContent} #EOT ---; const { status: tileUpdateStatus, file: tileFile } = await tp.user.upsertToFile(tileFilePath,###### #Digested-Tile ${digestTag}, tileFileContent); tileFilesUpdated[tileFilePath] = tileUpdateStatus; // Update tile file frontmatter if (tileFile) { await tp.user.updateFrontMatter(tileFile, { aliases: [digestTag], authors: authors, license: license, ‘digest-root’: digestRootHash }); } } let result = frontmatter + ‘\n’ + processedTiles.join(‘\n\n’); const yearMonth = currentDate.slice(2, 7); let digestRootHash = createDigestRootHash(digestTags); console.log(\n[${currentDate}] Digest Root hash created: ${digestRootHash}); // Modify the current file content await app.vault.modify(currentFile, result); // Update current file frontmatter using tp.user.updateFrontMatter after modifying content await tp.user.updateFrontMatter(currentFile, { aliases: [#ds/root/${digestRootHash}], ‘blockchain_last_digest_root’:#ds/root/${digestRootHash}, ‘blockchain_digest_timestamp’: currentTimestamp, ‘blockchain_file’:[[wwbc-${yearMonth}]]}); // Update blockchain file const blockchainFilePath =${blockchainDirectoryPath}/wwbc-${yearMonth}.md; const previousBlockchainEntryDigest = await tp.user.getPreviousBlockchainEntryDigest(app, blockchainDirectoryPath, tp.user.computeSHA256); console.log(Previous blockchain entry digest: ${previousBlockchainEntryDigest}); // Create the blockchain content without the final hash const blockchainContentWithoutHash =### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained to #ds/block/${previousBlockchainEntryDigest} on ${currentTimestamp} ${digestTags.join(' ')}.trim(); // Generate the hash for the blockchain entry const blockchainEntryHash = tp.user.computeSHA256(blockchainContentWithoutHash); // Create the final blockchain content const blockchainFileContent =${blockchainContentWithoutHash} #ds/block/${blockchainEntryHash}; const { status: blockchainUpdateStatus, file: blockchainFile } = await tp.user.upsertToFile(blockchainFilePath,### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained to #ds/block/${previousBlockchainEntryDigest} on ${currentTimestamp}, blockchainFileContent); if (blockchainFile) { await tp.user.updateFrontMatter(blockchainFile, { cssclasses: [locked] }); } if (blockchainUpdateStatus === ‘updated’) { console.log(Updated blockchain file: ${blockchainFilePath}); } else { console.log(Blockchain file already up to date: ${blockchainFilePath}); } const endTime = Date.now(); const runtime = ((endTime - startTime) / 1000).toFixed(2); console.log(\n[${currentDate}] DS Tagger Chain process completed successfully);const statusMessage = `DS Tagger Chain v${version} completed:
Runtime: {runtime}s
#ds/root/{digestRootHash}
Tiles processed: {digestedTiles}
Tiles not digested: {updatedTiles}
Date: {Object.entries(tileFilesUpdated).map(([file, status]) ⇒ ${file}: ${status}).join(‘\n’)}; const blockchainEntryMessage = Blockchain entry ({blockchainFileContent}; console.log(statusMessage); console.log(tileFilesMessage); console.log(blockchainEntryMessage); new Notice(statusMessage, 15000); new Notice(tileFilesMessage, 15000); new Notice(blockchainEntryMessage, 15000); } catch (error) { console.error([{version}: ${error.message}. Check console for details.`, 15000);
}
}
// Run the script and output the result
await dsTaggerChain();
%>
#EOT
DeformattedTile #Digested-Tile Authors:: Unknown License:: Unspecified Digest Root:: 62f36b314bb7 #MarkdownTile #DeformattedTile #EOT
Digested-Tile 2024-09-13 Authors:: Unknown License:: Unspecified Digest Root:: 62f36b314bb7 #MarkdownTile <%* // Doc Seal 0.9 for Obsidian Templater // Version 0.9.7 /* * Preserve Specs for Tile and Blockchain formats * * Tile Spec:
-
Structure
###### #Digested-Tile #ds/{deformat-digest}/{YYYY-MM-DD}\nAuthors:: {authors}\nLicense:: {license}\nDigest Root:: {digestRootHash}\n###### #MarkdownTile\n{tile}\n###### #DeformattedTile\n{deformatted-tile}\n###### #EOT\n---\n -
Location:
x/ds/tiles/{deformat-digest}.md -
Upsert Logic: Skip (with Notice message) if
#ds/{deformat-digest}/{YYYY-MM-DD}exists, append otherwise Blockchain Spec: -
Structure:
### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained to #ds/block/${previousBlockchainEntryDigest} on ${YYYY-MM-DDTHH:mm}\n${digestTags.join(' ')}\n#ds/block/{currentBlockchainEntryDigest} -
Location:
x/ds/blockchains/wwbc-{YY-MM}.md -
Blockchain Logic: {previousBlockchainEntryDigest} is a hash of {YY-MM} for initial block or the BlockchainEntryDigest of the previous entry; if there are no “wwbc-…md” files yet, use the hash of the YY-MM, if there are not blocks in this months file yet, use the last block from the previous month, otherwise, use the last block in the current month’s file Script Spec:
-
use Obsidian Templater scripting language for the script
-
use tp.user.updateFrontMatter to update frontmatter
-
15s Notice messages about updates, 3 messages: status, tiles, and blockchain
-
tp.user scripts: computeSHA256(content, length = 12); splitIntoTiles(content); ensureDirectoryExists(path); upsertToFile(filePath, header, content); updateFrontMatter(file, updates); getPreviousBlockchainEntryDigest(app, computeSHA256);
-
inline helper functions: createDigestTag(hash, date); createDigestRootHash(digestTags);
/ function createDigestTag(hash, date) { return#ds/${hash}/${date}; } function createDigestRootHash(digestTags) { return tp.user.computeSHA256(digestTags.join(’ ’), 12); } // Main function async function dsTaggerChain() { const version = “0.9.7”; const startTime = Date.now(); const currentDate = new Date().toISOString().split(‘T’)[0]; const currentTimestamp = new Date().toISOString(); console.log([${currentDate}] DS Tagger Chain v${version} started); // Configuration const tileDirectoryPath = “x/ds/tiles”; const blockchainDirectoryPath = “x/ds/blockchains”; try { // Ensure directories exist await tp.user.ensureDirectoryExists(tileDirectoryPath); await tp.user.ensureDirectoryExists(blockchainDirectoryPath); let content = tp.file.content; const fileName = tp.file.title; const currentFile = tp.file.find_tfile(fileName); if (typeof content !== ‘string’) { throw new Error(‘Received non-string content’); } const authors = tp.frontmatter.authors || ‘Unknown’; const license = tp.frontmatter.license || ‘Unspecified’; console.log([${currentDate}] Authors extracted: ${authors}); console.log([${currentDate}] License extracted: ${license}); console.log([${currentDate}] File content length: ${content.length} characters); const { frontmatter, tiles } = tp.user.splitIntoTiles(content); console.log([${currentDate}] Number of tiles: ${tiles.length}); let processedTiles = []; let digestedTiles = 0; let nonDigestedTiles = 0; let updatedTiles = 0; let digestTags = []; let tileFilesUpdated = {}; for (let i = 0; i < tiles.length; i++) { let tile = tiles[i]; const tileHash = tp.user.computeSHA256(tile); console.log(\n[${currentDate}] Processing tile ${i + 1} (${tileHash})); let existingDigestMatch = tile.match(/\s(#ds/[a-f0-9]+/\d{4}-\d{2}-\d{2})/); let existingDigest = existingDigestMatch ? existingDigestMatch[1] : null; console.log(Existing Digest Tag: ${existingDigest || 'None'}); let cleanTile = tile.replace(/\s*#ds/[a-f0-9]+/\d{4}-\d{2}-\d{2}/, ”).trim(); let { deformattedContent, charactersRemoved } = tp.user.deformatTile(cleanTile); let digest = tp.user.computeSHA256(deformattedContent); let digestTag = createDigestTag(digest, currentDate); console.log(New Digest Tag: ${digestTag}); if (existingDigest && existingDigest.includes(digest)) { console.log(Content unchanged for tile ${tileHash}. Keeping existing Digest Tag.); digestTag = existingDigest; nonDigestedTiles++; // new Notice(Skipping unchanged tile: ${digestTag}, 15000); } else { console.log(Content changed or new for tile ${tileHash}. Updating Digest Tag.); if (existingDigest) { updatedTiles++; } else { digestedTiles++; } } let processedTile =${cleanTile} ${digestTag}; processedTiles.push(processedTile); digestTags.push(digestTag); console.log(Tile ${tileHash} stats: Characters removed: ${charactersRemoved}); const tileFilePath =${tileDirectoryPath}/${digest}.md; const digestRootHash = createDigestRootHash(digestTags); const tileFileContent =###### #Digested-Tile ${digestTag} Authors:: ${authors} License:: ${license} Digest Root:: ${digestRootHash} #MarkdownTile ${cleanTile} #DeformattedTile ${deformattedContent} #EOT ---; const { status: tileUpdateStatus, file: tileFile } = await tp.user.upsertToFile(tileFilePath,###### #Digested-Tile ${digestTag}, tileFileContent); tileFilesUpdated[tileFilePath] = tileUpdateStatus; // Update tile file frontmatter if (tileFile) { await tp.user.updateFrontMatter(tileFile, { aliases: [digestTag], authors: authors, license: license, ‘digest-root’: digestRootHash }); } } let result = frontmatter + ‘\n’ + processedTiles.join(‘\n\n’); const yearMonth = currentDate.slice(2, 7); let digestRootHash = createDigestRootHash(digestTags); console.log(\n[${currentDate}] Digest Root hash created: ${digestRootHash}); // Modify the current file content await app.vault.modify(currentFile, result); // Update current file frontmatter using tp.user.updateFrontMatter after modifying content await tp.user.updateFrontMatter(currentFile, { aliases: [#ds/root/${digestRootHash}], ‘blockchain_last_digest_root’:#ds/root/${digestRootHash}, ‘blockchain_digest_timestamp’: currentTimestamp, ‘blockchain_file’:[[wwbc-${yearMonth}]]}); // Update blockchain file const blockchainFilePath =${blockchainDirectoryPath}/wwbc-${yearMonth}.md; const previousBlockchainEntryDigest = await tp.user.getPreviousBlockchainEntryDigest(app, blockchainDirectoryPath, tp.user.computeSHA256); console.log(Previous blockchain entry digest: ${previousBlockchainEntryDigest}); // Create the blockchain content without the final hash const blockchainContentWithoutHash =### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained to #ds/block/${previousBlockchainEntryDigest} on ${currentTimestamp} ${digestTags.join(' ')}.trim(); // Generate the hash for the blockchain entry const blockchainEntryHash = tp.user.computeSHA256(blockchainContentWithoutHash); // Create the final blockchain content const blockchainFileContent =${blockchainContentWithoutHash} #ds/block/${blockchainEntryHash}; const { status: blockchainUpdateStatus, file: blockchainFile } = await tp.user.upsertToFile(blockchainFilePath,### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained to #ds/block/${previousBlockchainEntryDigest} on ${currentTimestamp}, blockchainFileContent); if (blockchainFile) { await tp.user.updateFrontMatter(blockchainFile, { cssclasses: [locked] }); } if (blockchainUpdateStatus === ‘updated’) { console.log(Updated blockchain file: ${blockchainFilePath}); } else { console.log(Blockchain file already up to date: ${blockchainFilePath}); } const endTime = Date.now(); const runtime = ((endTime - startTime) / 1000).toFixed(2); console.log(\n[${currentDate}] DS Tagger Chain process completed successfully);const statusMessage = `DS Tagger Chain v${version} completed:
Runtime: {runtime}s
#ds/root/{digestRootHash}
Tiles processed: {digestedTiles}
Tiles not digested: {updatedTiles}
Date: {Object.entries(tileFilesUpdated).map(([file, status]) ⇒ ${file}: ${status}).join(‘\n’)}; const blockchainEntryMessage = Blockchain entry ({blockchainFileContent}; console.log(statusMessage); console.log(tileFilesMessage); console.log(blockchainEntryMessage); new Notice(statusMessage, 15000); new Notice(tileFilesMessage, 15000); new Notice(blockchainEntryMessage, 15000); } catch (error) { console.error([{version}: ${error.message}. Check console for details.`, 15000);
}
}
// Run the script and output the result
await dsTaggerChain();
%>
#DeformattedTile
<%*
// Doc Seal 0.9 for Obsidian Templater
// Version 0.9.7
/* * Preserve Specs for Tile and Blockchain formats * *
Tile Spec:
-
Structure
###### #Digested-Tile #ds/{deformat-digest}/{YYYY-MM-DD}\nAuthors:: {authors}\nLicense:: {license}\nDigest Root:: {digestRootHash}\n###### #MarkdownTile\n{tile}\n###### #DeformattedTile\n{deformatted-tile}\n###### #EOT\n---\n -
Location:
x/ds/tiles/{deformat-digest}.md -
Upsert Logic: Skip (with Notice message) if
#ds/{deformat-digest}/{YYYY-MM-DD}exists, append otherwise Blockchain Spec: -
Structure:
### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained to #ds/block/${previousBlockchainEntryDigest} on ${YYYY-MM-DDTHH:mm}\n${digestTags.join(' ')}\n#ds/block/{currentBlockchainEntryDigest} -
Location:
x/ds/blockchains/wwbc-{YY-MM}.md -
Blockchain Logic: {previousBlockchainEntryDigest} is a hash of {YY-MM} for initial block or the BlockchainEntryDigest of the previous entry; if there are no “wwbc-…md” files yet, use the hash of the YY-MM, if there are not blocks in this months file yet, use the last block from the previous month, otherwise, use the last block in the current month’s file Script Spec:
-
use Obsidian Templater scripting language for the script
-
use tp.user.updateFrontMatter to update frontmatter
-
15s Notice messages about updates, 3 messages: status, tiles, and blockchain
-
tp.user scripts: computeSHA256(content, length = 12); splitIntoTiles(content); ensureDirectoryExists(path); upsertToFile(filePath, header, content); updateFrontMatter(file, updates); getPreviousBlockchainEntryDigest(app, computeSHA256);
-
inline helper functions: createDigestTag(hash, date); createDigestRootHash(digestTags);
/ function createDigestTag(hash, date) { return#ds/${hash}/${date}; } function createDigestRootHash(digestTags) { return tp.user.computeSHA256(digestTags.join(’ ’), 12); } // Main function async function dsTaggerChain() { const version = “0.9.7”; const startTime = Date.now(); const currentDate = new Date().toISOString().split(‘T’)[0]; const currentTimestamp = new Date().toISOString(); console.log([${currentDate}] DS Tagger Chain v${version} started); // Configuration const tileDirectoryPath = “x/ds/tiles”; const blockchainDirectoryPath = “x/ds/blockchains”; try { // Ensure directories exist await tp.user.ensureDirectoryExists(tileDirectoryPath); await tp.user.ensureDirectoryExists(blockchainDirectoryPath); let content = tp.file.content; const fileName = tp.file.title; const currentFile = tp.file.find_tfile(fileName); if (typeof content !== ‘string’) { throw new Error(‘Received non-string content’); } const authors = tp.frontmatter.authors || ‘Unknown’; const license = tp.frontmatter.license || ‘Unspecified’; console.log([${currentDate}] Authors extracted: ${authors}); console.log([${currentDate}] License extracted: ${license}); console.log([${currentDate}] File content length: ${content.length} characters); const { frontmatter, tiles } = tp.user.splitIntoTiles(content); console.log([${currentDate}] Number of tiles: ${tiles.length}); let processedTiles = []; let digestedTiles = 0; let nonDigestedTiles = 0; let updatedTiles = 0; let digestTags = []; let tileFilesUpdated = {}; for (let i = 0; i < tiles.length; i++) { let tile = tiles[i]; const tileHash = tp.user.computeSHA256(tile); console.log(\n[${currentDate}] Processing tile ${i + 1} (${tileHash})); let existingDigestMatch = tile.match(/\s(#ds/[a-f0-9]+/\d{4}-\d{2}-\d{2})/); let existingDigest = existingDigestMatch ? existingDigestMatch[1] : null; console.log(Existing Digest Tag: ${existingDigest || 'None'}); let cleanTile = tile.replace(/\s*#ds/[a-f0-9]+/\d{4}-\d{2}-\d{2}/, ”).trim(); let { deformattedContent, charactersRemoved } = tp.user.deformatTile(cleanTile); let digest = tp.user.computeSHA256(deformattedContent); let digestTag = createDigestTag(digest, currentDate); console.log(New Digest Tag: ${digestTag}); if (existingDigest && existingDigest.includes(digest)) { console.log(Content unchanged for tile ${tileHash}. Keeping existing Digest Tag.); digestTag = existingDigest; nonDigestedTiles++; // new Notice(Skipping unchanged tile: ${digestTag}, 15000); } else { console.log(Content changed or new for tile ${tileHash}. Updating Digest Tag.); if (existingDigest) { updatedTiles++; } else { digestedTiles++; } } let processedTile =${cleanTile} ${digestTag}; processedTiles.push(processedTile); digestTags.push(digestTag); console.log(Tile ${tileHash} stats: Characters removed: ${charactersRemoved}); const tileFilePath =${tileDirectoryPath}/${digest}.md; const digestRootHash = createDigestRootHash(digestTags); const tileFileContent =###### #Digested-Tile ${digestTag} Authors:: ${authors} License:: ${license} Digest Root:: ${digestRootHash} #MarkdownTile ${cleanTile} #DeformattedTile ${deformattedContent} #EOT ---; const { status: tileUpdateStatus, file: tileFile } = await tp.user.upsertToFile(tileFilePath,###### #Digested-Tile ${digestTag}, tileFileContent); tileFilesUpdated[tileFilePath] = tileUpdateStatus; // Update tile file frontmatter if (tileFile) { await tp.user.updateFrontMatter(tileFile, { aliases: [digestTag], authors: authors, license: license, ‘digest-root’: digestRootHash }); } } let result = frontmatter + ‘\n’ + processedTiles.join(‘\n\n’); const yearMonth = currentDate.slice(2, 7); let digestRootHash = createDigestRootHash(digestTags); console.log(\n[${currentDate}] Digest Root hash created: ${digestRootHash}); // Modify the current file content await app.vault.modify(currentFile, result); // Update current file frontmatter using tp.user.updateFrontMatter after modifying content await tp.user.updateFrontMatter(currentFile, { aliases: [#ds/root/${digestRootHash}], ‘blockchain_last_digest_root’:#ds/root/${digestRootHash}, ‘blockchain_digest_timestamp’: currentTimestamp, ‘blockchain_file’:[[wwbc-${yearMonth}]]}); // Update blockchain file const blockchainFilePath =${blockchainDirectoryPath}/wwbc-${yearMonth}.md; const previousBlockchainEntryDigest = await tp.user.getPreviousBlockchainEntryDigest(app, blockchainDirectoryPath, tp.user.computeSHA256); console.log(Previous blockchain entry digest: ${previousBlockchainEntryDigest}); // Create the blockchain content without the final hash const blockchainContentWithoutHash =### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained to #ds/block/${previousBlockchainEntryDigest} on ${currentTimestamp} ${digestTags.join(' ')}.trim(); // Generate the hash for the blockchain entry const blockchainEntryHash = tp.user.computeSHA256(blockchainContentWithoutHash); // Create the final blockchain content const blockchainFileContent =${blockchainContentWithoutHash} #ds/block/${blockchainEntryHash}; const { status: blockchainUpdateStatus, file: blockchainFile } = await tp.user.upsertToFile(blockchainFilePath,### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained to #ds/block/${previousBlockchainEntryDigest} on ${currentTimestamp}, blockchainFileContent); if (blockchainFile) { await tp.user.updateFrontMatter(blockchainFile, { cssclasses: [locked] }); } if (blockchainUpdateStatus === ‘updated’) { console.log(Updated blockchain file: ${blockchainFilePath}); } else { console.log(Blockchain file already up to date: ${blockchainFilePath}); } const endTime = Date.now(); const runtime = ((endTime - startTime) / 1000).toFixed(2); console.log(\n[${currentDate}] DS Tagger Chain process completed successfully);const statusMessage = `DS Tagger Chain v${version} completed:
Runtime: {runtime}s
#ds/root/{digestRootHash}
Tiles processed: {digestedTiles}
Tiles not digested: {updatedTiles}
Date: {Object.entries(tileFilesUpdated).map(([file, status]) ⇒ ${file}: ${status}).join(‘\n’)}; const blockchainEntryMessage = Blockchain entry ({blockchainFileContent}; console.log(statusMessage); console.log(tileFilesMessage); console.log(blockchainEntryMessage); new Notice(statusMessage, 15000); new Notice(tileFilesMessage, 15000); new Notice(blockchainEntryMessage, 15000); } catch (error) { console.error([{version}: ${error.message}. Check console for details.`, 15000);
}
}
// Run the script and output the result
await dsTaggerChain();
%>
#EOT
EOT
DeformattedTile #Digested-Tile Authors:: Unknown License:: Unspecified Digest Root:: 1a947079cd7c #MarkdownTile #Digested-Tile Authors:: Unknown License:: Unspecified Digest Root:: 62f36b314bb7 #MarkdownTile #DeformattedTile #EOT
Digested-Tile 2024-09-13 Authors:: Unknown License:: Unspecified Digest Root:: 62f36b314bb7 #MarkdownTile <%* // Doc Seal 0.9 for Obsidian Templater // Version 0.9.7 /* * Preserve Specs for Tile and Blockchain formats * * Tile Spec:
-
Structure
###### #Digested-Tile #ds/{deformat-digest}/{YYYY-MM-DD}\nAuthors:: {authors}\nLicense:: {license}\nDigest Root:: {digestRootHash}\n###### #MarkdownTile\n{tile}\n###### #DeformattedTile\n{deformatted-tile}\n###### #EOT\n---\n -
Location:
x/ds/tiles/{deformat-digest}.md -
Upsert Logic: Skip (with Notice message) if
#ds/{deformat-digest}/{YYYY-MM-DD}exists, append otherwise Blockchain Spec: -
Structure:
### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained to #ds/block/${previousBlockchainEntryDigest} on ${YYYY-MM-DDTHH:mm}\n${digestTags.join(' ')}\n#ds/block/{currentBlockchainEntryDigest} -
Location:
x/ds/blockchains/wwbc-{YY-MM}.md -
Blockchain Logic: {previousBlockchainEntryDigest} is a hash of {YY-MM} for initial block or the BlockchainEntryDigest of the previous entry; if there are no “wwbc-…md” files yet, use the hash of the YY-MM, if there are not blocks in this months file yet, use the last block from the previous month, otherwise, use the last block in the current month’s file Script Spec:
-
use Obsidian Templater scripting language for the script
-
use tp.user.updateFrontMatter to update frontmatter
-
15s Notice messages about updates, 3 messages: status, tiles, and blockchain
-
tp.user scripts: computeSHA256(content, length = 12); splitIntoTiles(content); ensureDirectoryExists(path); upsertToFile(filePath, header, content); updateFrontMatter(file, updates); getPreviousBlockchainEntryDigest(app, computeSHA256);
-
inline helper functions: createDigestTag(hash, date); createDigestRootHash(digestTags);
/ function createDigestTag(hash, date) { return#ds/${hash}/${date}; } function createDigestRootHash(digestTags) { return tp.user.computeSHA256(digestTags.join(’ ’), 12); } // Main function async function dsTaggerChain() { const version = “0.9.7”; const startTime = Date.now(); const currentDate = new Date().toISOString().split(‘T’)[0]; const currentTimestamp = new Date().toISOString(); console.log([${currentDate}] DS Tagger Chain v${version} started); // Configuration const tileDirectoryPath = “x/ds/tiles”; const blockchainDirectoryPath = “x/ds/blockchains”; try { // Ensure directories exist await tp.user.ensureDirectoryExists(tileDirectoryPath); await tp.user.ensureDirectoryExists(blockchainDirectoryPath); let content = tp.file.content; const fileName = tp.file.title; const currentFile = tp.file.find_tfile(fileName); if (typeof content !== ‘string’) { throw new Error(‘Received non-string content’); } const authors = tp.frontmatter.authors || ‘Unknown’; const license = tp.frontmatter.license || ‘Unspecified’; console.log([${currentDate}] Authors extracted: ${authors}); console.log([${currentDate}] License extracted: ${license}); console.log([${currentDate}] File content length: ${content.length} characters); const { frontmatter, tiles } = tp.user.splitIntoTiles(content); console.log([${currentDate}] Number of tiles: ${tiles.length}); let processedTiles = []; let digestedTiles = 0; let nonDigestedTiles = 0; let updatedTiles = 0; let digestTags = []; let tileFilesUpdated = {}; for (let i = 0; i < tiles.length; i++) { let tile = tiles[i]; const tileHash = tp.user.computeSHA256(tile); console.log(\n[${currentDate}] Processing tile ${i + 1} (${tileHash})); let existingDigestMatch = tile.match(/\s(#ds/[a-f0-9]+/\d{4}-\d{2}-\d{2})/); let existingDigest = existingDigestMatch ? existingDigestMatch[1] : null; console.log(Existing Digest Tag: ${existingDigest || 'None'}); let cleanTile = tile.replace(/\s*#ds/[a-f0-9]+/\d{4}-\d{2}-\d{2}/, ”).trim(); let { deformattedContent, charactersRemoved } = tp.user.deformatTile(cleanTile); let digest = tp.user.computeSHA256(deformattedContent); let digestTag = createDigestTag(digest, currentDate); console.log(New Digest Tag: ${digestTag}); if (existingDigest && existingDigest.includes(digest)) { console.log(Content unchanged for tile ${tileHash}. Keeping existing Digest Tag.); digestTag = existingDigest; nonDigestedTiles++; // new Notice(Skipping unchanged tile: ${digestTag}, 15000); } else { console.log(Content changed or new for tile ${tileHash}. Updating Digest Tag.); if (existingDigest) { updatedTiles++; } else { digestedTiles++; } } let processedTile =${cleanTile} ${digestTag}; processedTiles.push(processedTile); digestTags.push(digestTag); console.log(Tile ${tileHash} stats: Characters removed: ${charactersRemoved}); const tileFilePath =${tileDirectoryPath}/${digest}.md; const digestRootHash = createDigestRootHash(digestTags); const tileFileContent =###### #Digested-Tile ${digestTag} Authors:: ${authors} License:: ${license} Digest Root:: ${digestRootHash} #MarkdownTile ${cleanTile} #DeformattedTile ${deformattedContent} #EOT ---; const { status: tileUpdateStatus, file: tileFile } = await tp.user.upsertToFile(tileFilePath,###### #Digested-Tile ${digestTag}, tileFileContent); tileFilesUpdated[tileFilePath] = tileUpdateStatus; // Update tile file frontmatter if (tileFile) { await tp.user.updateFrontMatter(tileFile, { aliases: [digestTag], authors: authors, license: license, ‘digest-root’: digestRootHash }); } } let result = frontmatter + ‘\n’ + processedTiles.join(‘\n\n’); const yearMonth = currentDate.slice(2, 7); let digestRootHash = createDigestRootHash(digestTags); console.log(\n[${currentDate}] Digest Root hash created: ${digestRootHash}); // Modify the current file content await app.vault.modify(currentFile, result); // Update current file frontmatter using tp.user.updateFrontMatter after modifying content await tp.user.updateFrontMatter(currentFile, { aliases: [#ds/root/${digestRootHash}], ‘blockchain_last_digest_root’:#ds/root/${digestRootHash}, ‘blockchain_digest_timestamp’: currentTimestamp, ‘blockchain_file’:[[wwbc-${yearMonth}]]}); // Update blockchain file const blockchainFilePath =${blockchainDirectoryPath}/wwbc-${yearMonth}.md; const previousBlockchainEntryDigest = await tp.user.getPreviousBlockchainEntryDigest(app, blockchainDirectoryPath, tp.user.computeSHA256); console.log(Previous blockchain entry digest: ${previousBlockchainEntryDigest}); // Create the blockchain content without the final hash const blockchainContentWithoutHash =### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained to #ds/block/${previousBlockchainEntryDigest} on ${currentTimestamp} ${digestTags.join(' ')}.trim(); // Generate the hash for the blockchain entry const blockchainEntryHash = tp.user.computeSHA256(blockchainContentWithoutHash); // Create the final blockchain content const blockchainFileContent =${blockchainContentWithoutHash} #ds/block/${blockchainEntryHash}; const { status: blockchainUpdateStatus, file: blockchainFile } = await tp.user.upsertToFile(blockchainFilePath,### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained to #ds/block/${previousBlockchainEntryDigest} on ${currentTimestamp}, blockchainFileContent); if (blockchainFile) { await tp.user.updateFrontMatter(blockchainFile, { cssclasses: [locked] }); } if (blockchainUpdateStatus === ‘updated’) { console.log(Updated blockchain file: ${blockchainFilePath}); } else { console.log(Blockchain file already up to date: ${blockchainFilePath}); } const endTime = Date.now(); const runtime = ((endTime - startTime) / 1000).toFixed(2); console.log(\n[${currentDate}] DS Tagger Chain process completed successfully);const statusMessage = `DS Tagger Chain v${version} completed:
Runtime: {runtime}s
#ds/root/{digestRootHash}
Tiles processed: {digestedTiles}
Tiles not digested: {updatedTiles}
Date: {Object.entries(tileFilesUpdated).map(([file, status]) ⇒ ${file}: ${status}).join(‘\n’)}; const blockchainEntryMessage = Blockchain entry ({blockchainFileContent}; console.log(statusMessage); console.log(tileFilesMessage); console.log(blockchainEntryMessage); new Notice(statusMessage, 15000); new Notice(tileFilesMessage, 15000); new Notice(blockchainEntryMessage, 15000); } catch (error) { console.error([{version}: ${error.message}. Check console for details.`, 15000);
}
}
// Run the script and output the result
await dsTaggerChain();
%>
#DeformattedTile
<%*
// Doc Seal 0.9 for Obsidian Templater
// Version 0.9.7
/* * Preserve Specs for Tile and Blockchain formats * *
Tile Spec:
-
Structure
###### #Digested-Tile #ds/{deformat-digest}/{YYYY-MM-DD}\nAuthors:: {authors}\nLicense:: {license}\nDigest Root:: {digestRootHash}\n###### #MarkdownTile\n{tile}\n###### #DeformattedTile\n{deformatted-tile}\n###### #EOT\n---\n -
Location:
x/ds/tiles/{deformat-digest}.md -
Upsert Logic: Skip (with Notice message) if
#ds/{deformat-digest}/{YYYY-MM-DD}exists, append otherwise Blockchain Spec: -
Structure:
### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained to #ds/block/${previousBlockchainEntryDigest} on ${YYYY-MM-DDTHH:mm}\n${digestTags.join(' ')}\n#ds/block/{currentBlockchainEntryDigest} -
Location:
x/ds/blockchains/wwbc-{YY-MM}.md -
Blockchain Logic: {previousBlockchainEntryDigest} is a hash of {YY-MM} for initial block or the BlockchainEntryDigest of the previous entry; if there are no “wwbc-…md” files yet, use the hash of the YY-MM, if there are not blocks in this months file yet, use the last block from the previous month, otherwise, use the last block in the current month’s file Script Spec:
-
use Obsidian Templater scripting language for the script
-
use tp.user.updateFrontMatter to update frontmatter
-
15s Notice messages about updates, 3 messages: status, tiles, and blockchain
-
tp.user scripts: computeSHA256(content, length = 12); splitIntoTiles(content); ensureDirectoryExists(path); upsertToFile(filePath, header, content); updateFrontMatter(file, updates); getPreviousBlockchainEntryDigest(app, computeSHA256);
-
inline helper functions: createDigestTag(hash, date); createDigestRootHash(digestTags);
/ function createDigestTag(hash, date) { return#ds/${hash}/${date}; } function createDigestRootHash(digestTags) { return tp.user.computeSHA256(digestTags.join(’ ’), 12); } // Main function async function dsTaggerChain() { const version = “0.9.7”; const startTime = Date.now(); const currentDate = new Date().toISOString().split(‘T’)[0]; const currentTimestamp = new Date().toISOString(); console.log([${currentDate}] DS Tagger Chain v${version} started); // Configuration const tileDirectoryPath = “x/ds/tiles”; const blockchainDirectoryPath = “x/ds/blockchains”; try { // Ensure directories exist await tp.user.ensureDirectoryExists(tileDirectoryPath); await tp.user.ensureDirectoryExists(blockchainDirectoryPath); let content = tp.file.content; const fileName = tp.file.title; const currentFile = tp.file.find_tfile(fileName); if (typeof content !== ‘string’) { throw new Error(‘Received non-string content’); } const authors = tp.frontmatter.authors || ‘Unknown’; const license = tp.frontmatter.license || ‘Unspecified’; console.log([${currentDate}] Authors extracted: ${authors}); console.log([${currentDate}] License extracted: ${license}); console.log([${currentDate}] File content length: ${content.length} characters); const { frontmatter, tiles } = tp.user.splitIntoTiles(content); console.log([${currentDate}] Number of tiles: ${tiles.length}); let processedTiles = []; let digestedTiles = 0; let nonDigestedTiles = 0; let updatedTiles = 0; let digestTags = []; let tileFilesUpdated = {}; for (let i = 0; i < tiles.length; i++) { let tile = tiles[i]; const tileHash = tp.user.computeSHA256(tile); console.log(\n[${currentDate}] Processing tile ${i + 1} (${tileHash})); let existingDigestMatch = tile.match(/\s(#ds/[a-f0-9]+/\d{4}-\d{2}-\d{2})/); let existingDigest = existingDigestMatch ? existingDigestMatch[1] : null; console.log(Existing Digest Tag: ${existingDigest || 'None'}); let cleanTile = tile.replace(/\s*#ds/[a-f0-9]+/\d{4}-\d{2}-\d{2}/, ”).trim(); let { deformattedContent, charactersRemoved } = tp.user.deformatTile(cleanTile); let digest = tp.user.computeSHA256(deformattedContent); let digestTag = createDigestTag(digest, currentDate); console.log(New Digest Tag: ${digestTag}); if (existingDigest && existingDigest.includes(digest)) { console.log(Content unchanged for tile ${tileHash}. Keeping existing Digest Tag.); digestTag = existingDigest; nonDigestedTiles++; // new Notice(Skipping unchanged tile: ${digestTag}, 15000); } else { console.log(Content changed or new for tile ${tileHash}. Updating Digest Tag.); if (existingDigest) { updatedTiles++; } else { digestedTiles++; } } let processedTile =${cleanTile} ${digestTag}; processedTiles.push(processedTile); digestTags.push(digestTag); console.log(Tile ${tileHash} stats: Characters removed: ${charactersRemoved}); const tileFilePath =${tileDirectoryPath}/${digest}.md; const digestRootHash = createDigestRootHash(digestTags); const tileFileContent =###### #Digested-Tile ${digestTag} Authors:: ${authors} License:: ${license} Digest Root:: ${digestRootHash} #MarkdownTile ${cleanTile} #DeformattedTile ${deformattedContent} #EOT ---; const { status: tileUpdateStatus, file: tileFile } = await tp.user.upsertToFile(tileFilePath,###### #Digested-Tile ${digestTag}, tileFileContent); tileFilesUpdated[tileFilePath] = tileUpdateStatus; // Update tile file frontmatter if (tileFile) { await tp.user.updateFrontMatter(tileFile, { aliases: [digestTag], authors: authors, license: license, ‘digest-root’: digestRootHash }); } } let result = frontmatter + ‘\n’ + processedTiles.join(‘\n\n’); const yearMonth = currentDate.slice(2, 7); let digestRootHash = createDigestRootHash(digestTags); console.log(\n[${currentDate}] Digest Root hash created: ${digestRootHash}); // Modify the current file content await app.vault.modify(currentFile, result); // Update current file frontmatter using tp.user.updateFrontMatter after modifying content await tp.user.updateFrontMatter(currentFile, { aliases: [#ds/root/${digestRootHash}], ‘blockchain_last_digest_root’:#ds/root/${digestRootHash}, ‘blockchain_digest_timestamp’: currentTimestamp, ‘blockchain_file’:[[wwbc-${yearMonth}]]}); // Update blockchain file const blockchainFilePath =${blockchainDirectoryPath}/wwbc-${yearMonth}.md; const previousBlockchainEntryDigest = await tp.user.getPreviousBlockchainEntryDigest(app, blockchainDirectoryPath, tp.user.computeSHA256); console.log(Previous blockchain entry digest: ${previousBlockchainEntryDigest}); // Create the blockchain content without the final hash const blockchainContentWithoutHash =### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained to #ds/block/${previousBlockchainEntryDigest} on ${currentTimestamp} ${digestTags.join(' ')}.trim(); // Generate the hash for the blockchain entry const blockchainEntryHash = tp.user.computeSHA256(blockchainContentWithoutHash); // Create the final blockchain content const blockchainFileContent =${blockchainContentWithoutHash} #ds/block/${blockchainEntryHash}; const { status: blockchainUpdateStatus, file: blockchainFile } = await tp.user.upsertToFile(blockchainFilePath,### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained to #ds/block/${previousBlockchainEntryDigest} on ${currentTimestamp}, blockchainFileContent); if (blockchainFile) { await tp.user.updateFrontMatter(blockchainFile, { cssclasses: [locked] }); } if (blockchainUpdateStatus === ‘updated’) { console.log(Updated blockchain file: ${blockchainFilePath}); } else { console.log(Blockchain file already up to date: ${blockchainFilePath}); } const endTime = Date.now(); const runtime = ((endTime - startTime) / 1000).toFixed(2); console.log(\n[${currentDate}] DS Tagger Chain process completed successfully);const statusMessage = `DS Tagger Chain v${version} completed:
Runtime: {runtime}s
#ds/root/{digestRootHash}
Tiles processed: {digestedTiles}
Tiles not digested: {updatedTiles}
Date: {Object.entries(tileFilesUpdated).map(([file, status]) ⇒ ${file}: ${status}).join(‘\n’)}; const blockchainEntryMessage = Blockchain entry ({blockchainFileContent}; console.log(statusMessage); console.log(tileFilesMessage); console.log(blockchainEntryMessage); new Notice(statusMessage, 15000); new Notice(tileFilesMessage, 15000); new Notice(blockchainEntryMessage, 15000); } catch (error) { console.error([{version}: ${error.message}. Check console for details.`, 15000);
}
}
// Run the script and output the result
await dsTaggerChain();
%>
#EOT
DeformattedTile #Digested-Tile Authors:: Unknown License:: Unspecified Digest Root:: 62f36b314bb7 #MarkdownTile #DeformattedTile #EOT
Digested-Tile 2024-09-13 Authors:: Unknown License:: Unspecified Digest Root:: 62f36b314bb7 #MarkdownTile <%* // Doc Seal 0.9 for Obsidian Templater // Version 0.9.7 /* * Preserve Specs for Tile and Blockchain formats * * Tile Spec:
-
Structure
###### #Digested-Tile #ds/{deformat-digest}/{YYYY-MM-DD}\nAuthors:: {authors}\nLicense:: {license}\nDigest Root:: {digestRootHash}\n###### #MarkdownTile\n{tile}\n###### #DeformattedTile\n{deformatted-tile}\n###### #EOT\n---\n -
Location:
x/ds/tiles/{deformat-digest}.md -
Upsert Logic: Skip (with Notice message) if
#ds/{deformat-digest}/{YYYY-MM-DD}exists, append otherwise Blockchain Spec: -
Structure:
### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained to #ds/block/${previousBlockchainEntryDigest} on ${YYYY-MM-DDTHH:mm}\n${digestTags.join(' ')}\n#ds/block/{currentBlockchainEntryDigest} -
Location:
x/ds/blockchains/wwbc-{YY-MM}.md -
Blockchain Logic: {previousBlockchainEntryDigest} is a hash of {YY-MM} for initial block or the BlockchainEntryDigest of the previous entry; if there are no “wwbc-…md” files yet, use the hash of the YY-MM, if there are not blocks in this months file yet, use the last block from the previous month, otherwise, use the last block in the current month’s file Script Spec:
-
use Obsidian Templater scripting language for the script
-
use tp.user.updateFrontMatter to update frontmatter
-
15s Notice messages about updates, 3 messages: status, tiles, and blockchain
-
tp.user scripts: computeSHA256(content, length = 12); splitIntoTiles(content); ensureDirectoryExists(path); upsertToFile(filePath, header, content); updateFrontMatter(file, updates); getPreviousBlockchainEntryDigest(app, computeSHA256);
-
inline helper functions: createDigestTag(hash, date); createDigestRootHash(digestTags);
/ function createDigestTag(hash, date) { return#ds/${hash}/${date}; } function createDigestRootHash(digestTags) { return tp.user.computeSHA256(digestTags.join(’ ’), 12); } // Main function async function dsTaggerChain() { const version = “0.9.7”; const startTime = Date.now(); const currentDate = new Date().toISOString().split(‘T’)[0]; const currentTimestamp = new Date().toISOString(); console.log([${currentDate}] DS Tagger Chain v${version} started); // Configuration const tileDirectoryPath = “x/ds/tiles”; const blockchainDirectoryPath = “x/ds/blockchains”; try { // Ensure directories exist await tp.user.ensureDirectoryExists(tileDirectoryPath); await tp.user.ensureDirectoryExists(blockchainDirectoryPath); let content = tp.file.content; const fileName = tp.file.title; const currentFile = tp.file.find_tfile(fileName); if (typeof content !== ‘string’) { throw new Error(‘Received non-string content’); } const authors = tp.frontmatter.authors || ‘Unknown’; const license = tp.frontmatter.license || ‘Unspecified’; console.log([${currentDate}] Authors extracted: ${authors}); console.log([${currentDate}] License extracted: ${license}); console.log([${currentDate}] File content length: ${content.length} characters); const { frontmatter, tiles } = tp.user.splitIntoTiles(content); console.log([${currentDate}] Number of tiles: ${tiles.length}); let processedTiles = []; let digestedTiles = 0; let nonDigestedTiles = 0; let updatedTiles = 0; let digestTags = []; let tileFilesUpdated = {}; for (let i = 0; i < tiles.length; i++) { let tile = tiles[i]; const tileHash = tp.user.computeSHA256(tile); console.log(\n[${currentDate}] Processing tile ${i + 1} (${tileHash})); let existingDigestMatch = tile.match(/\s(#ds/[a-f0-9]+/\d{4}-\d{2}-\d{2})/); let existingDigest = existingDigestMatch ? existingDigestMatch[1] : null; console.log(Existing Digest Tag: ${existingDigest || 'None'}); let cleanTile = tile.replace(/\s*#ds/[a-f0-9]+/\d{4}-\d{2}-\d{2}/, ”).trim(); let { deformattedContent, charactersRemoved } = tp.user.deformatTile(cleanTile); let digest = tp.user.computeSHA256(deformattedContent); let digestTag = createDigestTag(digest, currentDate); console.log(New Digest Tag: ${digestTag}); if (existingDigest && existingDigest.includes(digest)) { console.log(Content unchanged for tile ${tileHash}. Keeping existing Digest Tag.); digestTag = existingDigest; nonDigestedTiles++; // new Notice(Skipping unchanged tile: ${digestTag}, 15000); } else { console.log(Content changed or new for tile ${tileHash}. Updating Digest Tag.); if (existingDigest) { updatedTiles++; } else { digestedTiles++; } } let processedTile =${cleanTile} ${digestTag}; processedTiles.push(processedTile); digestTags.push(digestTag); console.log(Tile ${tileHash} stats: Characters removed: ${charactersRemoved}); const tileFilePath =${tileDirectoryPath}/${digest}.md; const digestRootHash = createDigestRootHash(digestTags); const tileFileContent =###### #Digested-Tile ${digestTag} Authors:: ${authors} License:: ${license} Digest Root:: ${digestRootHash} #MarkdownTile ${cleanTile} #DeformattedTile ${deformattedContent} #EOT ---; const { status: tileUpdateStatus, file: tileFile } = await tp.user.upsertToFile(tileFilePath,###### #Digested-Tile ${digestTag}, tileFileContent); tileFilesUpdated[tileFilePath] = tileUpdateStatus; // Update tile file frontmatter if (tileFile) { await tp.user.updateFrontMatter(tileFile, { aliases: [digestTag], authors: authors, license: license, ‘digest-root’: digestRootHash }); } } let result = frontmatter + ‘\n’ + processedTiles.join(‘\n\n’); const yearMonth = currentDate.slice(2, 7); let digestRootHash = createDigestRootHash(digestTags); console.log(\n[${currentDate}] Digest Root hash created: ${digestRootHash}); // Modify the current file content await app.vault.modify(currentFile, result); // Update current file frontmatter using tp.user.updateFrontMatter after modifying content await tp.user.updateFrontMatter(currentFile, { aliases: [#ds/root/${digestRootHash}], ‘blockchain_last_digest_root’:#ds/root/${digestRootHash}, ‘blockchain_digest_timestamp’: currentTimestamp, ‘blockchain_file’:[[wwbc-${yearMonth}]]}); // Update blockchain file const blockchainFilePath =${blockchainDirectoryPath}/wwbc-${yearMonth}.md; const previousBlockchainEntryDigest = await tp.user.getPreviousBlockchainEntryDigest(app, blockchainDirectoryPath, tp.user.computeSHA256); console.log(Previous blockchain entry digest: ${previousBlockchainEntryDigest}); // Create the blockchain content without the final hash const blockchainContentWithoutHash =### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained to #ds/block/${previousBlockchainEntryDigest} on ${currentTimestamp} ${digestTags.join(' ')}.trim(); // Generate the hash for the blockchain entry const blockchainEntryHash = tp.user.computeSHA256(blockchainContentWithoutHash); // Create the final blockchain content const blockchainFileContent =${blockchainContentWithoutHash} #ds/block/${blockchainEntryHash}; const { status: blockchainUpdateStatus, file: blockchainFile } = await tp.user.upsertToFile(blockchainFilePath,### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained to #ds/block/${previousBlockchainEntryDigest} on ${currentTimestamp}, blockchainFileContent); if (blockchainFile) { await tp.user.updateFrontMatter(blockchainFile, { cssclasses: [locked] }); } if (blockchainUpdateStatus === ‘updated’) { console.log(Updated blockchain file: ${blockchainFilePath}); } else { console.log(Blockchain file already up to date: ${blockchainFilePath}); } const endTime = Date.now(); const runtime = ((endTime - startTime) / 1000).toFixed(2); console.log(\n[${currentDate}] DS Tagger Chain process completed successfully);const statusMessage = `DS Tagger Chain v${version} completed:
Runtime: {runtime}s
#ds/root/{digestRootHash}
Tiles processed: {digestedTiles}
Tiles not digested: {updatedTiles}
Date: {Object.entries(tileFilesUpdated).map(([file, status]) ⇒ ${file}: ${status}).join(‘\n’)}; const blockchainEntryMessage = Blockchain entry ({blockchainFileContent}; console.log(statusMessage); console.log(tileFilesMessage); console.log(blockchainEntryMessage); new Notice(statusMessage, 15000); new Notice(tileFilesMessage, 15000); new Notice(blockchainEntryMessage, 15000); } catch (error) { console.error([{version}: ${error.message}. Check console for details.`, 15000);
}
}
// Run the script and output the result
await dsTaggerChain();
%>
#DeformattedTile
<%*
// Doc Seal 0.9 for Obsidian Templater
// Version 0.9.7
/* * Preserve Specs for Tile and Blockchain formats * *
Tile Spec:
-
Structure
###### #Digested-Tile #ds/{deformat-digest}/{YYYY-MM-DD}\nAuthors:: {authors}\nLicense:: {license}\nDigest Root:: {digestRootHash}\n###### #MarkdownTile\n{tile}\n###### #DeformattedTile\n{deformatted-tile}\n###### #EOT\n---\n -
Location:
x/ds/tiles/{deformat-digest}.md -
Upsert Logic: Skip (with Notice message) if
#ds/{deformat-digest}/{YYYY-MM-DD}exists, append otherwise Blockchain Spec: -
Structure:
### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained to #ds/block/${previousBlockchainEntryDigest} on ${YYYY-MM-DDTHH:mm}\n${digestTags.join(' ')}\n#ds/block/{currentBlockchainEntryDigest} -
Location:
x/ds/blockchains/wwbc-{YY-MM}.md -
Blockchain Logic: {previousBlockchainEntryDigest} is a hash of {YY-MM} for initial block or the BlockchainEntryDigest of the previous entry; if there are no “wwbc-…md” files yet, use the hash of the YY-MM, if there are not blocks in this months file yet, use the last block from the previous month, otherwise, use the last block in the current month’s file Script Spec:
-
use Obsidian Templater scripting language for the script
-
use tp.user.updateFrontMatter to update frontmatter
-
15s Notice messages about updates, 3 messages: status, tiles, and blockchain
-
tp.user scripts: computeSHA256(content, length = 12); splitIntoTiles(content); ensureDirectoryExists(path); upsertToFile(filePath, header, content); updateFrontMatter(file, updates); getPreviousBlockchainEntryDigest(app, computeSHA256);
-
inline helper functions: createDigestTag(hash, date); createDigestRootHash(digestTags);
/ function createDigestTag(hash, date) { return#ds/${hash}/${date}; } function createDigestRootHash(digestTags) { return tp.user.computeSHA256(digestTags.join(’ ’), 12); } // Main function async function dsTaggerChain() { const version = “0.9.7”; const startTime = Date.now(); const currentDate = new Date().toISOString().split(‘T’)[0]; const currentTimestamp = new Date().toISOString(); console.log([${currentDate}] DS Tagger Chain v${version} started); // Configuration const tileDirectoryPath = “x/ds/tiles”; const blockchainDirectoryPath = “x/ds/blockchains”; try { // Ensure directories exist await tp.user.ensureDirectoryExists(tileDirectoryPath); await tp.user.ensureDirectoryExists(blockchainDirectoryPath); let content = tp.file.content; const fileName = tp.file.title; const currentFile = tp.file.find_tfile(fileName); if (typeof content !== ‘string’) { throw new Error(‘Received non-string content’); } const authors = tp.frontmatter.authors || ‘Unknown’; const license = tp.frontmatter.license || ‘Unspecified’; console.log([${currentDate}] Authors extracted: ${authors}); console.log([${currentDate}] License extracted: ${license}); console.log([${currentDate}] File content length: ${content.length} characters); const { frontmatter, tiles } = tp.user.splitIntoTiles(content); console.log([${currentDate}] Number of tiles: ${tiles.length}); let processedTiles = []; let digestedTiles = 0; let nonDigestedTiles = 0; let updatedTiles = 0; let digestTags = []; let tileFilesUpdated = {}; for (let i = 0; i < tiles.length; i++) { let tile = tiles[i]; const tileHash = tp.user.computeSHA256(tile); console.log(\n[${currentDate}] Processing tile ${i + 1} (${tileHash})); let existingDigestMatch = tile.match(/\s(#ds/[a-f0-9]+/\d{4}-\d{2}-\d{2})/); let existingDigest = existingDigestMatch ? existingDigestMatch[1] : null; console.log(Existing Digest Tag: ${existingDigest || 'None'}); let cleanTile = tile.replace(/\s*#ds/[a-f0-9]+/\d{4}-\d{2}-\d{2}/, ”).trim(); let { deformattedContent, charactersRemoved } = tp.user.deformatTile(cleanTile); let digest = tp.user.computeSHA256(deformattedContent); let digestTag = createDigestTag(digest, currentDate); console.log(New Digest Tag: ${digestTag}); if (existingDigest && existingDigest.includes(digest)) { console.log(Content unchanged for tile ${tileHash}. Keeping existing Digest Tag.); digestTag = existingDigest; nonDigestedTiles++; // new Notice(Skipping unchanged tile: ${digestTag}, 15000); } else { console.log(Content changed or new for tile ${tileHash}. Updating Digest Tag.); if (existingDigest) { updatedTiles++; } else { digestedTiles++; } } let processedTile =${cleanTile} ${digestTag}; processedTiles.push(processedTile); digestTags.push(digestTag); console.log(Tile ${tileHash} stats: Characters removed: ${charactersRemoved}); const tileFilePath =${tileDirectoryPath}/${digest}.md; const digestRootHash = createDigestRootHash(digestTags); const tileFileContent =###### #Digested-Tile ${digestTag} Authors:: ${authors} License:: ${license} Digest Root:: ${digestRootHash} #MarkdownTile ${cleanTile} #DeformattedTile ${deformattedContent} #EOT ---; const { status: tileUpdateStatus, file: tileFile } = await tp.user.upsertToFile(tileFilePath,###### #Digested-Tile ${digestTag}, tileFileContent); tileFilesUpdated[tileFilePath] = tileUpdateStatus; // Update tile file frontmatter if (tileFile) { await tp.user.updateFrontMatter(tileFile, { aliases: [digestTag], authors: authors, license: license, ‘digest-root’: digestRootHash }); } } let result = frontmatter + ‘\n’ + processedTiles.join(‘\n\n’); const yearMonth = currentDate.slice(2, 7); let digestRootHash = createDigestRootHash(digestTags); console.log(\n[${currentDate}] Digest Root hash created: ${digestRootHash}); // Modify the current file content await app.vault.modify(currentFile, result); // Update current file frontmatter using tp.user.updateFrontMatter after modifying content await tp.user.updateFrontMatter(currentFile, { aliases: [#ds/root/${digestRootHash}], ‘blockchain_last_digest_root’:#ds/root/${digestRootHash}, ‘blockchain_digest_timestamp’: currentTimestamp, ‘blockchain_file’:[[wwbc-${yearMonth}]]}); // Update blockchain file const blockchainFilePath =${blockchainDirectoryPath}/wwbc-${yearMonth}.md; const previousBlockchainEntryDigest = await tp.user.getPreviousBlockchainEntryDigest(app, blockchainDirectoryPath, tp.user.computeSHA256); console.log(Previous blockchain entry digest: ${previousBlockchainEntryDigest}); // Create the blockchain content without the final hash const blockchainContentWithoutHash =### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained to #ds/block/${previousBlockchainEntryDigest} on ${currentTimestamp} ${digestTags.join(' ')}.trim(); // Generate the hash for the blockchain entry const blockchainEntryHash = tp.user.computeSHA256(blockchainContentWithoutHash); // Create the final blockchain content const blockchainFileContent =${blockchainContentWithoutHash} #ds/block/${blockchainEntryHash}; const { status: blockchainUpdateStatus, file: blockchainFile } = await tp.user.upsertToFile(blockchainFilePath,### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained to #ds/block/${previousBlockchainEntryDigest} on ${currentTimestamp}, blockchainFileContent); if (blockchainFile) { await tp.user.updateFrontMatter(blockchainFile, { cssclasses: [locked] }); } if (blockchainUpdateStatus === ‘updated’) { console.log(Updated blockchain file: ${blockchainFilePath}); } else { console.log(Blockchain file already up to date: ${blockchainFilePath}); } const endTime = Date.now(); const runtime = ((endTime - startTime) / 1000).toFixed(2); console.log(\n[${currentDate}] DS Tagger Chain process completed successfully);const statusMessage = `DS Tagger Chain v${version} completed: