| 
					
				 | 
			
			
				@@ -0,0 +1,106 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import { type Handler } from "aws-lambda"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import { createRestAPIClient } from "masto"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import ScraperArticles from "../utils/scraper-articles"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import RedisClient from "../libs/redis-client"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import LogLevels from "../enums/log-levels"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import Emojis from "../enums/emojis"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import config from "../config"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import { type IScraperArticlesOptions } from "../interfaces/article-scaper-options"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+export default class Portal { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  private readonly _name: string; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  private readonly _scraperArticlesOptions: IScraperArticlesOptions 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  private readonly _redisClient: RedisClient; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  private readonly _mastodonClient: any 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  private readonly _scraperArticles: ScraperArticles; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  constructor (name: string, scraperArticlesOptions: IScraperArticlesOptions) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    this._name = name; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    this._scraperArticlesOptions = scraperArticlesOptions; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    this._scraperArticles = new ScraperArticles(this._name, this._scraperArticlesOptions); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    this._redisClient = new RedisClient(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    this._mastodonClient = createRestAPIClient({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      url: config.MASTODON_URL, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      accessToken: config.MASTODON_ACCESS_TOKEN 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  public async run (event?: any, context?: any): Promise<void> { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    try { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const articles = await this._scraperArticles.getArticles(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (config.LOG_LEVEL === LogLevels.DEBUG) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        console.log(`${this._name} | Articles`, articles); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      let totalPublished = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const length = articles.length; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // Order has to be reversed to appear in the correct order when posting 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      for (let i = length - 1; i >= 0; i--) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        const article = articles[i]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        const exists = await this._redisClient.retrieve(article.link); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (exists !== null) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          continue; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        const date = new Date(Date.now()).toLocaleDateString(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let message = `${Emojis.NEWS} ${article.title}.`; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (article.content !== "") { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          message += `\n\n${article.content}`; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        message += `\n${article.link}`; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (message.trim().length === 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          continue; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // To avoid publiposts (I'm lookint at you La Tercera >:-|) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (article.link.includes("publirreportajes")) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          continue; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // If the message is more than 400 characters long, its very likely due to the article.content 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (message.length > 400) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          message = `${Emojis.NEWS} ${article.title}.\n\n${article.content}`.substring(0, 397) + "..."; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          message += `\n${article.link}`; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        const mediaIds: any[] = []; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (article.image !== null && article.image !== undefined) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          const media = await this._mastodonClient.v2.media.create({ file: article.image, description: article.title }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          mediaIds.push(media.id); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        console.log(`\n${this._name} | Sending`, message); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // await this._mastodonClient.v1.statuses.create({ status: message, mediaIds }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // await this._redisClient.store(article.link, date, { EX: 60 * 60 * 24 }); // EX: 24 hrs expiration 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        totalPublished++ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      console.log(`${this._name} | Published ${totalPublished} new articles`); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } catch (err: any) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      console.log(`${this._name} | An error has occurred\n`) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      console.error(err.message); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (config.LOG_LEVEL === LogLevels.DEBUG) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (event !== undefined) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          console.debug("\nEvent\n"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          console.debug(event); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (context !== undefined) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          console.debug("\nContext\n"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          console.debug(context); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    console.log(`${this._name} | Finished`); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  public getHandler (): Handler { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return async (event, context) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      await this.run(event, context); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 |