Enhance metadata handling in MetaTagHelper and views

Updated MetaTagHelper.cs to add new metadata properties including ArticlePublishedTime, MetaDescription, and others. Refactored JavaScript in Index1.cshtml for improved readability and added functionality for video playback. Updated metadata attributes in Index.cshtml and Index1.cshtml to support new properties, ensuring better SEO and social media sharing capabilities.
This commit is contained in:
Nick 2025-09-10 21:05:51 +01:00
parent 82cb5cde02
commit b3cc5ccedd
4 changed files with 220 additions and 122 deletions

View File

@ -8,27 +8,42 @@ namespace CatherineLynwood.TagHelpers
#region Public Properties #region Public Properties
public DateTime? ArticleModifiedTime { get; set; } public DateTime? ArticleModifiedTime { get; set; }
public DateTime? ArticlePublishedTime { get; set; } public DateTime? ArticlePublishedTime { get; set; }
public string MetaAuthor { get; set; } public string MetaAuthor { get; set; }
public string MetaDescription { get; set; } public string MetaDescription { get; set; }
public string MetaImage { get; set; } public string MetaImage { get; set; }
public string MetaImageAlt { get; set; } public string MetaImageAlt { get; set; }
public string MetaImagePNG { get; set; }
public string MetaKeywords { get; set; } public string MetaKeywords { get; set; }
public string MetaTitle { get; set; } public string MetaTitle { get; set; }
public string MetaUrl { get; set; } public string MetaUrl { get; set; }
public string OgSiteName { get; set; } public string OgSiteName { get; set; }
public string OgType { get; set; } = "article"; public string OgType { get; set; } = "article";
public string TwitterCardType { get; set; } = "summary_large_image"; public string TwitterCardType { get; set; } = "summary_large_image";
public string TwitterCreatorHandle { get; set; } public string TwitterCreatorHandle { get; set; }
public int? TwitterPlayerHeight { get; set; } public int? TwitterPlayerHeight { get; set; }
public int? TwitterPlayerWidth { get; set; } public int? TwitterPlayerWidth { get; set; }
public string TwitterSiteHandle { get; set; } public string TwitterSiteHandle { get; set; }
public string TwitterVideoUrl { get; set; } public string TwitterVideoUrl { get; set; }
#endregion #endregion Public Properties
#region Public Methods #region Public Methods
@ -63,6 +78,9 @@ namespace CatherineLynwood.TagHelpers
if (!string.IsNullOrWhiteSpace(MetaImage)) if (!string.IsNullOrWhiteSpace(MetaImage))
metaTags.AppendLine($"<meta property=\"og:image\" content=\"{MetaImage}\">"); metaTags.AppendLine($"<meta property=\"og:image\" content=\"{MetaImage}\">");
if (!string.IsNullOrWhiteSpace(MetaImagePNG))
metaTags.AppendLine($"<meta property=\"og:image\" content=\"{MetaImagePNG}\">");
if (!string.IsNullOrWhiteSpace(MetaImageAlt)) if (!string.IsNullOrWhiteSpace(MetaImageAlt))
metaTags.AppendLine($"<meta property=\"og:image:alt\" content=\"{MetaImageAlt}\">"); metaTags.AppendLine($"<meta property=\"og:image:alt\" content=\"{MetaImageAlt}\">");
@ -124,6 +142,6 @@ namespace CatherineLynwood.TagHelpers
output.Content.SetHtmlContent(metaTags.ToString()); output.Content.SetHtmlContent(metaTags.ToString());
} }
#endregion #endregion Public Methods
} }
} }

View File

