Переглянути джерело

Merge branch 'develop' of Mastodon/bots into main

Pablo Yaksic 1 тиждень тому
батько
коміт
7ebb164815

+ 14 - 2
.env.example

@@ -85,10 +85,22 @@ MASTODON_KEY_VIDEO_STREAMS = ""
 COUNTDOWN_EVENTS = ""
 
 # VIDEO STREAMS
-# Format: "Location|URL|hashtag1,hashtag2;Location2|URL2|hashtag3"
+# JSON array with the following structure:
+# [
+#   {
+#     "location": "Plaza Italia, Santiago",
+#     "url": "https://www.youtube.com/watch?v=...",
+#     "hashtags": ["Santiago", "Chile"],
+#     "screenshotSelector": "#movie_player",
+#     "clickSelector": ".ytp-large-play-button",
+#     "screenshotDelay": 10000
+#   }
+# ]
+# If screenshotSelector is not set, full page screenshot is taken.
+# If clickSelector is not set, no click is performed.
+# screenshotDelay is optional; falls back to VIDEO_STREAMS_SCREENSHOT_DELAY.
 VIDEO_STREAMS = ""
 VIDEO_STREAMS_SCREENSHOT_DELAY = 10000
-VIDEO_STREAMS_CLICK_SELECTOR = ".ytp-large-play-button"
 
 # OLLAMA
 OLLAMA_URL = "http://localhost:11434/api/generate"

+ 1 - 1
package.json

@@ -1,6 +1,6 @@
 {
   "name": "bot-noticias",
-  "version": "0.0.30",
+  "version": "0.0.31",
   "description": "Bot que busca noticias y las replica en mastodon.cl",
   "main": "dist/index.js",
   "scripts": {

+ 35 - 21
src/agents/video-streams/index.ts

@@ -12,14 +12,15 @@ interface IStreamConfig {
   location: string;
   url: string;
   hashtags: string[];
+  screenshotSelector?: string;
+  clickSelector?: string;
+  screenshotDelay?: number;
 }
 
 export default class VideoStreams {
   private readonly _name: string = "Video Streams";
   private readonly _mastodonClient: mastodon.rest.Client;
   private readonly _scraper: Scraper;
-  private readonly _selector: string = "#movie_player";
-  private readonly _clickSelector: string = config.VIDEO_STREAMS_CLICK_SELECTOR;
 
   constructor(accessToken = config.MASTODON_TEST_ACCESS_TOKEN) {
     accessToken = config.DEVELOP ? config.MASTODON_TEST_ACCESS_TOKEN : accessToken;
@@ -33,21 +34,26 @@ export default class VideoStreams {
       return [];
     }
 
-    const streams: IStreamConfig[] = [];
-    const streamPairs = streamsString.split(";");
-
-    streamPairs.forEach((streamPair) => {
-      const [location, url, hashTags] = streamPair.split("|");
-      if (location && url) {
-        streams.push({
-          location: location.trim(),
-          url: url.trim(),
-          hashtags: hashTags?.split(",").map((h) => h.trim()).filter((h) => h !== "") ?? []
-        });
+    try {
+      const parsed = JSON.parse(streamsString);
+      if (!Array.isArray(parsed)) {
+        throw new Error("VIDEO_STREAMS must be a JSON array");
       }
-    });
 
-    return streams;
+      return parsed.map((item: any) => ({
+        location: String(item.location ?? "").trim(),
+        url: String(item.url ?? "").trim(),
+        hashtags: Array.isArray(item.hashtags)
+          ? item.hashtags.map((h: unknown) => String(h).trim()).filter((h: string) => h !== "")
+          : [],
+        screenshotSelector: item.screenshotSelector !== undefined ? String(item.screenshotSelector).trim() : undefined,
+        clickSelector: item.clickSelector !== undefined ? String(item.clickSelector).trim() : undefined,
+        screenshotDelay: item.screenshotDelay !== undefined ? Number(item.screenshotDelay) : undefined
+      })).filter((stream) => stream.location !== "" && stream.url !== "");
+    } catch (err: any) {
+      console.error(`${this._name} | Error parsing VIDEO_STREAMS: ${err.message}`);
+      throw err;
+    }
   }
 
   private base64ToFile(base64: string, fileName: string): File {
@@ -98,14 +104,22 @@ export default class VideoStreams {
       for (const stream of streams) {
         console.log(`${this._name} | Capturing ${stream.location}`);
 
-        const response = await this._scraper.scrape({
+        const scrapeOptions: any = {
           url: stream.url,
           scraperMethod: ScraperMethods.PUPPETEER,
-          screenshotSelector: this._selector,
-          screenshotDelay: config.VIDEO_STREAMS_SCREENSHOT_DELAY,
-          clickSelector: this._clickSelector,
-          useProxy: true
-        });
+          screenshotDelay: stream.screenshotDelay ?? config.VIDEO_STREAMS_SCREENSHOT_DELAY
+        };
+
+        if (stream.screenshotSelector !== undefined && stream.screenshotSelector !== "") {
+          scrapeOptions.screenshot = true;
+          scrapeOptions.screenshotSelector = stream.screenshotSelector;
+        }
+
+        if (stream.clickSelector !== undefined && stream.clickSelector !== "") {
+          scrapeOptions.clickSelector = stream.clickSelector;
+        }
+
+        const response = await this._scraper.scrape(scrapeOptions);
 
         const screenshotBase64 = response?.data?.data?.screenshot;
 

+ 0 - 1
src/config.ts

@@ -85,7 +85,6 @@ const config = {
   COUNTDOWN_EVENTS: process.env.COUNTDOWN_EVENTS ?? "",
   VIDEO_STREAMS: process.env.VIDEO_STREAMS ?? "",
   VIDEO_STREAMS_SCREENSHOT_DELAY: Number(process.env.VIDEO_STREAMS_SCREENSHOT_DELAY ?? 10000),
-  VIDEO_STREAMS_CLICK_SELECTOR: process.env.VIDEO_STREAMS_CLICK_SELECTOR ?? ".ytp-large-play-button",
   // ANONYBOT Settings
   ANONYBOT_MAX_MESSAGE_LENGTH: process.env.ANONYBOT_MAX_MESSAGE_LENGTH ?? 500,
   ANONYBOT_RATE_LIMIT_HOURS: process.env.ANONYBOT_RATE_LIMIT_HOURS ?? 1,

+ 1 - 0
src/interfaces/scraper-options.ts

@@ -5,6 +5,7 @@ export interface IScraperOptions {
   userAgent?: string
   incognito?: boolean
   scraperMethod?: ScraperMethods
+  screenshot?: boolean
   screenshotSelector?: string
   screenshotDelay?: number
   clickSelector?: string

+ 2 - 2
src/utils/scraper.ts

@@ -17,7 +17,7 @@ export default class Scraper {
     if (this._options.scraperMethod == ScraperMethods.PUPPETEER) {
       console.debug(response.data.data.html);
       console.debug("\n");
-      console.debug("Screenshot (Base64)\n")
+      console.debug("Screenshot (Base64)\n");
       console.debug(response.data.data.screenshot);
     } else {
       console.debug(response.data);
@@ -66,7 +66,7 @@ export default class Scraper {
       if (this._options.scraperMethod == ScraperMethods.PUPPETEER) {
         const payload: any = {
           url: this._options.url,
-          screenshot: config.LOG_LEVEL === LogLevels.DEBUG || this._options.screenshotSelector !== undefined,
+          screenshot: this._options.screenshot === true || this._options.screenshotSelector !== undefined,
           incognito: this._options.incognito ?? false
         };