crawlforge-extractors 1.2.0 → 1.2.1

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/templates.js +18 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "crawlforge-extractors",
3
- "version": "1.2.0",
3
+ "version": "1.2.1",
4
4
  "description": "Extraction logic shared by the CrawlForge MCP server and REST API — scrape templates, charset-correct capped body reading, and structural fingerprinting. One implementation, so the two surfaces cannot drift apart.",
5
5
  "type": "module",
6
6
  "main": "./index.js",
package/src/templates.js CHANGED
@@ -172,6 +172,22 @@ function fullSizeImage(src) {
172
172
  return src.replace(/\._[^/]*_\.(jpe?g|png|gif)$/i, ".$1");
173
173
  }
174
174
 
175
+ // ── YouTube helpers ──────────────────────────────────────────────────────────
176
+
177
+ /**
178
+ * Views and likes are both userInteractionCount; only the sibling
179
+ * interactionType tells them apart, and YouTube emits the LikeAction counter
180
+ * first — so reading the attribute directly returns likes where views are
181
+ * meant. There is no interactionCount attribute on the page at all.
182
+ */
183
+ function youtubeInteractionCount($, action) {
184
+ const counter = $('[itemprop="interactionStatistic"]')
185
+ .filter((_, el) => ($(el).find('[itemprop="interactionType"]').attr('content') || '').split('/').pop() === action)
186
+ .first();
187
+ const count = counter.find('[itemprop="userInteractionCount"]').attr('content');
188
+ return count ? Number.parseInt(count, 10) : null;
189
+ }
190
+
175
191
  // ── Template definitions ─────────────────────────────────────────────────────
176
192
 
177
193
  export const TEMPLATES = [
@@ -360,7 +376,8 @@ export const TEMPLATES = [
360
376
  title: attr($, 'meta[name="title"]', 'content') || attr($, 'meta[property="og:title"]', 'content'),
361
377
  channel: attr($, 'link[itemprop="name"]', 'content') || text($, '#channel-name'),
362
378
  channel_url: attr($, 'span[itemprop="author"] link[itemprop="url"]', 'href'),
363
- views: attr($, 'meta[itemprop="interactionCount"]', 'content'),
379
+ views: youtubeInteractionCount($, 'WatchAction'),
380
+ likes: youtubeInteractionCount($, 'LikeAction'),
364
381
  published: attr($, 'meta[itemprop="uploadDate"]', 'content') || attr($, 'meta[itemprop="datePublished"]', 'content'),
365
382
  description: attr($, 'meta[property="og:description"]', 'content'),
366
383
  thumbnail: attr($, 'meta[property="og:image"]', 'content'),