Skip to content

Commit 6acd306

Browse files
Deploy site from ffac6ba
1 parent 052c691 commit 6acd306

15 files changed

Lines changed: 2503 additions & 0 deletions

File tree

1970-01-01-blog-guide/index.html

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -659,6 +659,188 @@ <h4 class="card-title mb-3 fw-bolder">Donate</h4>
659659

660660

661661

662+
<div class="amazon-affiliate-container">
663+
<div class="affiliate-disclaimer">
664+
<small>
665+
<em>#CommissionsEarned | As an Amazon Associate we earn from qualifying purchases.</em>
666+
</small>
667+
</div>
668+
669+
<div id="amazon-product-display">
670+
<!-- Product will be inserted here by JavaScript -->
671+
</div>
672+
</div>
673+
674+
<script>
675+
(function() {
676+
// Load products from Jekyll data
677+
const allProducts = [{"title":"ASUS TUF Gaming GeForce RTX ™ 5070 12GB GDDR7 OC Edition Gaming Graphics Card (PCIe® 5.0, HDMI®/DP 2.1, 3.125-slot, Military-Grade Components, Protective PCB Coating, axial-tech Fans)","image":"https://m.media-amazon.com/images/I/815-M4vy8JL._AC_SL1500_.jpg","link":"https://www.amazon.com/dp/B0DS6S98ZF","tags":["gpu","computer hardware","gaming","streaming"]},{"title":"AMD Ryzen™ 9 9900X 12-Core, 24-Thread Unlocked Desktop Processor","image":"https://m.media-amazon.com/images/I/61dukbEGziL._AC_SL1500_.jpg","link":"https://www.amazon.com/dp/B0D6NN87T8","tags":["cpu","computer hardware","gaming","streaming"]},{"title":"Elgato Stream Deck MK.2 – Studio Controller, 15 macro keys, trigger actions in apps and software like OBS, Twitch, ​YouTube and more, works with Mac and PC","image":"https://m.media-amazon.com/images/I/61gtdFnK+UL._AC_SL1500_.jpg","link":"https://www.amazon.com/dp/B09738CV2G","tags":["streaming","accessories","content creation"]},{"title":"Logitech for Creators Blue Microphones Yeti USB Microphone (Blackout)","image":"https://m.media-amazon.com/images/I/61KTMvS5JBL._AC_SL1500_.jpg","link":"https://www.amazon.com/dp/B00N1YPXW2","tags":["audio","streaming","content creation","accessories"]},{"title":"SAMSUNG 990 PRO SSD 2TB NVMe M.2 PCIe Gen4, M.2 2280 Internal Solid State Hard Drive, Seq. Read Speeds Up to 7,450 MB/s for High End Computing, Gaming, and Heavy Duty Workstations, MZ-V9P2T0B/AM","image":"https://m.media-amazon.com/images/I/71OWtcxKgvL._AC_SL1500_.jpg","link":"https://www.amazon.com/dp/B0BHJJ9Y77","tags":["storage","computer hardware","gaming"]}];
678+
679+
// Get affiliate tag from site config
680+
const affiliateTag = "lizardbyte-blog-20";
681+
682+
// Get tags from page front matter if available
683+
const pageTags = [];
684+
685+
let filteredProducts = allProducts;
686+
687+
// Filter products by tags if specified
688+
if (pageTags && pageTags.length > 0) {
689+
filteredProducts = allProducts.filter(product => {
690+
if (!product.tags) return false;
691+
// Check if any page tag matches any product tag
692+
return pageTags.some(pageTag =>
693+
product.tags.some(productTag =>
694+
productTag.toLowerCase() === pageTag.toLowerCase()
695+
)
696+
);
697+
});
698+
699+
// If no products match, fall back to all products
700+
if (filteredProducts.length === 0) {
701+
filteredProducts = allProducts;
702+
}
703+
}
704+
705+
// Shuffle products once at the start for random initial order
706+
function shuffleArray(array) {
707+
const shuffled = [...array];
708+
for (let i = shuffled.length - 1; i > 0; i--) {
709+
const j = Math.floor(Math.random() * (i + 1));
710+
[shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]];
711+
}
712+
return shuffled;
713+
}
714+
715+
// Shuffle products once and keep that order
716+
filteredProducts = shuffleArray(filteredProducts);
717+
718+
let currentProductIndex = 0;
719+
let rotationTimer = null;
720+
721+
function startRotationTimer() {
722+
if (rotationTimer) {
723+
clearInterval(rotationTimer);
724+
}
725+
rotationTimer = setInterval(function() {
726+
navigateProduct('next');
727+
}, 30000); // 30 seconds
728+
}
729+
730+
function navigateProduct(direction) {
731+
if (filteredProducts.length === 0) return;
732+
733+
if (direction === 'next') {
734+
currentProductIndex = (currentProductIndex + 1) % filteredProducts.length;
735+
} else if (direction === 'prev') {
736+
currentProductIndex = (currentProductIndex - 1 + filteredProducts.length) % filteredProducts.length;
737+
}
738+
739+
displayProduct(filteredProducts[currentProductIndex]);
740+
}
741+
742+
function addAffiliateTag(url) {
743+
if (!affiliateTag || !url) return url;
744+
745+
try {
746+
const urlObj = new URL(url);
747+
urlObj.searchParams.set('tag', affiliateTag);
748+
return urlObj.toString();
749+
} catch (e) {
750+
console.error('Invalid URL:', url);
751+
return url;
752+
}
753+
}
754+
755+
function displayProduct(product) {
756+
if (!product) return;
757+
758+
const container = document.getElementById('amazon-product-display');
759+
if (!container) return;
760+
761+
// Add affiliate tag to product link
762+
const productLink = addAffiliateTag(product.link);
763+
764+
// Show navigation buttons only if there are multiple products
765+
const showNavigation = filteredProducts.length > 1;
766+
767+
container.innerHTML = `
768+
<div class="amazon-product-display">
769+
${showNavigation ? `
770+
<button class="product-nav-btn product-nav-prev" aria-label="Previous product">
771+
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
772+
<polyline points="15 18 9 12 15 6"></polyline>
773+
</svg>
774+
</button>
775+
` : ''}
776+
<div class="product-image">
777+
<a href="${productLink}" target="_blank" rel="noopener noreferrer nofollow sponsored">
778+
<img src="${product.image}" alt="${product.title}">
779+
</a>
780+
</div>
781+
<div class="product-details">
782+
<h4>
783+
<a href="${productLink}" target="_blank" rel="noopener noreferrer nofollow sponsored">
784+
${product.title}
785+
</a>
786+
</h4>
787+
<a href="${productLink}" target="_blank" rel="noopener noreferrer nofollow sponsored" class="product-link">
788+
View on Amazon
789+
</a>
790+
${product.tags ? `
791+
<div class="product-tags">
792+
<small>
793+
${product.tags.map(tag => `<span class="product-tag">${tag}</span>`).join('')}
794+
</small>
795+
</div>
796+
` : ''}
797+
</div>
798+
${showNavigation ? `
799+
<button class="product-nav-btn product-nav-next" aria-label="Next product">
800+
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
801+
<polyline points="9 18 15 12 9 6"></polyline>
802+
</svg>
803+
</button>
804+
` : ''}
805+
</div>
806+
`;
807+
808+
// Add event listeners for navigation buttons
809+
if (showNavigation) {
810+
const prevBtn = container.querySelector('.product-nav-prev');
811+
const nextBtn = container.querySelector('.product-nav-next');
812+
813+
if (prevBtn) {
814+
prevBtn.addEventListener('click', function() {
815+
navigateProduct('prev');
816+
startRotationTimer(); // Reset timer on manual navigation
817+
});
818+
}
819+
820+
if (nextBtn) {
821+
nextBtn.addEventListener('click', function() {
822+
navigateProduct('next');
823+
startRotationTimer(); // Reset timer on manual navigation
824+
});
825+
}
826+
}
827+
}
828+
829+
// Display initial product (first in shuffled array)
830+
if (filteredProducts.length > 0) {
831+
displayProduct(filteredProducts[currentProductIndex]);
832+
833+
// Start automatic rotation if there are products
834+
if (filteredProducts.length > 1) {
835+
startRotationTimer();
836+
}
837+
}
838+
})();
839+
</script>
840+
841+
842+
843+
662844
<!-- Check if any share-links are active -->
663845