@ -399,38 +399,55 @@
<!-- Trailer source selection + play button --> <!-- Trailer source selection + play button -->
<script> <script>
document.addEventListener("DOMContentLoaded", () => { document.addEventListener("DOMContentLoaded", () => {
const vPortrait = document.getElementById("trailerPortrait"); const vPortrait = document.getElementById("trailerPortrait");
const vLandscape = document.getElementById("trailerLandscape"); const vLandscape = document.getElementById("trailerLandscape");
const playBtn = document.getElementById("trailerPlayBtn"); const playBtn = document.getElementById("trailerPlayBtn");
if (!playBtn) return; if (!playBtn) return;
// Which video is currently visible according to Bootstraps lg breakpoint (>=992px)? // Which video is currently visible according to Bootstraps lg breakpoint (>=992px)?
const isDesktop = () => window.matchMedia("(min-width: 992px)").matches; const isDesktop = () => window.matchMedia("(min-width: 992px)").matches;
const activeVideo = () => isDesktop() ? vLandscape : vPortrait; const activeVideo = () => isDesktop() ? vLandscape : vPortrait;
// Hide native controls when JS is active; custom button will start playback // Hide native controls when JS is active; custom button will start playback
[vPortrait, vLandscape].forEach(v => { if (v) v.controls = false; }); [vPortrait, vLandscape].forEach(v => { if (v) v.controls = false; });
// Start playback on whichever video is visible // Start playback on whichever video is visible
playBtn.addEventListener("click", () => { playBtn.addEventListener("click", () => {
const v = activeVideo(); const v = activeVideo();
if (!v) return; if (!v) return;
v.muted = false; v.muted = false;
v.volume = 1.0; v.volume = 1.0;
v.play().then(() => {
playBtn.style.display = "none";
}).catch(err => console.warn("Video play failed:", err));
});
// Toggle pause/play when user clicks on the video itself
[vPortrait, vLandscape].forEach(v => {
if (!v) return;
v.addEventListener("click", () => {
if (v.paused) {
v.play().then(() => { v.play().then(() => {
playBtn.style.display = "none"; playBtn.style.display = "none";
}).catch(err => console.warn("Video play failed:", err)); });
}); } else {
v.pause();
// If the user starts via OS overlay/natives, also hide the custom button playBtn.style.display = "block";
[vPortrait, vLandscape].forEach(v => { }
if (!v) return;
v.addEventListener("play", () => { playBtn.style.display = "none"; }, { once: true });
});
}); });
});
// If the user starts via OS overlay/natives, also hide the custom button
[vPortrait, vLandscape].forEach(v => {
if (!v) return;
v.addEventListener("play", () => { playBtn.style.display = "none"; });
v.addEventListener("pause", () => { playBtn.style.display = "block"; });
});
});
</script> </script>
<script> <script>
document.addEventListener('DOMContentLoaded', function () { document.addEventListener('DOMContentLoaded', function () {
const el = document.getElementById('fullSynopsis'); const el = document.getElementById('fullSynopsis');
@ -532,112 +549,172 @@
<!-- Geo-based slug swap for /go/{retailer}-{format}-{country} + dev override --> <!-- Geo-based slug swap for /go/{retailer}-{format}-{country} + dev override -->
<script> <script>
(function(){ (function(){
// Direct IngramSpark URLs // Direct IngramSpark URLs
const INGRAM_PB = "https://shop.ingramspark.com/b/084?params=6easpH54PaugzXFKdF4Tu4Izb0cvkMqbj3ZNlaYBKMJ"; const INGRAM_PB = "https://shop.ingramspark.com/b/084?params=6easpH54PaugzXFKdF4Tu4Izb0cvkMqbj3ZNlaYBKMJ";
const INGRAM_HB = "https://shop.ingramspark.com/b/084?params=GC1p1c8b66Rhfoy6Tq97SJmmhdZSEYuxBcCY5zxNstO"; const INGRAM_HB = "https://shop.ingramspark.com/b/084?params=GC1p1c8b66Rhfoy6Tq97SJmmhdZSEYuxBcCY5zxNstO";
// Elements // Elements
const elKindle = document.getElementById('kindleLink'); const elKindle = document.getElementById('kindleLink');
const elPbSelf = document.getElementById('paperbackLinkSelf'); const elPbSelf = document.getElementById('paperbackLinkSelf');
const elHbSelf = document.getElementById('hardbackLinkSelf'); const elHbSelf = document.getElementById('hardbackLinkSelf');
const elPbAmazon = document.getElementById('paperbackLink'); // optional const elPbAmazon = document.getElementById('paperbackLink'); // optional
const elHbAmazon = document.getElementById('hardbackLink'); // optional const elHbAmazon = document.getElementById('hardbackLink'); // optional
const elHbNat = document.getElementById('hardbackNational'); const elHbNat = document.getElementById('hardbackNational');
const elPbNat = document.getElementById('paperbackNational'); const elPbNat = document.getElementById('paperbackNational');
function show(el){ if (el) el.classList.remove('d-none'); } // Hint + flag
function hide(el){ if (el) el.classList.add('d-none'); } const elText = document.getElementById('buyCountryText');
const elFlag = document.getElementById('buyCountryFlag');
// helper to set both direct href and go slug // Countries we show custom text + flag for
function setLink(el, directHref, slug) { const targeted = new Set(['GB','US','CA','AU','IE']);
if (!el) return; const countryNames = {
el.href = directHref; GB: 'United Kingdom',
el.setAttribute('data-go-slug', slug); US: 'United States',
} CA: 'Canada',
AU: 'Australia',
IE: 'Ireland'
};
window.applyLinks = function applyLinks(code) { function show(el){ if (el) el.classList.remove('d-none'); }
const cc = (code || '').toUpperCase(); function hide(el){ if (el) el.classList.add('d-none'); }
// Defaults to US Amazon // Set both the visible direct URL and the /go slug used by your click router
let kindleHref = "https://www.amazon.com/dp/B0FBS427VD"; function setLink(el, directHref, slug) {
let pbAmzHref = "https://www.amazon.com/dp/1068225815"; if (!el) return;
let hbAmzHref = "https://www.amazon.com/dp/1068225807"; el.href = directHref;
el.setAttribute('data-go-slug', slug);
}
// National retailer defaults (GB Waterstones; US B&N) function setHint(code, name) {
let hbNatHref = "https://www.waterstones.com/book/the-alpha-flame/catherine-lynwood/9781068225802"; if (elText) elText.textContent = `Best options for ${name || 'your country'}`;
let pbNatHref = "https://www.waterstones.com/book/the-alpha-flame/catherine-lynwood/9781068225819"; if (!elFlag) return;
let hbNatSlug = "waterstones-hardback-gb"; const cc = (code || '').toUpperCase();
let pbNatSlug = "waterstones-paperback-gb"; if (!cc) { elFlag.classList.add('d-none'); return; }
const base = `/images/flags/${cc}`;
elFlag.src = `${base}.svg`;
elFlag.alt = `${name || cc} flag`;
elFlag.classList.remove('d-none');
elFlag.onerror = function () {
if (this.src.endsWith('.svg')) this.src = `${base}.png`;
else this.classList.add('d-none');
};
}
switch (cc) { // Expose for reuse if needed elsewhere
case 'GB': window.applyLinks = function applyLinks(code) {
kindleHref = "https://www.amazon.co.uk/dp/B0FBS427VD"; const cc = (code || '').toUpperCase();
pbAmzHref = "https://www.amazon.co.uk/dp/1068225815";
hbAmzHref = "https://www.amazon.co.uk/dp/1068225807";
hbNatHref = "https://www.waterstones.com/book/the-alpha-flame/catherine-lynwood/9781068225802";
pbNatHref = "https://www.waterstones.com/book/the-alpha-flame/catherine-lynwood/9781068225819";
hbNatSlug = "waterstones-hardback-gb";
pbNatSlug = "waterstones-paperback-gb";
break;
case 'US':
// keep US Amazon defaults
hbNatHref = "https://www.barnesandnoble.com/s/9781068225802";
pbNatHref = "https://www.barnesandnoble.com/s/9781068225819";
hbNatSlug = "bn-hardback-us";
pbNatSlug = "bn-paperback-us";
break;
case 'CA':
kindleHref = "https://www.amazon.ca/dp/B0FBS427VD";
pbAmzHref = "https://www.amazon.ca/dp/1068225815";
hbAmzHref = "https://www.amazon.ca/dp/1068225807";
// keep GB Waterstones/B&N as-is if you prefer not to show national links in CA
break;
case 'AU':
kindleHref = "https://www.amazon.com.au/dp/B0FBS427VD";
pbAmzHref = "https://www.amazon.com.au/dp/1068225815";
hbAmzHref = "https://www.amazon.com.au/dp/1068225807";
break;
case 'IE': // Ireland → use Amazon UK by default
kindleHref = "https://www.amazon.co.uk/dp/B0FBS427VD";
pbAmzHref = "https://www.amazon.co.uk/dp/1068225815";
hbAmzHref = "https://www.amazon.co.uk/dp/1068225807";
// keep Waterstones GB for national if you show it
hbNatHref = "https://www.waterstones.com/book/the-alpha-flame/catherine-lynwood/9781068225802";
pbNatHref = "https://www.waterstones.com/book/the-alpha-flame/catherine-lynwood/9781068225819";
hbNatSlug = "waterstones-hardback-gb";
pbNatSlug = "waterstones-paperback-gb";
break;
default:
break;
}
// Kindle: direct Amazon, route via /go/ on click // Defaults to US Amazon
setLink(elKindle, kindleHref, `amazon-kindle-${cc || 'us'}`); let kindleHref = "https://www.amazon.com/dp/B0FBS427VD";
let pbAmzHref = "https://www.amazon.com/dp/1068225815";
let hbAmzHref = "https://www.amazon.com/dp/1068225807";
// Ingram “Self” buttons: direct Ingram in GB/US only; hide elsewhere // National retailer defaults (GB Waterstones; US B&N)
if (cc === 'GB' || cc === 'US') { let hbNatHref = "https://www.waterstones.com/book/the-alpha-flame/catherine-lynwood/9781068225802";
setLink(elPbSelf, INGRAM_PB, `ingram-paperback-${cc.toLowerCase()}`); let pbNatHref = "https://www.waterstones.com/book/the-alpha-flame/catherine-lynwood/9781068225819";
setLink(elHbSelf, INGRAM_HB, `ingram-hardback-${cc.toLowerCase()}`); let hbNatSlug = "waterstones-hardback-gb";
show(elPbSelf); show(elHbSelf); let pbNatSlug = "waterstones-paperback-gb";
} else {
hide(elPbSelf); hide(elHbSelf);
}
// Amazon print buttons (if present): direct Amazon, route via /go/ switch (cc) {
setLink(elPbAmazon, pbAmzHref, `amazon-paperback-${cc || 'us'}`); case 'GB':
setLink(elHbAmazon, hbAmzHref, `amazon-hardback-${cc || 'us'}`); kindleHref = "https://www.amazon.co.uk/dp/B0FBS427VD";
pbAmzHref = "https://www.amazon.co.uk/dp/1068225815";
hbAmzHref = "https://www.amazon.co.uk/dp/1068225807";
hbNatHref = "https://www.waterstones.com/book/the-alpha-flame/catherine-lynwood/9781068225802";
pbNatHref = "https://www.waterstones.com/book/the-alpha-flame/catherine-lynwood/9781068225819";
hbNatSlug = "waterstones-hardback-gb";
pbNatSlug = "waterstones-paperback-gb";
break;
case 'US':
// keep US Amazon defaults
hbNatHref = "https://www.barnesandnoble.com/s/9781068225802";
pbNatHref = "https://www.barnesandnoble.com/s/9781068225819";
hbNatSlug = "bn-hardback-us";
pbNatSlug = "bn-paperback-us";
break;
case 'CA':
kindleHref = "https://www.amazon.ca/dp/B0FBS427VD";
pbAmzHref = "https://www.amazon.ca/dp/1068225815";
hbAmzHref = "https://www.amazon.ca/dp/1068225807";
break;
case 'AU':
kindleHref = "https://www.amazon.com.au/dp/B0FBS427VD";
pbAmzHref = "https://www.amazon.com.au/dp/1068225815";
hbAmzHref = "https://www.amazon.com.au/dp/1068225807";
break;
case 'IE': // Ireland → use Amazon UK by default
kindleHref = "https://www.amazon.co.uk/dp/B0FBS427VD";
pbAmzHref = "https://www.amazon.co.uk/dp/1068225815";
hbAmzHref = "https://www.amazon.co.uk/dp/1068225807";
hbNatHref = "https://www.waterstones.com/book/the-alpha-flame/catherine-lynwood/9781068225802";
pbNatHref = "https://www.waterstones.com/book/the-alpha-flame/catherine-lynwood/9781068225819";
hbNatSlug = "waterstones-hardback-gb";
pbNatSlug = "waterstones-paperback-gb";
break;
default:
break;
}
// National retailer row: direct URLs, route via /go/ // Kindle: direct Amazon, route via /go/ on click
setLink(elHbNat, hbNatHref, hbNatSlug); setLink(elKindle, kindleHref, `amazon-kindle-${cc || 'us'}`);
setLink(elPbNat, pbNatHref, pbNatSlug);
// Toggle any Ingram-only containers youve marked // Ingram “Self” buttons: direct Ingram in GB/US only; hide elsewhere
document.querySelectorAll('[data-ingram-only="true"]').forEach(x => { if (cc === 'GB' || cc === 'US') {
if (cc === 'GB' || cc === 'US') x.classList.remove('d-none'); else x.classList.add('d-none'); setLink(elPbSelf, INGRAM_PB, `ingram-paperback-${cc.toLowerCase()}`);
}); setLink(elHbSelf, INGRAM_HB, `ingram-hardback-${cc.toLowerCase()}`);
}; show(elPbSelf); show(elHbSelf);
})(); } else {
hide(elPbSelf); hide(elHbSelf);
}
// Amazon print buttons (if present): direct Amazon, route via /go/
setLink(elPbAmazon, pbAmzHref, `amazon-paperback-${cc.toLowerCase() || 'us'}`);
setLink(elHbAmazon, hbAmzHref, `amazon-hardback-${cc.toLowerCase() || 'us'}`);
// National retailer row: direct URLs, route via /go/
setLink(elHbNat, hbNatHref, hbNatSlug);
setLink(elPbNat, pbNatHref, pbNatSlug);
// Toggle any Ingram-only containers youve marked
document.querySelectorAll('[data-ingram-only="true"]').forEach(x => {
if (cc === 'GB' || cc === 'US') x.classList.remove('d-none'); else x.classList.add('d-none');
});
};
function updateForCountry(code, nameFromAPI) {
const cc = (code || '').toUpperCase();
// Update links
window.applyLinks(cc);
// Update hint + flag only for targeted set; leave default text for others
if (targeted.has(cc)) {
setHint(cc, countryNames[cc] || nameFromAPI || cc);
}
}
// Dev override: ?country=CA
const params = new URLSearchParams(location.search);
const override = params.get('country');
if (override) {
const cc = override.toUpperCase();
updateForCountry(cc, countryNames[cc] || cc);
return;
}
// Single geo lookup
fetch('https://ipapi.co/json/')
.then(r => r.json())
.then(d => {
const code = d && d.country_code ? String(d.country_code).toUpperCase() : '';
const name = d && d.country_name ? d.country_name : code;
updateForCountry(code, name);
})
.catch(() => {
// Leave defaults if geo fails
window.applyLinks('');
});
})();
</script> </script>
@ -650,6 +727,7 @@
meta-author="Catherine Lynwood" meta-author="Catherine Lynwood"
meta-url="https://www.catherinelynwood.com/the-alpha-flame/discovery" meta-url="https://www.catherinelynwood.com/the-alpha-flame/discovery"
meta-image="https://www.catherinelynwood.com/images/webp/the-alpha-flame-discovery-cover-1200.webp" meta-image="https://www.catherinelynwood.com/images/webp/the-alpha-flame-discovery-cover-1200.webp"
meta-image-png="https://www.catherinelynwood.com/images/the-alpha-flame-discovery-cover.png"
meta-image-alt="Maggie from 'The Alpha Flame: Discovery' by Catherine Lynwood" meta-image-alt="Maggie from 'The Alpha Flame: Discovery' by Catherine Lynwood"
og-site-name="Catherine Lynwood - The Alpha Flame: Discovery" og-site-name="Catherine Lynwood - The Alpha Flame: Discovery"
article-published-time="@new DateTime(2024, 11, 20)" article-published-time="@new DateTime(2024, 11, 20)"

View File

@ -72,6 +72,7 @@
meta-author="Catherine Lynwood" meta-author="Catherine Lynwood"
meta-url="https://www.catherinelynwood.com/" meta-url="https://www.catherinelynwood.com/"
meta-image="https://www.catherinelynwood.com/images/webp/the-alpha-flame-discovery-cover-600.webp" meta-image="https://www.catherinelynwood.com/images/webp/the-alpha-flame-discovery-cover-600.webp"
meta-image-png="https://www.catherinelynwood.com/images/the-alpha-flame-discovery-cover.png"
meta-image-alt="Cover artwork from 'The Alpha Flame: Discovery' by Catherine Lynwood" meta-image-alt="Cover artwork from 'The Alpha Flame: Discovery' by Catherine Lynwood"
og-site-name="Catherine Lynwood The Alpha Flame" og-site-name="Catherine Lynwood The Alpha Flame"
article-published-time="@new DateTime(2024, 11, 20)" article-published-time="@new DateTime(2024, 11, 20)"

View File

@ -162,7 +162,8 @@
meta-keywords="The Alpha Flame trilogy, Catherine Lynwood, 1980s fiction, family saga, twin sisters, Birmingham novel, suspense fiction, indie fiction series" meta-keywords="The Alpha Flame trilogy, Catherine Lynwood, 1980s fiction, family saga, twin sisters, Birmingham novel, suspense fiction, indie fiction series"
meta-author="Catherine Lynwood" meta-author="Catherine Lynwood"
meta-url="https://www.catherinelynwood.com/the-alpha-flame" meta-url="https://www.catherinelynwood.com/the-alpha-flame"
meta-image="https://www.catherinelynwood.com/images/webp/the-alpha-flame-trilogy-banner.webp" meta-image="https://www.catherinelynwood.com/images/webp/the-alpha-flame-discovery-cover-1200.webp"
meta-image-png="https://www.catherinelynwood.com/images/the-alpha-flame-discovery-cover.png"
meta-image-alt="The Alpha Flame trilogy banner image showing three covers of the series by Catherine Lynwood" meta-image-alt="The Alpha Flame trilogy banner image showing three covers of the series by Catherine Lynwood"
og-site-name="Catherine Lynwood - The Alpha Flame Trilogy" og-site-name="Catherine Lynwood - The Alpha Flame Trilogy"
article-published-time="@new DateTime(2024, 11, 20)" article-published-time="@new DateTime(2024, 11, 20)"