14 socials integration #34

Merged
Nunzi99 merged 12 commits from 14-socials-integration into main 2025-10-20 16:56:11 +02:00
5 changed files with 23 additions and 68 deletions
Showing only changes of commit 6b71a5a553 - Show all commits

View File

@@ -2,6 +2,8 @@
# Infatti scegliamo l'immagine ufficiale di uv che ha già tutto configurato # Infatti scegliamo l'immagine ufficiale di uv che ha già tutto configurato
FROM ghcr.io/astral-sh/uv:python3.12-alpine FROM ghcr.io/astral-sh/uv:python3.12-alpine
RUN apk add --update npm
RUN npm install -g rettiwt-api
# Dopo aver definito la workdir mi trovo già in essa # Dopo aver definito la workdir mi trovo già in essa
WORKDIR /app WORKDIR /app

View File

@@ -38,7 +38,6 @@ dependencies = [
Berack96 commented 2025-10-19 16:12:15 +02:00 (Migrated from github.com)
Review

Come per il file x.py, è meglio usare direttamente il comando della CMD

Come per il file x.py, è meglio usare direttamente il comando della CMD
# API di social media # API di social media
"praw", # Reddit "praw", # Reddit
"docker", # Necessario per usare Rettiwt per X
] ]
[tool.pytest.ini_options] [tool.pytest.ini_options]

View File

