diff --git a/config.js b/config.js index 0e42e379a..034fcceec 100644 --- a/config.js +++ b/config.js @@ -136,6 +136,7 @@ og: "og", twitter: "twitter", oembed: "oembed", + ld: "ld", icon: "icon", logo: "logo", @@ -373,6 +374,18 @@ 'getSignals': 'signals', 'getPolicy': 'policy', 'getContent': 'content', + }, + + // Used to (re-)group LD+JSON into buckets + LD_TYPE_ALIASES: { + article: [ + 'Article' + ], + + image: [ + 'ImageObject', + 'Photograph' + ] } }; diff --git a/lib/utils.js b/lib/utils.js index 77c117541..fe8f93133 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -494,7 +494,7 @@ export function parseJSONSource(text, decode) { return JSON.parse(s); }; -export function parseLDSource(ld, decode, uri) { +export function parseLDSource(ld, decode, uri, type_aliases) { if (typeof ld === 'string') { try { @@ -505,7 +505,7 @@ export function parseLDSource(ld, decode, uri) { } } - if (!ld) return; + if (!ld) return; if (!(ld instanceof Array)) { if (!ld['@type'] && ld['@graph'] && Array.isArray(ld['@graph'])) { @@ -515,52 +515,70 @@ export function parseLDSource(ld, decode, uri) { } } - var ldParsed; + let ldParsed; - const addObject = function(obj) { + const getName = function(type) { + if (!type) return '-'; - const pushObj = function(id, obj) { - if (id) { + let name = String(type).toLowerCase().replace(/[^a-z0-9]/g, ''); + const TYPE_ALIASES = type_aliases || CONFIG.LD_TYPE_ALIASES; + if (TYPE_ALIASES) { + const alias = Object.keys(TYPE_ALIASES).find(alias => { + return TYPE_ALIASES[alias].some( + type => name === type.toLowerCase() || name.endsWith(type.toLowerCase()) + ); + }) + if (alias) { + name = alias; + } + } + return name; + } - if (!ldParsed) { - ldParsed = {}; - } + const pushObj = function(name, obj) { + if (name) { - if (!ldParsed[id]) { - ldParsed[id] = obj; - } else { - if (!Array.isArray(ldParsed[id])) { - ldParsed[id] = [ldParsed[id]]; - } - ldParsed[id].push(obj); + if (!ldParsed) { + ldParsed = {}; + } + + if (!ldParsed[name]) { + ldParsed[name] = obj; + + } else { + if (!Array.isArray(ldParsed[name])) { + ldParsed[name] = [ldParsed[name]]; } - } + ldParsed[name].push(obj); + } } + }; - if (Array.isArray(obj['@type'])) { - for (var i = 0; i < obj['@type'].length; i++) { - var type = obj['@type'][i]; - pushObj(type && type.toLowerCase && type.toLowerCase(), obj); - } - } else { - var type = obj && obj['@type']; - pushObj(type && type.toLowerCase && type.toLowerCase(), obj); + const addObject = function(obj) { + + if (!obj || !obj['@type']) { + return; } + + const type = Array.isArray(obj['@type']) ? obj['@type'][0] : obj['@type']; + const name = getName(type); + + pushObj(name, obj); }; - for (var i = 0; i < ld.length; i++) { + for (let i = 0; i < ld.length; i++) { try { - var str = ld[i]; - var obj = typeof str === 'string' ? parseJSONSource(str, decode) : str; + const str = ld[i]; + const obj = typeof str === 'string' ? parseJSONSource(str, decode) : str; if (Array.isArray(obj)) { - for(var j = 0; j < obj.length; j++) { + for(let j = 0; j < obj.length; j++) { addObject(obj[j]); } } else { addObject(obj); } - + } catch (ex) { log(' -- Error parsing ld-json', uri, ex.message); } diff --git a/plugins/domains/facebook.com/facebook.thumbnail.js b/plugins/domains/facebook.com/facebook.thumbnail.js index a8e18318a..dd32d7e1b 100644 --- a/plugins/domains/facebook.com/facebook.thumbnail.js +++ b/plugins/domains/facebook.com/facebook.thumbnail.js @@ -15,10 +15,7 @@ export default { getLink: function(url, __allowFBThumbnail, options, meta) { var thumbnail = meta.twitter?.image - || meta.og?.image - || meta.ld?.socialmediaposting?.image?.contenturl - || meta.ld?.socialmediaposting?.image && Array.isArray(meta.ld.socialmediaposting.image) // This one is for photos - && meta.ld.socialmediaposting.image.length === 1 && meta.ld.socialmediaposting.image[0].contenturl; + || meta.og?.image; if (thumbnail?.url || thumbnail?.src) { thumbnail = thumbnail.url || thumbnail.src; diff --git a/plugins/meta/ld-article-keywords.js b/plugins/meta/ld-article-keywords.js index d77b6c4a0..4e469478c 100644 --- a/plugins/meta/ld-article-keywords.js +++ b/plugins/meta/ld-article-keywords.js @@ -2,9 +2,9 @@ export default { getMeta: function(ld) { - if (ld.newsarticle && ld.newsarticle.keywords && ld.newsarticle.keywords instanceof Array) { + if (ld.article?.keywords && ld.article.keywords instanceof Array) { return { - keywords: ld.newsarticle.keywords.join(', ') + keywords: ld.article.keywords.join(', ') } } } diff --git a/plugins/meta/ld-article.js b/plugins/meta/ld-article.js index 418169b29..69807587c 100644 --- a/plugins/meta/ld-article.js +++ b/plugins/meta/ld-article.js @@ -14,27 +14,34 @@ export default { } } - if (ld.newsarticle) { + if (ld.article) { return { - title: clean(ld.newsarticle.headline), - category: clean(ld.newsarticle.articlesection), - description: clean(ld.newsarticle.description) + title: clean(ld.article.headline), + category: clean(ld.article.articlesection), + description: clean(ld.article.description) } } }, getLink: function(ld) { - if (ld.newsarticle && ld.newsarticle.thumbnailurl) { - return { - href: ld.newsarticle.thumbnailurl, - type: CONFIG.T.image, - rel: CONFIG.R.thumbnail - } + if (ld.article?.image) { + const images = Array.isArray(ld.article.image) ? ld.article.image : [ld.article.image] + const links = []; + + images.forEach(image => { + links.push({ + href: image.contenturl || image.url, + type: CONFIG.T.image, + rel: [CONFIG.R.thumbnail, CONFIG.R.ld], + alt: image.caption || image.name + }) + }); + + return links; } } // ex: - // http://www.app.com/story/entertainment/music/2017/03/17/springsteen-legacy-apmff-upstage-film-explores-1970-asbury-park/99313864/ - // https://www.nhl.com/video/oshie-buries-ppg-with-a-backhand/c-51625603?tcid=tw_video_content_id + // https://www.sabah.com.tr/yasam/2019/09/20/son-dakika-tuzladaki-yanginla-ilgili-flas-aciklama };