minitch/lib/handlers.py
2022-11-27 20:26:14 +01:00

113 lines
No EOL
4.5 KiB
Python

import os.path
import hashlib
from typing import Literal
import requests
from lib import itch
from prettytable import PrettyTable
from tqdm import tqdm
class HandlerException(Exception):
pass
class GameHandler:
OUTPUT_FORMATS = Literal['table', 'json']
OS_TYPES = Literal['linux', 'osx', 'windows']
def __init__(self, api_key, output_format: OUTPUT_FORMATS ='table'):
self.__itch_client = itch.Client(api_key)
self.__output_format = output_format
def __print_table(self, table: PrettyTable):
if self.__output_format == 'table':
return print(table)
if self.__output_format == 'json':
return print(table.get_json_string())
def find(self, query: str):
games = self.__itch_client.find_game(query)
table = PrettyTable(header=True, align='l', autowrap=False)
table.field_names = ['ID', 'Title', 'Description', 'URL', 'Purchaseable', 'Min price', 'Linux', 'Windows', 'OSX']
for game in games:
table.add_row([
game['id'],
game['title'] if 'title' in game else '-',
game['short_text'] if 'short_text' in game else '-',
game['url'] if 'url' in game else '-',
'yes' if game['can_be_bought'] == True else 'no',
float(game['min_price']) / 100,
'yes' if game['p_linux'] == True else 'no',
'yes' if game['p_windows'] == True else 'no',
'yes' if game['p_osx'] == True else 'no'
])
self.__print_table(table)
def uploads(self, game_id: int):
uploads = self.__itch_client.game_uploads(game_id)
table = PrettyTable(header=True, align='l', autowrap=False)
table.field_names = ['ID', 'File Name', 'Last Update', 'Size', 'MD5', 'Linux', 'Windows', 'OSX']
for upload in uploads:
table.add_row([
upload['id'],
upload['filename'] if 'filename' in upload else '-',
upload['updated_at'] if 'updated_at' in upload else '-',
upload['size'] if 'size' in upload else '-',
upload['md5_hash'] if 'md5_hash' in upload else '-',
'yes' if upload['p_linux'] == True else 'no',
'yes' if upload['p_windows'] == True else 'no',
'yes' if upload['p_osx'] == True else 'no'
])
self.__print_table(table)
def download(self, game_id: int, dst_dir: str, os_type: OS_TYPES = 'linux'):
meta = self.__itch_client.game_meta(game_id)
uploads = self.__itch_client.game_uploads(game_id)
for upload in uploads:
if upload[f'p_{os_type}'] == True:
try:
url = self.__itch_client.game_url(upload['id'])
dst = os.path.join(dst_dir, upload['filename'])
# Download game
md5 = hashlib.md5()
with requests.get(url, stream=True) as r:
r.raise_for_status()
total_size = int(r.headers.get('content-length', 0))
with tqdm.wrapattr(open(dst, 'wb'), 'write', miniters=1, desc='Downloading game', total=total_size) as f:
for chunk in r.iter_content(chunk_size=8192):
f.write(chunk)
md5.update(chunk)
if 'md5_hash' in upload and md5.hexdigest() != upload['md5_hash']:
raise HandlerException('Invalid checksum')
return (dst, upload, meta)
except itch.API_ERROR as err:
raise HandlerException(str(err))
raise HandlerException('No valid upload found')
def list_local(self, games):
table = PrettyTable(header=True, align='l', autowrap=False)
table.field_names = ['ID', 'Title', 'Description', 'URL', 'Last update', 'Installation path']
for id, game in games.items():
table.add_row([
id,
game['title'],
game['description'],
game['url'],
game['last_update'],
game['path']
])
self.__print_table(table)
def check_update(self, game_id, last_update, os_type: OS_TYPES = 'linux'):
uploads = self.__itch_client.game_uploads(game_id)
for upload in uploads:
if upload[f'p_{os_type}'] == True:
return upload['updated_at'] != last_update