664846

2023-09-14-remote-ssh-headless-sunshine-setup/index.html

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1116,6 +1116,188 @@ <h4 class="card-title mb-3 fw-bolder">Donate</h4>
11161116

11171117

11181118

1119+
<div class="amazon-affiliate-container">
1120+
<div class="affiliate-disclaimer">
1121+
<small>
1122+
<em>#CommissionsEarned | As an Amazon Associate we earn from qualifying purchases.</em>
1123+
</small>
1124+
</div>
1125+
1126+
<div id="amazon-product-display">
1127+
<!-- Product will be inserted here by JavaScript -->
1128+
</div>
1129+
</div>
1130+
1131+
<script>
1132+
(function() {
1133+
// Load products from Jekyll data
1134+
const allProducts = [{"title":"ASUS TUF Gaming GeForce RTX ™ 5070 12GB GDDR7 OC Edition Gaming Graphics Card (PCIe® 5.0, HDMI®/DP 2.1, 3.125-slot, Military-Grade Components, Protective PCB Coating, axial-tech Fans)","image":"https://m.media-amazon.com/images/I/815-M4vy8JL._AC_SL1500_.jpg","link":"https://www.amazon.com/dp/B0DS6S98ZF","tags":["gpu","computer hardware","gaming","streaming"]},{"title":"AMD Ryzen™ 9 9900X 12-Core, 24-Thread Unlocked Desktop Processor","image":"https://m.media-amazon.com/images/I/61dukbEGziL._AC_SL1500_.jpg","link":"https://www.amazon.com/dp/B0D6NN87T8","tags":["cpu","computer hardware","gaming","streaming"]},{"title":"Elgato Stream Deck MK.2 – Studio Controller, 15 macro keys, trigger actions in apps and software like OBS, Twitch, ​YouTube and more, works with Mac and PC","image":"https://m.media-amazon.com/images/I/61gtdFnK+UL._AC_SL1500_.jpg","link":"https://www.amazon.com/dp/B09738CV2G","tags":["streaming","accessories","content creation"]},{"title":"Logitech for Creators Blue Microphones Yeti USB Microphone (Blackout)","image":"https://m.media-amazon.com/images/I/61KTMvS5JBL._AC_SL1500_.jpg","link":"https://www.amazon.com/dp/B00N1YPXW2","tags":["audio","streaming","content creation","accessories"]},{"title":"SAMSUNG 990 PRO SSD 2TB NVMe M.2 PCIe Gen4, M.2 2280 Internal Solid State Hard Drive, Seq. Read Speeds Up to 7,450 MB/s for High End Computing, Gaming, and Heavy Duty Workstations, MZ-V9P2T0B/AM","image":"https://m.media-amazon.com/images/I/71OWtcxKgvL._AC_SL1500_.jpg","link":"https://www.amazon.com/dp/B0BHJJ9Y77","tags":["storage","computer hardware","gaming"]}];
1135+
1136+
// Get affiliate tag from site config
1137+
const affiliateTag = "lizardbyte-blog-20";
1138+
1139+
// Get tags from page front matter if available
1140+
const pageTags = ["community-guide","community-guide-sunshine","linux","sunshine"];
1141+
1142+
let filteredProducts = allProducts;
1143+
1144+
// Filter products by tags if specified
1145+
if (pageTags && pageTags.length > 0) {
1146+
filteredProducts = allProducts.filter(product => {
1147+
if (!product.tags) return false;
1148+
// Check if any page tag matches any product tag
1149+
return pageTags.some(pageTag =>
1150+
product.tags.some(productTag =>
1151+
productTag.toLowerCase() === pageTag.toLowerCase()
1152+
)
1153+
);
1154+
});
1155+
1156+
// If no products match, fall back to all products
1157+
if (filteredProducts.length === 0) {
1158+
filteredProducts = allProducts;
1159+
}
1160+
}
1161+
1162+
// Shuffle products once at the start for random initial order
1163+
function shuffleArray(array) {
1164+
const shuffled = [...array];
1165+
for (let i = shuffled.length - 1; i > 0; i--) {
1166+
const j = Math.floor(Math.random() * (i + 1));
1167+
[shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]];
1168+
}
1169+
return shuffled;
1170+
}
1171+
1172+
// Shuffle products once and keep that order
1173+
filteredProducts = shuffleArray(filteredProducts);
1174+
1175+
let currentProductIndex = 0;
1176+
let rotationTimer = null;
1177+
1178+
function startRotationTimer() {
1179+
if (rotationTimer) {
1180+
clearInterval(rotationTimer);
1181+
}
1182+
rotationTimer = setInterval(function() {
1183+
navigateProduct('next');
1184+
}, 30000); // 30 seconds
1185+
}
1186+
1187+
function navigateProduct(direction) {
1188+
if (filteredProducts.length === 0) return;
1189+
1190+
if (direction === 'next') {
1191+
currentProductIndex = (currentProductIndex + 1) % filteredProducts.length;
1192+
} else if (direction === 'prev') {
1193+
currentProductIndex = (currentProductIndex - 1 + filteredProducts.length) % filteredProducts.length;
1194+
}
1195+
1196+
displayProduct(filteredProducts[currentProductIndex]);
1197+
}
1198+
1199+
function addAffiliateTag(url) {
1200+
if (!affiliateTag || !url) return url;
1201+
1202+
try {
1203+
const urlObj = new URL(url);
1204+
urlObj.searchParams.set('tag', affiliateTag);
1205+
return urlObj.toString();
1206+
} catch (e) {
1207+
console.error('Invalid URL:', url);
1208+
return url;
1209+
}
1210+
}
1211+
1212+
function displayProduct(product) {
1213+
if (!product) return;
1214+
1215+
const container = document.getElementById('amazon-product-display');
1216+
if (!container) return;
1217+
1218+
// Add affiliate tag to product link
1219+
const productLink = addAffiliateTag(product.link);
1220+
1221+
// Show navigation buttons only if there are multiple products
1222+
const showNavigation = filteredProducts.length > 1;
1223+
1224+
container.innerHTML = `
1225+
<div class="amazon-product-display">
1226+
${showNavigation ? `
1227+
<button class="product-nav-btn product-nav-prev" aria-label="Previous product">
1228+
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
1229+
<polyline points="15 18 9 12 15 6"></polyline>
1230+
</svg>
1231+
</button>
1232+
` : ''}
1233+
<div class="product-image">
1234+
<a href="${productLink}" target="_blank" rel="noopener noreferrer nofollow sponsored">
1235+
<img src="${product.image}" alt="${product.title}">
1236+
</a>
1237+
</div>
1238+
<div class="product-details">
1239+
<h4>
1240+
<a href="${productLink}" target="_blank" rel="noopener noreferrer nofollow sponsored">
1241+
${product.title}
1242+
</a>
1243+
</h4>
1244+
<a href="${productLink}" target="_blank" rel="noopener noreferrer nofollow sponsored" class="product-link">
1245+
View on Amazon
1246+
</a>
1247+
${product.tags ? `
1248+
<div class="product-tags">
1249+
<small>
1250+
${product.tags.map(tag => `<span class="product-tag">${tag}</span>`).join('')}
1251+
</small>
1252+
</div>
1253+
` : ''}
1254+
</div>
1255+
${showNavigation ? `
1256+
<button class="product-nav-btn product-nav-next" aria-label="Next product">
1257+
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
1258+
<polyline points="9 18 15 12 9 6"></polyline>
1259+
</svg>
1260+
</button>
1261+
` : ''}
1262+
</div>
1263+
`;
1264+
1265+
// Add event listeners for navigation buttons
1266+
if (showNavigation) {
1267+
const prevBtn = container.querySelector('.product-nav-prev');
1268+
const nextBtn = container.querySelector('.product-nav-next');
1269+
1270+
if (prevBtn) {
1271+
prevBtn.addEventListener('click', function() {
1272+
navigateProduct('prev');
1273+
startRotationTimer(); // Reset timer on manual navigation
1274+
});
1275+
}
1276+
1277+
if (nextBtn) {
1278+
nextBtn.addEventListener('click', function() {
1279+
navigateProduct('next');
1280+
startRotationTimer(); // Reset timer on manual navigation
1281+
});
1282+
}
1283+
}
1284+
}
1285+
1286+
// Display initial product (first in shuffled array)
1287+
if (filteredProducts.length > 0) {
1288+
displayProduct(filteredProducts[currentProductIndex]);
1289+
1290+
// Start automatic rotation if there are products
1291+
if (filteredProducts.length > 1) {
1292+
startRotationTimer();
1293+
}
1294+
}
1295+
})();
1296+
</script>
1297+
1298+
1299+
1300+
11191301
<!-- Check if any share-links are active -->
11201302

11211303

0 commit comments

Comments
 (0)