110 lines
No EOL
4.4 KiB
Python
110 lines
No EOL
4.4 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:
|
|
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)
|
|
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 |