Created
May 12, 2025 09:51
-
-
Save abesmon/40dde63b8c0199927d6ba4d464d8ea32 to your computer and use it in GitHub Desktop.
# Image Uploader Скрипт для загрузки изображений на ImgBB и FreeImage. Использует только стандартную библиотеку Python. ## Использование ```bash python image_uploader.py путь_к_изображению --service [imgbb|freeimage] [--expiration время_в_секундах] ``` Требуется файл `.env` с API ключами: ```env IMG_BB_API_KEY=ваш_ключ FREEIMAGE_API_KEY=ваш_ключ…
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import os | |
import base64 | |
import json | |
import urllib.request | |
import urllib.parse | |
import urllib.error | |
import argparse | |
import logging | |
from pathlib import Path | |
from typing import Optional, Dict, Any | |
# Настройка логирования | |
logging.basicConfig( | |
level=logging.INFO, | |
format='%(asctime)s - %(levelname)s - %(message)s' | |
) | |
logger = logging.getLogger(__name__) | |
def load_env_file(env_path: str = ".env") -> None: | |
""" | |
Загружает переменные окружения из файла .env | |
Args: | |
env_path: Путь к файлу .env (по умолчанию ".env") | |
""" | |
try: | |
if not os.path.exists(env_path): | |
logger.warning(f"Файл {env_path} не найден") | |
return | |
with open(env_path, 'r', encoding='utf-8') as file: | |
for line in file: | |
line = line.strip() | |
if not line or line.startswith('#'): | |
continue | |
try: | |
key, value = line.split('=', 1) | |
key = key.strip() | |
value = value.strip() | |
# Удаляем кавычки, если они есть | |
if (value.startswith('"') and value.endswith('"')) or \ | |
(value.startswith("'") and value.endswith("'")): | |
value = value[1:-1] | |
os.environ[key] = value | |
except ValueError: | |
logger.warning(f"Пропущена некорректная строка в {env_path}: {line}") | |
except Exception as e: | |
logger.error(f"Ошибка при загрузке {env_path}: {e}") | |
# Загрузка переменных окружения | |
load_env_file() | |
# Получение API ключей из переменных окружения | |
IMG_BB_API_KEY = os.getenv("IMG_BB_API_KEY") | |
FREEIMAGE_API_KEY = os.getenv("FREEIMAGE_API_KEY") | |
class ImageUploadError(Exception): | |
"""Базовый класс для ошибок загрузки изображений""" | |
pass | |
def read_image_file(image_path: str) -> bytes: | |
""" | |
Читает файл изображения и возвращает его содержимое в виде байтов. | |
Args: | |
image_path: Путь к файлу изображения | |
Returns: | |
bytes: Содержимое файла в виде байтов | |
Raises: | |
ImageUploadError: Если файл не существует или не может быть прочитан | |
""" | |
try: | |
with open(image_path, "rb") as file: | |
return file.read() | |
except Exception as e: | |
raise ImageUploadError(f"Ошибка при чтении файла: {e}") | |
def upload_image( | |
image_path: str, | |
service: str, | |
expiration: int = 180 | |
) -> Optional[str]: | |
""" | |
Загружает изображение на выбранный сервис хостинга. | |
Args: | |
image_path: Путь к файлу изображения | |
service: Сервис хостинга ('imgbb' или 'freeimage') | |
expiration: Время жизни изображения в секундах | |
Returns: | |
Optional[str]: URL загруженного изображения или None в случае ошибки | |
""" | |
try: | |
image_data = read_image_file(image_path) | |
encoded_image = base64.b64encode(image_data) | |
if service == "imgbb": | |
if not IMG_BB_API_KEY: | |
raise ImageUploadError("IMG_BB_API_KEY не установлен") | |
return upload_to_imgbb(encoded_image, expiration) | |
elif service == "freeimage": | |
if not FREEIMAGE_API_KEY: | |
raise ImageUploadError("FREEIMAGE_API_KEY не установлен") | |
return upload_to_freeimage(encoded_image, expiration) | |
else: | |
raise ImageUploadError(f"Неизвестный сервис: {service}") | |
except ImageUploadError as e: | |
logger.error(str(e)) | |
return None | |
except Exception as e: | |
logger.error(f"Неожиданная ошибка: {e}") | |
return None | |
def upload_to_imgbb(image_data: bytes, expiration: int) -> Optional[str]: | |
"""Загружает изображение на ImgBB""" | |
url = "https://api.imgbb.com/1/upload" | |
payload = { | |
"key": IMG_BB_API_KEY, | |
"image": image_data, | |
"expiration": expiration | |
} | |
try: | |
data = urllib.parse.urlencode(payload).encode('utf-8') | |
req = urllib.request.Request(url, data=data, method='POST') | |
with urllib.request.urlopen(req) as response: | |
result = json.loads(response.read().decode('utf-8')) | |
return result["data"]["url"] | |
except urllib.error.HTTPError as e: | |
raise ImageUploadError(f"Ошибка загрузки на ImgBB: {e.code}, {e.read().decode('utf-8')}") | |
except urllib.error.URLError as e: | |
raise ImageUploadError(f"Ошибка сети при загрузке на ImgBB: {e.reason}") | |
def upload_to_freeimage(image_data: bytes, expiration: int) -> Optional[str]: | |
"""Загружает изображение на FreeImage""" | |
url = "https://freeimage.host/api/1/upload" | |
payload = { | |
"key": FREEIMAGE_API_KEY, | |
"source": image_data, | |
"expiration": expiration | |
} | |
try: | |
data = urllib.parse.urlencode(payload).encode('utf-8') | |
req = urllib.request.Request(url, data=data, method='POST') | |
with urllib.request.urlopen(req) as response: | |
result = json.loads(response.read().decode('utf-8')) | |
return result["image"]["url"] | |
except urllib.error.HTTPError as e: | |
raise ImageUploadError(f"Ошибка загрузки на FreeImage: {e.code}, {e.read().decode('utf-8')}") | |
except urllib.error.URLError as e: | |
raise ImageUploadError(f"Ошибка сети при загрузке на FreeImage: {e.reason}") | |
def validate_image_path(image_path: str) -> bool: | |
"""Проверяет существование и доступность файла изображения""" | |
path = Path(image_path) | |
return path.is_file() and path.stat().st_size > 0 | |
def main() -> None: | |
parser = argparse.ArgumentParser(description="Загрузка изображения на сервис хостинга") | |
parser.add_argument("image_path", help="Путь к файлу изображения") | |
parser.add_argument( | |
"--service", | |
choices=["imgbb", "freeimage"], | |
required=True, | |
help="Сервис хостинга изображений" | |
) | |
parser.add_argument( | |
"--expiration", | |
type=int, | |
default=180, | |
help="Время жизни изображения в секундах (по умолчанию: 180)" | |
) | |
args = parser.parse_args() | |
if not validate_image_path(args.image_path): | |
logger.error("Ошибка: Файл не существует или пуст") | |
return | |
url = upload_image(args.image_path, args.service, args.expiration) | |
if url: | |
logger.info(f"Изображение успешно загружено: {url}") | |
else: | |
logger.error("Не удалось загрузить изображение") | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment