ultimate-jekyll-manager 0.0.135 → 0.0.137
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/TODO.md +0 -4
- package/dist/assets/css/pages/blog/post.scss +0 -5
- package/dist/assets/js/pages/blog/post.js +9 -0
- package/dist/commands/setup.js +121 -1
- package/firebase-debug.log +28 -0
- package/package.json +1 -1
package/TODO.md
CHANGED
|
@@ -98,10 +98,6 @@ REMAKE main/misc/embed-manager.html in UJ
|
|
|
98
98
|
REMAKE the dashboard one in UJ
|
|
99
99
|
FINISH redirec.js in UJ
|
|
100
100
|
|
|
101
|
-
# Update git remote url
|
|
102
|
-
* Check git remote get-url origin
|
|
103
|
-
* Update to correct one if necessary (imagemin wont work unless tis is accurate)
|
|
104
|
-
|
|
105
101
|
# Fix notifications
|
|
106
102
|
* UJ 2.0 for a while was making a DUPLICATE notifaction in users/{uid}/notifications/{token} AND in notifications/{token}
|
|
107
103
|
* We can SAFELY DELETE the users/{uid}/notifications collection
|
|
@@ -40,7 +40,9 @@ function insertBlogPostAds() {
|
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
// Find valid positions to insert ads (every 4 paragraphs)
|
|
43
|
+
// But ensure the last ad isn't too close to the end of the article
|
|
43
44
|
const positions = [];
|
|
45
|
+
const minParagraphsAfterLastAd = 2; // Ensure at least 2 paragraphs after the last ad
|
|
44
46
|
|
|
45
47
|
for (let i = 0; i < $paragraphs.length; i++) {
|
|
46
48
|
// Only consider every 4th paragraph
|
|
@@ -48,6 +50,12 @@ function insertBlogPostAds() {
|
|
|
48
50
|
continue;
|
|
49
51
|
}
|
|
50
52
|
|
|
53
|
+
// Skip if this position is too close to the end of the article
|
|
54
|
+
const paragraphsRemaining = $paragraphs.length - 1 - i;
|
|
55
|
+
if (paragraphsRemaining < minParagraphsAfterLastAd) {
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
|
|
51
59
|
const $p = $paragraphs[i];
|
|
52
60
|
const $prevSibling = $p.previousElementSibling;
|
|
53
61
|
|
|
@@ -101,6 +109,7 @@ function insertBlogPostAds() {
|
|
|
101
109
|
|
|
102
110
|
// Set data-lazy attribute
|
|
103
111
|
$adContainer.setAttribute('data-lazy', `@script ${JSON.stringify(lazyConfig)}`);
|
|
112
|
+
$adContainer.classList.add('my-4');
|
|
104
113
|
|
|
105
114
|
// Insert after the target paragraph
|
|
106
115
|
targetParagraph.parentNode.insertBefore($adContainer, targetParagraph.nextSibling);
|
package/dist/commands/setup.js
CHANGED
|
@@ -42,6 +42,7 @@ module.exports = async function (options) {
|
|
|
42
42
|
options.updateBundle = options.updateBundle !== 'false';
|
|
43
43
|
options.publishGitHubToken = options.publishGitHubToken !== 'false';
|
|
44
44
|
options.updateGitHubPages = options.updateGitHubPages !== 'false';
|
|
45
|
+
options.deduplicatePosts = options.deduplicatePosts !== 'false';
|
|
45
46
|
|
|
46
47
|
// Log
|
|
47
48
|
logger.log(`Welcome to ${package.name} v${package.version}!`);
|
|
@@ -125,6 +126,11 @@ module.exports = async function (options) {
|
|
|
125
126
|
if (options.updateBundle && !Manager.isServer()) {
|
|
126
127
|
await updateBundle();
|
|
127
128
|
}
|
|
129
|
+
|
|
130
|
+
// Deduplicate posts (remove duplicate posts with same slug but different dates)
|
|
131
|
+
if (options.deduplicatePosts) {
|
|
132
|
+
await deduplicatePosts();
|
|
133
|
+
}
|
|
128
134
|
} catch (e) {
|
|
129
135
|
// Throw error
|
|
130
136
|
throw e;
|
|
@@ -599,7 +605,7 @@ async function updateGitHubPages(options) {
|
|
|
599
605
|
owner,
|
|
600
606
|
repo,
|
|
601
607
|
source: sourceConfig,
|
|
602
|
-
|
|
608
|
+
};
|
|
603
609
|
|
|
604
610
|
// Add custom domain if available and not github.io domain
|
|
605
611
|
if (customDomain && !customDomain.includes('github.io')) {
|
|
@@ -654,3 +660,117 @@ async function updateGitHubPages(options) {
|
|
|
654
660
|
// Don't throw - this is not critical for setup to continue
|
|
655
661
|
}
|
|
656
662
|
}
|
|
663
|
+
|
|
664
|
+
// Deduplicate posts - removes duplicate posts with same slug but different dates
|
|
665
|
+
// Keeps the ORIGINAL (oldest) post and removes newer duplicates
|
|
666
|
+
async function deduplicatePosts() {
|
|
667
|
+
logger.log('🔍 Checking for duplicate posts...');
|
|
668
|
+
|
|
669
|
+
// Find all post files in src/_posts
|
|
670
|
+
const postsGlob = 'src/_posts/**/*.{md,markdown,html}';
|
|
671
|
+
const postFiles = glob(postsGlob, { nodir: true });
|
|
672
|
+
|
|
673
|
+
if (postFiles.length === 0) {
|
|
674
|
+
logger.log('No posts found');
|
|
675
|
+
return;
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
logger.log(`Found ${postFiles.length} post files`);
|
|
679
|
+
|
|
680
|
+
// Group posts by slug (filename without date prefix)
|
|
681
|
+
const postsBySlug = {};
|
|
682
|
+
|
|
683
|
+
for (const filePath of postFiles) {
|
|
684
|
+
const filename = path.basename(filePath);
|
|
685
|
+
|
|
686
|
+
// Jekyll post format: YYYY-MM-DD-slug.ext
|
|
687
|
+
const match = filename.match(/^(\d{4}-\d{2}-\d{2})-(.+)\.(md|markdown|html)$/);
|
|
688
|
+
|
|
689
|
+
if (!match) {
|
|
690
|
+
continue;
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
const [, dateStr, slug, ext] = match;
|
|
694
|
+
const date = new Date(dateStr);
|
|
695
|
+
|
|
696
|
+
if (!postsBySlug[slug]) {
|
|
697
|
+
postsBySlug[slug] = [];
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
postsBySlug[slug].push({
|
|
701
|
+
filePath,
|
|
702
|
+
filename,
|
|
703
|
+
date,
|
|
704
|
+
dateStr,
|
|
705
|
+
slug,
|
|
706
|
+
ext,
|
|
707
|
+
});
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
// Find duplicates and keep only the ORIGINAL (oldest)
|
|
711
|
+
let removedCount = 0;
|
|
712
|
+
const duplicates = [];
|
|
713
|
+
|
|
714
|
+
for (const [slug, posts] of Object.entries(postsBySlug)) {
|
|
715
|
+
if (posts.length <= 1) {
|
|
716
|
+
continue;
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
// Sort by date ascending (oldest first)
|
|
720
|
+
posts.sort((a, b) => a.date - b.date);
|
|
721
|
+
|
|
722
|
+
// Keep the oldest (original), mark the rest for removal
|
|
723
|
+
const [original, ...newer] = posts;
|
|
724
|
+
|
|
725
|
+
logger.log(`Found ${posts.length} posts with slug "${slug}":`);
|
|
726
|
+
logger.log(` ✅ Keeping original: ${original.filename} (${original.dateStr})`);
|
|
727
|
+
|
|
728
|
+
for (const post of newer) {
|
|
729
|
+
logger.log(` ❌ Removing duplicate: ${post.filename} (${post.dateStr})`);
|
|
730
|
+
|
|
731
|
+
// Remove the duplicate post file
|
|
732
|
+
try {
|
|
733
|
+
jetpack.remove(post.filePath);
|
|
734
|
+
removedCount++;
|
|
735
|
+
|
|
736
|
+
// Also remove the associated images folder (src/assets/images/blog/post-SLUG)
|
|
737
|
+
const imageFolder = `src/assets/images/blog/post-${post.slug}`;
|
|
738
|
+
if (jetpack.exists(imageFolder)) {
|
|
739
|
+
jetpack.remove(imageFolder);
|
|
740
|
+
logger.log(` 🗑️ Removed image folder: ${imageFolder}`);
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
duplicates.push({
|
|
744
|
+
kept: original.filename,
|
|
745
|
+
removed: post.filename,
|
|
746
|
+
removedPath: post.filePath,
|
|
747
|
+
slug,
|
|
748
|
+
});
|
|
749
|
+
} catch (error) {
|
|
750
|
+
logger.error(`Failed to remove ${post.filePath}:`, error);
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
// Log summary
|
|
756
|
+
if (removedCount > 0) {
|
|
757
|
+
logger.log(`✅ Removed ${removedCount} duplicate post(s)`);
|
|
758
|
+
|
|
759
|
+
// Save report
|
|
760
|
+
const reportDir = path.join(rootPathProject, '.temp/deduplicate');
|
|
761
|
+
jetpack.dir(reportDir);
|
|
762
|
+
|
|
763
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
764
|
+
const reportPath = path.join(reportDir, `duplicates-${timestamp}.json`);
|
|
765
|
+
|
|
766
|
+
jetpack.write(reportPath, JSON.stringify({
|
|
767
|
+
timestamp: new Date().toISOString(),
|
|
768
|
+
removedCount,
|
|
769
|
+
duplicates,
|
|
770
|
+
}, null, 2));
|
|
771
|
+
|
|
772
|
+
logger.log(`Report saved to: ${reportPath}`);
|
|
773
|
+
} else {
|
|
774
|
+
logger.log('✅ No duplicate posts found');
|
|
775
|
+
}
|
|
776
|
+
}
|
package/firebase-debug.log
CHANGED
|
@@ -2396,3 +2396,31 @@
|
|
|
2396
2396
|
[debug] [2025-12-04T08:02:22.587Z] > authorizing via signed-in user (ian.wiedenman@gmail.com)
|
|
2397
2397
|
[debug] [2025-12-04T08:02:22.588Z] > command requires scopes: ["email","openid","https://www.googleapis.com/auth/cloudplatformprojects.readonly","https://www.googleapis.com/auth/firebase","https://www.googleapis.com/auth/cloud-platform"]
|
|
2398
2398
|
[debug] [2025-12-04T08:02:22.588Z] > authorizing via signed-in user (ian.wiedenman@gmail.com)
|
|
2399
|
+
[debug] [2025-12-04T19:09:21.046Z] > command requires scopes: ["email","openid","https://www.googleapis.com/auth/cloudplatformprojects.readonly","https://www.googleapis.com/auth/firebase","https://www.googleapis.com/auth/cloud-platform"]
|
|
2400
|
+
[debug] [2025-12-04T19:09:21.045Z] > command requires scopes: ["email","openid","https://www.googleapis.com/auth/cloudplatformprojects.readonly","https://www.googleapis.com/auth/firebase","https://www.googleapis.com/auth/cloud-platform"]
|
|
2401
|
+
[debug] [2025-12-04T19:09:21.047Z] > authorizing via signed-in user (ian.wiedenman@gmail.com)
|
|
2402
|
+
[debug] [2025-12-04T19:09:21.047Z] > command requires scopes: ["email","openid","https://www.googleapis.com/auth/cloudplatformprojects.readonly","https://www.googleapis.com/auth/firebase","https://www.googleapis.com/auth/cloud-platform"]
|
|
2403
|
+
[debug] [2025-12-04T19:09:21.048Z] > authorizing via signed-in user (ian.wiedenman@gmail.com)
|
|
2404
|
+
[debug] [2025-12-04T19:09:21.057Z] > command requires scopes: ["email","openid","https://www.googleapis.com/auth/cloudplatformprojects.readonly","https://www.googleapis.com/auth/firebase","https://www.googleapis.com/auth/cloud-platform"]
|
|
2405
|
+
[debug] [2025-12-04T19:09:21.057Z] > authorizing via signed-in user (ian.wiedenman@gmail.com)
|
|
2406
|
+
[debug] [2025-12-04T19:09:21.047Z] > authorizing via signed-in user (ian.wiedenman@gmail.com)
|
|
2407
|
+
[debug] [2025-12-04T19:09:21.047Z] > command requires scopes: ["email","openid","https://www.googleapis.com/auth/cloudplatformprojects.readonly","https://www.googleapis.com/auth/firebase","https://www.googleapis.com/auth/cloud-platform"]
|
|
2408
|
+
[debug] [2025-12-04T19:09:21.048Z] > authorizing via signed-in user (ian.wiedenman@gmail.com)
|
|
2409
|
+
[debug] [2025-12-04T19:09:21.056Z] > command requires scopes: ["email","openid","https://www.googleapis.com/auth/cloudplatformprojects.readonly","https://www.googleapis.com/auth/firebase","https://www.googleapis.com/auth/cloud-platform"]
|
|
2410
|
+
[debug] [2025-12-04T19:09:21.057Z] > authorizing via signed-in user (ian.wiedenman@gmail.com)
|
|
2411
|
+
[debug] [2025-12-04T19:09:21.106Z] > command requires scopes: ["email","openid","https://www.googleapis.com/auth/cloudplatformprojects.readonly","https://www.googleapis.com/auth/firebase","https://www.googleapis.com/auth/cloud-platform"]
|
|
2412
|
+
[debug] [2025-12-04T19:09:21.108Z] > command requires scopes: ["email","openid","https://www.googleapis.com/auth/cloudplatformprojects.readonly","https://www.googleapis.com/auth/firebase","https://www.googleapis.com/auth/cloud-platform"]
|
|
2413
|
+
[debug] [2025-12-04T19:09:21.106Z] > authorizing via signed-in user (ian.wiedenman@gmail.com)
|
|
2414
|
+
[debug] [2025-12-04T19:09:21.107Z] > command requires scopes: ["email","openid","https://www.googleapis.com/auth/cloudplatformprojects.readonly","https://www.googleapis.com/auth/firebase","https://www.googleapis.com/auth/cloud-platform"]
|
|
2415
|
+
[debug] [2025-12-04T19:09:21.107Z] > authorizing via signed-in user (ian.wiedenman@gmail.com)
|
|
2416
|
+
[debug] [2025-12-04T19:09:21.108Z] > command requires scopes: ["email","openid","https://www.googleapis.com/auth/cloudplatformprojects.readonly","https://www.googleapis.com/auth/firebase","https://www.googleapis.com/auth/cloud-platform"]
|
|
2417
|
+
[debug] [2025-12-04T19:09:21.108Z] > authorizing via signed-in user (ian.wiedenman@gmail.com)
|
|
2418
|
+
[debug] [2025-12-04T19:09:21.109Z] > command requires scopes: ["email","openid","https://www.googleapis.com/auth/cloudplatformprojects.readonly","https://www.googleapis.com/auth/firebase","https://www.googleapis.com/auth/cloud-platform"]
|
|
2419
|
+
[debug] [2025-12-04T19:09:21.109Z] > authorizing via signed-in user (ian.wiedenman@gmail.com)
|
|
2420
|
+
[debug] [2025-12-04T19:09:21.109Z] > authorizing via signed-in user (ian.wiedenman@gmail.com)
|
|
2421
|
+
[debug] [2025-12-04T19:09:21.109Z] > command requires scopes: ["email","openid","https://www.googleapis.com/auth/cloudplatformprojects.readonly","https://www.googleapis.com/auth/firebase","https://www.googleapis.com/auth/cloud-platform"]
|
|
2422
|
+
[debug] [2025-12-04T19:09:21.109Z] > authorizing via signed-in user (ian.wiedenman@gmail.com)
|
|
2423
|
+
[debug] [2025-12-04T19:09:21.111Z] > command requires scopes: ["email","openid","https://www.googleapis.com/auth/cloudplatformprojects.readonly","https://www.googleapis.com/auth/firebase","https://www.googleapis.com/auth/cloud-platform"]
|
|
2424
|
+
[debug] [2025-12-04T19:09:21.111Z] > authorizing via signed-in user (ian.wiedenman@gmail.com)
|
|
2425
|
+
[debug] [2025-12-04T19:09:21.111Z] > command requires scopes: ["email","openid","https://www.googleapis.com/auth/cloudplatformprojects.readonly","https://www.googleapis.com/auth/firebase","https://www.googleapis.com/auth/cloud-platform"]
|
|
2426
|
+
[debug] [2025-12-04T19:09:21.111Z] > authorizing via signed-in user (ian.wiedenman@gmail.com)
|