@@ -43,97 +43,60 @@ class ChanWrapper(SocialWrapper):
if 'sticky' in thread: if 'sticky' in thread:
continue continue
else: else:
# print(thread)
# Otteniamo la data
time: str = thread['now'] time: str = thread['now']
# Otteniamo dalla data il mese (primi 2 caratteri)
month: str = time[:2] month: str = time[:2]
# Otteniamo dalla data il giorno (caratteri 4 e 5)
day: str = time[4:6] day: str = time[4:6]
# Otteniamo dalla data l'anno (caratteri 7 e 8)
year: str = time[7:9] year: str = time[7:9]
# Ricreiamo la data completa come dd/mm/yy
time: str = day + '/' + month + '/' + year time: str = day + '/' + month + '/' + year
# Otteniamo il nome dell'utente
name: str = thread['name'] name: str = thread['name']
# Proviamo a recuperare il titolo
try: try:
# Otteniamo il titolo del thread contenuto nella key "sub"
title: str = thread['sub'] title: str = thread['sub']
# Ripuliamo la stringa
# Decodifichiamo caratteri ed entità HTML
html_entities = html.unescape(title) html_entities = html.unescape(title)
# Rimuoviamo caratteri HTML
soup = BeautifulSoup(html_entities, 'html.parser') soup = BeautifulSoup(html_entities, 'html.parser')
title = soup.get_text(separator=" ") title = soup.get_text(separator=" ")
# Rimuoviamo backlash e doppi slash
title = re.sub(r"[\\/]+", "/", title) title = re.sub(r"[\\/]+", "/", title)
# Rimuoviamo spazi in piú
title = re.sub(r"\s+", " ", title).strip() title = re.sub(r"\s+", " ", title).strip()
# Aggiungiamo il nome dell'utente al titolo
title = name + " posted: " + title title = name + " posted: " + title
except: except:
title: str = name + " posted" title: str = name + " posted"
try: try:
# Otteniamo il commento del thread contenuto nella key "com"
thread_description: str = thread['com'] thread_description: str = thread['com']
# Ripuliamo la stringa
# Decodifichiamo caratteri ed entità HTML
html_entities = html.unescape(thread_description) html_entities = html.unescape(thread_description)
# Rimuoviamo caratteri HTML
soup = BeautifulSoup(html_entities, 'html.parser') soup = BeautifulSoup(html_entities, 'html.parser')
thread_description = soup.get_text(separator=" ") thread_description = soup.get_text(separator=" ")
# Rimuoviamo backlash e doppi slash
thread_description = re.sub(r"[\\/]+", "/", thread_description) thread_description = re.sub(r"[\\/]+", "/", thread_description)
# Rimuoviamo spazi in piú
thread_description = re.sub(r"\s+", " ", thread_description).strip() thread_description = re.sub(r"\s+", " ", thread_description).strip()
except: except:
thread_description = None thread_description = None
# Creiamo la lista delle risposte al thread
try: try:
response_list: list[dict] = thread['last_replies'] response_list: list[dict] = thread['last_replies']
except: except:
response_list: list[dict] = [] response_list: list[dict] = []
# Creiamo la lista che conterrà i commenti
comments_list: list[SocialComment] = [] comments_list: list[SocialComment] = []
# Otteniamo i primi 5 commenti # Otteniamo i primi 5 commenti
i = 0 i = 0
for response in response_list: for response in response_list:
# Otteniamo la data
time: str = response['now'] time: str = response['now']
# print(time)
# Otteniamo dalla data il mese (primi 2 caratteri)
month: str = time[:2] month: str = time[:2]
# Otteniamo dalla data il giorno (caratteri 4 e 5)
day: str = time[3:5] day: str = time[3:5]
# Otteniamo dalla data l'anno (caratteri 7 e 8)
year: str = time[6:8] year: str = time[6:8]
# Ricreiamo la data completa come dd/mm/yy
time: str = day + '/' + month + '/' + year time: str = day + '/' + month + '/' + year
try: try:
# Otteniamo il commento della risposta contenuto nella key "com"
comment_description: str = response['com'] comment_description: str = response['com']
# Ripuliamo la stringa
# Decodifichiamo caratteri ed entità HTML
html_entities = html.unescape(comment_description) html_entities = html.unescape(comment_description)
# Rimuoviamo caratteri HTML
soup = BeautifulSoup(html_entities, 'html.parser') soup = BeautifulSoup(html_entities, 'html.parser')
comment_description = soup.get_text(separator=" ") comment_description = soup.get_text(separator=" ")
# Rimuoviamo backlash e doppi slash
comment_description = re.sub(r"[\\/]+", "/", comment_description) comment_description = re.sub(r"[\\/]+", "/", comment_description)
# Rimuoviamo spazi in piú
comment_description = re.sub(r"\s+", " ", comment_description).strip() comment_description = re.sub(r"\s+", " ", comment_description).strip()
except: except:
comment_description = None comment_description = None
# Se la descrizione del commento non esiste, passiamo al commento successivo
if comment_description is None: if comment_description is None:
continue continue
else: else:
# Creiamo il SocialComment
social_comment: SocialComment = SocialComment( social_comment: SocialComment = SocialComment(
time=time, time=time,
description=comment_description description=comment_description
@@ -145,7 +108,6 @@ class ChanWrapper(SocialWrapper):
if thread_description is None: if thread_description is None:
continue continue
else: else:
# Creiamo il SocialPost
social_post: SocialPost = SocialPost( social_post: SocialPost = SocialPost(
time=time, time=time,
title=title, title=title,

View File

@@ -6,9 +6,10 @@ https://www.npmjs.com/package/rettiwt-api
''' '''
import os import os
import docker
import json import json
from .base import SocialWrapper, SocialPost, SocialComment from .base import SocialWrapper, SocialPost
from shutil import which
import subprocess
class XWrapper(SocialWrapper): class XWrapper(SocialWrapper):
def __init__(self): def __init__(self):
''' '''
@@ -26,10 +27,13 @@ class XWrapper(SocialWrapper):
] ]
self.api_key = os.getenv("X_API_KEY") self.api_key = os.getenv("X_API_KEY")
assert self.api_key, "X_API_KEY environment variable not set" assert self.api_key, "X_API_KEY environment variable not set"
'''
# Connection to the docker deamon # Connection to the docker deamon
self.client = docker.from_env() self.client = docker.from_env()
# Connect with the relative container # Connect with the relative container
self.container = self.client.containers.get("node_rettiwt") self.container = self.client.containers.get("node_rettiwt")
'''
assert which('rettiwt') is not None, "Command `rettiwt` not installed"
self.social_posts: list[SocialPost] = [] self.social_posts: list[SocialPost] = []
def get_top_crypto_posts(self, limit = 5) -> list[SocialPost]: #-> list[SocialPost]: def get_top_crypto_posts(self, limit = 5) -> list[SocialPost]: #-> list[SocialPost]:
''' '''
@@ -38,7 +42,8 @@ class XWrapper(SocialWrapper):
social_posts: list[SocialPost] = [] social_posts: list[SocialPost] = []
for user in self.users: for user in self.users:
# This currently doesn't work as intended since it returns the posts in random order # This currently doesn't work as intended since it returns the posts in random order
tweets = self.container.exec_run("rettiwt -k" + self.api_key + " tweet search -f " + str(user), tty=True) # tweets = self.container.exec_run("rettiwt -k" + self.api_key + " tweet search -f " + str(user), tty=True)
tweets = subprocess.run("rettiwt -k" + self.api_key + " tweet search -f " + str(user))
tweets = tweets.output.decode() tweets = tweets.output.decode()
tweets = json.loads(tweets) tweets = json.loads(tweets)
tweets: list[dict] = tweets['list'] tweets: list[dict] = tweets['list']

39
uv.lock generated
View File

@@ -377,6 +377,17 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/40/cd/ef820662e0d87f46b829bba7e2324c7978e0153692bbd2f08f7746049708/ddgs-9.6.0-py3-none-any.whl", hash = "sha256:24120f1b672fd3a28309db029e7038eb3054381730aea7a08d51bb909dd55520", size = 41558, upload-time = "2025-09-17T13:27:08.99Z" }, { url = "https://files.pythonhosted.org/packages/40/cd/ef820662e0d87f46b829bba7e2324c7978e0153692bbd2f08f7746049708/ddgs-9.6.0-py3-none-any.whl", hash = "sha256:24120f1b672fd3a28309db029e7038eb3054381730aea7a08d51bb909dd55520", size = 41558, upload-time = "2025-09-17T13:27:08.99Z" },
] ]
[[package]]
name = "deepseek"
version = "1.0.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "requests" },
]
wheels = [
{ url = "https://files.pythonhosted.org/packages/04/7b/bede06edf1a25a6ab06553b15f6abf8e912848dfa5f68514720d3e388550/deepseek-1.0.0-py3-none-any.whl", hash = "sha256:ee4175bfcb7ac1154369dbd86a4d8bc1809f6fa20e3e7baa362544567197cb3f", size = 4542, upload-time = "2025-01-03T08:06:23.887Z" },
]
[[package]] [[package]]
name = "distro" name = "distro"
version = "1.9.0" version = "1.9.0"
@@ -395,20 +406,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl", hash = "sha256:01d9bbc4a2d76bf0db7c1f729812ded6d912bd318d3b1cf81d30c0f845dbf3af", size = 331094, upload-time = "2025-09-07T18:57:58.071Z" }, { url = "https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl", hash = "sha256:01d9bbc4a2d76bf0db7c1f729812ded6d912bd318d3b1cf81d30c0f845dbf3af", size = 331094, upload-time = "2025-09-07T18:57:58.071Z" },
] ]
[[package]]
name = "docker"
version = "7.1.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "pywin32", marker = "sys_platform == 'win32'" },
{ name = "requests" },
{ name = "urllib3" },
]
sdist = { url = "https://files.pythonhosted.org/packages/91/9b/4a2ea29aeba62471211598dac5d96825bb49348fa07e906ea930394a83ce/docker-7.1.0.tar.gz", hash = "sha256:ad8c70e6e3f8926cb8a92619b832b4ea5299e2831c14284663184e200546fa6c", size = 117834, upload-time = "2024-05-23T11:13:57.216Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/e3/26/57c6fb270950d476074c087527a558ccb6f4436657314bfb6cdf484114c4/docker-7.1.0-py3-none-any.whl", hash = "sha256:c96b93b7f0a746f9e77d325bcfb87422a3d8bd4f03136ae8a85b37f1898d5fc0", size = 147774, upload-time = "2024-05-23T11:13:55.01Z" },
]
[[package]] [[package]]
name = "docstring-parser" name = "docstring-parser"
version = "0.17.0" version = "0.17.0"
@@ -1360,16 +1357,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/81/c4/34e93fe5f5429d7570ec1fa436f1986fb1f00c3e0f43a589fe2bbcd22c3f/pytz-2025.2-py2.py3-none-any.whl", hash = "sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00", size = 509225, upload-time = "2025-03-25T02:24:58.468Z" }, { url = "https://files.pythonhosted.org/packages/81/c4/34e93fe5f5429d7570ec1fa436f1986fb1f00c3e0f43a589fe2bbcd22c3f/pytz-2025.2-py2.py3-none-any.whl", hash = "sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00", size = 509225, upload-time = "2025-03-25T02:24:58.468Z" },
] ]
[[package]]
name = "pywin32"
version = "311"
source = { registry = "https://pypi.org/simple" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/e7/ab/01ea1943d4eba0f850c3c61e78e8dd59757ff815ff3ccd0a84de5f541f42/pywin32-311-cp312-cp312-win32.whl", hash = "sha256:750ec6e621af2b948540032557b10a2d43b0cee2ae9758c54154d711cc852d31", size = 8706543, upload-time = "2025-07-14T20:13:20.765Z" },
{ url = "https://files.pythonhosted.org/packages/d1/a8/a0e8d07d4d051ec7502cd58b291ec98dcc0c3fff027caad0470b72cfcc2f/pywin32-311-cp312-cp312-win_amd64.whl", hash = "sha256:b8c095edad5c211ff31c05223658e71bf7116daa0ecf3ad85f3201ea3190d067", size = 9495040, upload-time = "2025-07-14T20:13:22.543Z" },
{ url = "https://files.pythonhosted.org/packages/ba/3a/2ae996277b4b50f17d61f0603efd8253cb2d79cc7ae159468007b586396d/pywin32-311-cp312-cp312-win_arm64.whl", hash = "sha256:e286f46a9a39c4a18b319c28f59b61de793654af2f395c102b4f819e584b5852", size = 8710102, upload-time = "2025-07-14T20:13:24.682Z" },
]
[[package]] [[package]]
name = "pyyaml" name = "pyyaml"
version = "6.0.3" version = "6.0.3"
@@ -1677,7 +1664,7 @@ dependencies = [
{ name = "agno" }, { name = "agno" },
{ name = "coinbase-advanced-py" }, { name = "coinbase-advanced-py" },
{ name = "ddgs" }, { name = "ddgs" },
{ name = "docker" }, { name = "deepseek" },
{ name = "dotenv" }, { name = "dotenv" },
{ name = "gnews" }, { name = "gnews" },
{ name = "google-genai" }, { name = "google-genai" },
@@ -1696,7 +1683,7 @@ requires-dist = [
{ name = "agno" }, { name = "agno" },
{ name = "coinbase-advanced-py" }, { name = "coinbase-advanced-py" },
{ name = "ddgs" }, { name = "ddgs" },
{ name = "docker" }, { name = "deepseek" },
{ name = "dotenv" }, { name = "dotenv" },
{ name = "gnews" }, { name = "gnews" },
{ name = "google-genai" }, { name = "google-genai" },