feat: support defining Mastodon toot URL
This commit is contained in:
25
README.md
25
README.md
@@ -62,6 +62,31 @@ Comments are loaded automatically via JavaScript when visitors view a blog post.
|
|||||||
- Queries the PHP backend to find matching Mastodon toots
|
- Queries the PHP backend to find matching Mastodon toots
|
||||||
- Displays replies as comments with full formatting
|
- Displays replies as comments with full formatting
|
||||||
|
|
||||||
|
### Optional: Direct Toot URL (Recommended for Performance)
|
||||||
|
|
||||||
|
For better performance, you can specify the Mastodon toot URL directly in your post's front matter:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
---
|
||||||
|
title: "My Post Title"
|
||||||
|
mastodon_toot_url: "https://mastodon.social/@username/113456789012345678"
|
||||||
|
---
|
||||||
|
```
|
||||||
|
|
||||||
|
**Benefits:**
|
||||||
|
- Skips the entire toot search phase
|
||||||
|
- Reduces API calls significantly
|
||||||
|
- Faster page loads
|
||||||
|
- Works across different Mastodon instances
|
||||||
|
- Ensures the correct toot is always used
|
||||||
|
|
||||||
|
**When to use:**
|
||||||
|
- For any post where you know the Mastodon toot URL
|
||||||
|
- Especially recommended for popular or archived posts
|
||||||
|
- When you've shared the post on a different Mastodon instance
|
||||||
|
|
||||||
|
If no `mastodon_toot_url` is provided, the system automatically falls back to searching for toots containing the post URL.
|
||||||
|
|
||||||
### Force Cache Refresh
|
### Force Cache Refresh
|
||||||
|
|
||||||
To manually clear and rebuild the cache:
|
To manually clear and rebuild the cache:
|
||||||
|
|||||||
@@ -30,3 +30,4 @@
|
|||||||
<script>var MastodonUser="{{ .Site.Params.mastodoncomments.user }}"</script>
|
<script>var MastodonUser="{{ .Site.Params.mastodoncomments.user }}"</script>
|
||||||
<script>var BlogRegex="{{ .Site.Params.mastodoncomments.regex }}"</script>
|
<script>var BlogRegex="{{ .Site.Params.mastodoncomments.regex }}"</script>
|
||||||
<script>var CommentsContact="{{ .Site.Params.mastodoncomments.contact }}"</script>
|
<script>var CommentsContact="{{ .Site.Params.mastodoncomments.contact }}"</script>
|
||||||
|
<script>var MastodonTootUrl="{{ .Params.mastodon_toot_url }}"</script>
|
||||||
|
|||||||
@@ -28,12 +28,18 @@ $(document).ready(function() {
|
|||||||
|
|
||||||
debugLog('Searching for comments for: ' + RelPermalink);
|
debugLog('Searching for comments for: ' + RelPermalink);
|
||||||
|
|
||||||
|
// Check if a direct Mastodon toot URL is provided
|
||||||
|
var ajaxData = { search: RelPermalink };
|
||||||
|
if (MastodonTootUrl && MastodonTootUrl !== "") {
|
||||||
|
// Pass the full URL to PHP so it can extract instance and ID
|
||||||
|
ajaxData.toot_url = MastodonTootUrl;
|
||||||
|
debugLog('Using predefined Mastodon toot URL: ' + MastodonTootUrl);
|
||||||
|
}
|
||||||
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: "/comments/getcomments.php",
|
url: "/comments/getcomments.php",
|
||||||
type: "get",
|
type: "get",
|
||||||
data: {
|
data: ajaxData,
|
||||||
search : RelPermalink
|
|
||||||
},
|
|
||||||
success: function(data) {
|
success: function(data) {
|
||||||
// Enable debug logging if backend has debug enabled
|
// Enable debug logging if backend has debug enabled
|
||||||
if (data.debug === true) {
|
if (data.debug === true) {
|
||||||
|
|||||||
@@ -10,8 +10,11 @@ $instance = $config['mastodon-instance'];
|
|||||||
$uid = $config['user-id'];
|
$uid = $config['user-id'];
|
||||||
$searchurl = $config['search-url'];
|
$searchurl = $config['search-url'];
|
||||||
$search = isset($_GET['search']) ? strtolower($_GET['search']) : '';
|
$search = isset($_GET['search']) ? strtolower($_GET['search']) : '';
|
||||||
|
$toot_url = isset($_GET['toot_url']) ? $_GET['toot_url'] : null;
|
||||||
$force_refresh = isset($_GET['force_refresh']) && $_GET['force_refresh'] == '1';
|
$force_refresh = isset($_GET['force_refresh']) && $_GET['force_refresh'] == '1';
|
||||||
$debug_on = $config['debug'];
|
$debug_on = $config['debug'];
|
||||||
|
|
||||||
|
debug("Request parameters - search: $search, toot_url: " . ($toot_url ? $toot_url : "not provided") . ", force_refresh: " . ($force_refresh ? "yes" : "no"));
|
||||||
/* cache files */
|
/* cache files */
|
||||||
$ctt = $config['cache_toots'];
|
$ctt = $config['cache_toots'];
|
||||||
$dbt = "cache-toots.json";
|
$dbt = "cache-toots.json";
|
||||||
@@ -45,6 +48,19 @@ function debug($data) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Parse Mastodon toot URL to extract instance and toot ID */
|
||||||
|
function parseTootUrl($url) {
|
||||||
|
// Expected format: https://instance.example/@username/1234567890
|
||||||
|
// or: https://instance.example/users/username/statuses/1234567890
|
||||||
|
if (preg_match('|^(https?://[^/]+)/.*/(\d+)$|i', $url, $matches)) {
|
||||||
|
return [
|
||||||
|
'instance' => $matches[1],
|
||||||
|
'id' => $matches[2]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/* CACHE FUNCTIONS */
|
/* CACHE FUNCTIONS */
|
||||||
/* write data to file */
|
/* write data to file */
|
||||||
function write_db($db, $data, $id) {
|
function write_db($db, $data, $id) {
|
||||||
@@ -170,12 +186,41 @@ function tootContextAndStats($instance, $id, &$result) {
|
|||||||
* START PROGRAM
|
* START PROGRAM
|
||||||
***************/
|
***************/
|
||||||
|
|
||||||
/* check whether the cached file containing all toots is older than max. cache time */
|
// create empty $result template
|
||||||
// this at the same time loads the cached DB, either way
|
$result_empty = ['comments' => [], 'stats' => ['reblogs' => 0, 'favs' => 0, 'replies' => 0, 'url' => '', 'root' => 0]];
|
||||||
$cachebreak = $force_refresh; // Force cache break if requested
|
$result = $result_empty;
|
||||||
read_db($dbt, $toots, $ctt, $cachebreak, false);
|
|
||||||
|
|
||||||
if ($cachebreak) {
|
/* If toot_url is provided, skip the toot search entirely */
|
||||||
|
$toot_instance = $instance; // Default to config instance
|
||||||
|
$id = null; // Initialize
|
||||||
|
|
||||||
|
if ($toot_url) {
|
||||||
|
$parsed = parseTootUrl($toot_url);
|
||||||
|
if ($parsed) {
|
||||||
|
$id = $parsed['id'];
|
||||||
|
$toot_instance = $parsed['instance'];
|
||||||
|
debug("Toot URL provided: $toot_url");
|
||||||
|
debug("Extracted - Instance: $toot_instance, ID: $id");
|
||||||
|
|
||||||
|
// When using a custom instance, include instance hash in cache filename to avoid collisions
|
||||||
|
if ($toot_instance !== $instance) {
|
||||||
|
$instance_hash = md5($toot_instance);
|
||||||
|
$dbc = "cache-comments_%id-{$instance_hash}.json";
|
||||||
|
debug("Using instance-specific cache file for non-default instance");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
debug("Failed to parse toot URL: $toot_url");
|
||||||
|
$toot_url = null; // Fall back to search
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$toot_url) {
|
||||||
|
/* check whether the cached file containing all toots is older than max. cache time */
|
||||||
|
// this at the same time loads the cached DB, either way
|
||||||
|
$cachebreak = $force_refresh; // Force cache break if requested
|
||||||
|
read_db($dbt, $toots, $ctt, $cachebreak, false);
|
||||||
|
|
||||||
|
if ($cachebreak) {
|
||||||
/* Collect all the toots */
|
/* Collect all the toots */
|
||||||
/* get id of latest cached toot, and set as $min_id */
|
/* get id of latest cached toot, and set as $min_id */
|
||||||
debug("Toots cache outdated. Checking for new toots");
|
debug("Toots cache outdated. Checking for new toots");
|
||||||
@@ -208,24 +253,25 @@ if ($cachebreak) {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
debug("Toots cache is up-to-date");
|
debug("Toots cache is up-to-date");
|
||||||
}
|
}
|
||||||
|
|
||||||
// create empty $result
|
/* check if URL from $search exists in $toots */
|
||||||
$result_empty = ['comments' => [], 'stats' => ['reblogs' => 0, 'favs' => 0, 'replies' => 0, 'url' => '', 'root' => 0]];
|
$found_id = null;
|
||||||
$result = $result_empty;
|
foreach ($toots as $toot) {
|
||||||
|
if (!empty($toot['url']) && strpos($toot['url'], $search) !== false) {
|
||||||
|
$found_id = $toot['id']; // will keep the oldest (last in array)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* check if URL from $search exists in $toots */
|
if ($found_id === null) {
|
||||||
$found_id = null;
|
debug("Blog URL \"$search\" has not been found");
|
||||||
foreach ($toots as $toot) {
|
} else {
|
||||||
if (!empty($toot['url']) && strpos($toot['url'], $search) !== false) {
|
$id = $found_id;
|
||||||
$found_id = $toot['id']; // will keep the oldest (last in array)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($found_id === null) {
|
/* Process comments if we have a toot ID (either from URL or search) */
|
||||||
debug("Blog URL \"$search\" has not been found");
|
if ($id) {
|
||||||
} else {
|
|
||||||
$id = $found_id;
|
|
||||||
|
|
||||||
/* read cached comments, or reload new comments if cached data too old */
|
/* read cached comments, or reload new comments if cached data too old */
|
||||||
$cachebreak = false;
|
$cachebreak = false;
|
||||||
@@ -239,7 +285,7 @@ if ($found_id === null) {
|
|||||||
$result = $result_empty;
|
$result = $result_empty;
|
||||||
read_db($dbc, $result, $ctc, $cachebreak, $id);
|
read_db($dbc, $result, $ctc, $cachebreak, $id);
|
||||||
/* Extract comments and stats from toot */
|
/* Extract comments and stats from toot */
|
||||||
tootContextAndStats($instance, $id, $result);
|
tootContextAndStats($toot_instance, $id, $result);
|
||||||
// Always count replies manually for accuracy
|
// Always count replies manually for accuracy
|
||||||
$result['stats']['replies'] = count($result['comments']);
|
$result['stats']['replies'] = count($result['comments']);
|
||||||
$result['stats']['root'] = $id;
|
$result['stats']['root'] = $id;
|
||||||
|
|||||||
Reference in New Issue
Block a user