feat: add posting capabilities
This commit is contained in:
parent
01050792d0
commit
b84d0ba0af
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,6 +1,7 @@
|
||||
media/
|
||||
.secrets
|
||||
*.db
|
||||
imagebot.cfg
|
||||
|
||||
|
||||
# Byte-compiled / optimized / DLL files
|
||||
|
28
README.md
28
README.md
@ -11,3 +11,31 @@ ibot runserver
|
||||
```
|
||||
|
||||
Put images in `media/consume/`
|
||||
|
||||
|
||||
Add `ìmagebot.cfg` with
|
||||
|
||||
```cfg
|
||||
[imagebot]
|
||||
instance_name=ImageBot
|
||||
host=localhost
|
||||
|
||||
[django]
|
||||
secret=CHANGE-ME
|
||||
debug=True
|
||||
|
||||
[database]
|
||||
backend=sqlite3
|
||||
name=imagebot.sqlite3
|
||||
|
||||
[locations]
|
||||
media_root=./media/
|
||||
|
||||
[logging]
|
||||
app_log_level=INFO
|
||||
django_log_level=INFO
|
||||
|
||||
[fediverse]
|
||||
server = "example.org"
|
||||
token = "VERYSECRETTOKEN"
|
||||
```
|
94
idescriptor/bot.py
Normal file
94
idescriptor/bot.py
Normal file
@ -0,0 +1,94 @@
|
||||
import requests
|
||||
|
||||
from imagebot import settings
|
||||
from idescriptor.models import Image
|
||||
|
||||
|
||||
class FediClient:
|
||||
def __init__(self, access_token, api_base_url):
|
||||
"""
|
||||
:param access_token: Your server API access token.
|
||||
:param api_base_url: The base URL of the Fediverse instance (e.g., 'https://gay-pirate-assassins.de').
|
||||
"""
|
||||
self.access_token = access_token
|
||||
self.api_base_url = api_base_url.rstrip('/')
|
||||
self.headers = {
|
||||
'Authorization': f'Bearer {self.access_token}',
|
||||
}
|
||||
|
||||
def upload_media(self, image_path, alt_text):
|
||||
"""
|
||||
Uploads media (image) to the server and returns the media ID.
|
||||
:param image_path: Path to the image file to upload.
|
||||
:param alt_text: Description (alt text) for the image.
|
||||
:return: The media ID of the uploaded image.
|
||||
"""
|
||||
|
||||
media_endpoint = f'{self.api_base_url}/api/v2/media'
|
||||
|
||||
with open(image_path, 'rb') as image_file:
|
||||
files = {
|
||||
'file': image_file,
|
||||
'description': (None, alt_text)
|
||||
}
|
||||
response = requests.post(media_endpoint, headers=self.headers, files=files)
|
||||
|
||||
# Raise exception if upload fails
|
||||
response.raise_for_status()
|
||||
|
||||
# Parse and return the media ID from the response
|
||||
media_id = response.json().get('id')
|
||||
return media_id
|
||||
|
||||
def post_status(self, status, media_ids=None):
|
||||
"""
|
||||
Posts a status to Mastodon with optional media.
|
||||
:param status: The text of the status to post.
|
||||
:param media_ids: A list of media IDs to attach to the status (optional).
|
||||
:return: The response from the Mastodon API.
|
||||
"""
|
||||
status_endpoint = f'{self.api_base_url}/api/v1/statuses'
|
||||
|
||||
payload = {
|
||||
'status': status,
|
||||
'media_ids[]': media_ids if media_ids else []
|
||||
}
|
||||
response = requests.post(status_endpoint, headers=self.headers, data=payload)
|
||||
|
||||
# Raise exception if posting fails
|
||||
response.raise_for_status()
|
||||
|
||||
return response.json()
|
||||
|
||||
def post_status_with_image(self, status, image_path, alt_text):
|
||||
"""
|
||||
Uploads an image, then posts a status with that image and alt text.
|
||||
:param status: The text of the status.
|
||||
:param image_path: The path to the image file.
|
||||
:param alt_text: The alt text for the image.
|
||||
:return: The response from the Mastodon API.
|
||||
"""
|
||||
# Upload the image and get the media ID
|
||||
media_id = self.upload_media(image_path, alt_text)
|
||||
|
||||
# Post the status with the uploaded image's media ID
|
||||
return self.post_status(status, media_ids=[media_id])
|
||||
|
||||
|
||||
def post():
|
||||
ACCESS_TOKEN = settings.FEDIVERSE_TOKEN
|
||||
API_BASE_URL = f"https://{settings.FEDIVERSE_SERVER}"
|
||||
client = FediClient(ACCESS_TOKEN, API_BASE_URL)
|
||||
|
||||
image = Image.get_image_to_post()
|
||||
|
||||
status_text = image.title
|
||||
image_path = f"{settings.MEDIA_ROOT}/{image.image}"
|
||||
alt_text = image.alt_text
|
||||
|
||||
response = client.post_status_with_image(status_text, image_path, alt_text)
|
||||
print(response)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
post()
|
13
idescriptor/management/commands/post.py
Normal file
13
idescriptor/management/commands/post.py
Normal file
@ -0,0 +1,13 @@
|
||||
from django.core.management import BaseCommand
|
||||
from idescriptor.bot import post
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = 'Post an image'
|
||||
|
||||
def add_arguments(self, parser):
|
||||
# Named (optional) arguments
|
||||
pass
|
||||
|
||||
def handle(self, *args, **options):
|
||||
print(post())
|
@ -83,6 +83,9 @@ MEDIA_PROCESSED_DIR_RELATIVE = Path("processed") # Relative to MEDIA_ROOT
|
||||
|
||||
CRISPY_TEMPLATE_PACK = 'bootstrap4'
|
||||
|
||||
FEDIVERSE_SERVER = config.get('fediverse', 'server')
|
||||
FEDIVERSE_TOKEN = config.get('fediverse', 'token')
|
||||
|
||||
# Application definition
|
||||
|
||||
INSTALLED_APPS = [
|
||||
|
@ -22,6 +22,7 @@ crispy-bootstrap4 = "*"
|
||||
|
||||
[tool.poetry.scripts]
|
||||
ibot = 'imagebot.manage:main'
|
||||
ibotpost = 'idescriptor.bot:main'
|
||||
|
||||
|
||||
[tool.poetry.group.test.dependencies]
|
||||
|
Loading…
Reference in New Issue
Block a user