mirror of
https://github.com/Emersont1/itchio.git
synced 2026-03-11 08:54:39 +00:00
Added CIs (And applied Autopep8 fixes) (#18)
* Added CIs * autopep8 action fixes (#19) Co-authored-by: Emersont1 <Emersont1@users.noreply.github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Emersont1 <Emersont1@users.noreply.github.com>
This commit is contained in:
parent
68c30fd32d
commit
36498a88b4
10 changed files with 119 additions and 43 deletions
31
.github/workflows/autopep8.yml
vendored
Normal file
31
.github/workflows/autopep8.yml
vendored
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
name: autopep8
|
||||
on: pull_request
|
||||
jobs:
|
||||
autopep8:
|
||||
# Check if the PR is not raised by this workflow and is not from a fork
|
||||
if: startsWith(github.head_ref, 'autopep8-patches') == false && github.event.pull_request.head.repo.full_name == github.repository
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
ref: ${{ github.head_ref }}
|
||||
- name: autopep8
|
||||
id: autopep8
|
||||
uses: peter-evans/autopep8@v1
|
||||
with:
|
||||
args: --exit-code --recursive --in-place --aggressive --aggressive .
|
||||
- name: Set autopep8 branch name
|
||||
id: vars
|
||||
run: echo ::set-output name=branch-name::"autopep8-patches/${{ github.head_ref }}"
|
||||
- name: Create Pull Request
|
||||
if: steps.autopep8.outputs.exit-code == 2
|
||||
uses: peter-evans/create-pull-request@v3
|
||||
with:
|
||||
commit-message: autopep8 action fixes
|
||||
title: Fixes by autopep8 action
|
||||
body: This is an auto-generated PR with fixes by autopep8.
|
||||
labels: autopep8, automated pr
|
||||
branch: ${{ steps.vars.outputs.branch-name }}
|
||||
- name: Fail if autopep8 made changes
|
||||
if: steps.autopep8.outputs.exit-code == 2
|
||||
run: exit 1
|
||||
14
.github/workflows/poetry-publish.yml
vendored
Normal file
14
.github/workflows/poetry-publish.yml
vendored
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
name: Python package
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "v*.*.*"
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Build and publish to pypi
|
||||
uses: JRubics/poetry-publish@v1.10
|
||||
with:
|
||||
pypi_token: ${{ secrets.PYPI_TOKEN }}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
from .login import LoginWeb, LoginAPI
|
||||
from .bundle import Bundle
|
||||
from .library import Library
|
||||
from .game import Game
|
||||
from .game import Game
|
||||
|
|
|
|||
|
|
@ -1,14 +1,15 @@
|
|||
import requests
|
||||
from bs4 import BeautifulSoup as soup
|
||||
|
||||
|
||||
class Bundle:
|
||||
def __init__(self, login, url):
|
||||
self.login = login
|
||||
self.url = url
|
||||
|
||||
|
||||
def load_games(self):
|
||||
i = 1
|
||||
|
||||
|
||||
r = self.login.get(self.url)
|
||||
s = soup(r.text, "html.parser")
|
||||
pages = int(s.select("span.pager_label a")[-1].text)
|
||||
|
|
@ -18,7 +19,8 @@ class Bundle:
|
|||
print(f"Processing Page {i} of {pages}")
|
||||
|
||||
def load_game(self, i):
|
||||
# Load 1 game. This will refresh the game afterwards, as the csrf token will update
|
||||
# Load 1 game. This will refresh the game afterwards, as the csrf token
|
||||
# will update
|
||||
r = self.login.get(f"{self.url}?page={i}")
|
||||
s = soup(r.text, "html.parser")
|
||||
for g in s.select("div.game_row"):
|
||||
|
|
@ -26,14 +28,16 @@ class Bundle:
|
|||
if f := g.find("form"):
|
||||
print(f"Processing {name}")
|
||||
|
||||
game_id = f.find("input", {"name":"game_id"})["value"]
|
||||
csrf_token = f.find("input", {"name":"csrf_token"})["value"]
|
||||
game_id = f.find("input", {"name": "game_id"})["value"]
|
||||
csrf_token = f.find("input", {"name": "csrf_token"})["value"]
|
||||
|
||||
data = {"action":"claim", "game_id":game_id, "csrf_token":csrf_token}
|
||||
data = {
|
||||
"action": "claim",
|
||||
"game_id": game_id,
|
||||
"csrf_token": csrf_token}
|
||||
|
||||
r = self.login.post(f"{self.url}?page={i}", data=data)
|
||||
return False
|
||||
#else:
|
||||
# else:
|
||||
# print(f"Skipping {name} - Already in Library")
|
||||
return True
|
||||
|
||||
|
|
|
|||
|
|
@ -1,15 +1,17 @@
|
|||
from getpass import getpass
|
||||
import itchiodl
|
||||
|
||||
|
||||
def main():
|
||||
user = input("Username: ")
|
||||
password = getpass("Password: ")
|
||||
|
||||
|
||||
l = itchiodl.LoginWeb(user, password)
|
||||
|
||||
url = input("Bundle URL: ")
|
||||
b = itchiodl.Bundle(l, url)
|
||||
b.load_games()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
main()
|
||||
|
|
|
|||
|
|
@ -3,13 +3,17 @@ from getpass import getpass
|
|||
|
||||
import itchiodl
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
prog='python -m hstp',
|
||||
description='Build an '
|
||||
)
|
||||
|
||||
parser.add_argument("-k", "--api-key", help="Use API key instead of username/password")
|
||||
parser.add_argument(
|
||||
"-k",
|
||||
"--api-key",
|
||||
help="Use API key instead of username/password")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
|
|
@ -26,5 +30,6 @@ def main():
|
|||
lib.load_games()
|
||||
lib.download_library()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
main()
|
||||
|
|
|
|||
|
|
@ -5,10 +5,10 @@ import os
|
|||
import urllib
|
||||
|
||||
|
||||
|
||||
import itchiodl.utils
|
||||
|
||||
class Game:
|
||||
|
||||
class Game:
|
||||
def __init__(self, data):
|
||||
self.data = data["game"]
|
||||
self.name = self.data["title"]
|
||||
|
|
@ -17,7 +17,7 @@ class Game:
|
|||
|
||||
self.id = data["id"]
|
||||
self.game_id = data["game_id"]
|
||||
|
||||
|
||||
matches = re.match(r"https://(.+)\.itch\.io/(.+)", self.link)
|
||||
self.game_slug = matches.group(2)
|
||||
self.publisher_slug = matches.group(1)
|
||||
|
|
@ -26,11 +26,14 @@ class Game:
|
|||
|
||||
def load_downloads(self, token):
|
||||
self.downloads = []
|
||||
r = requests.get(f"https://api.itch.io/games/{self.game_id}/uploads?download_key_id={self.id}", headers={"Authorization": token})
|
||||
r = requests.get(
|
||||
f"https://api.itch.io/games/{self.game_id}/uploads?download_key_id={self.id}",
|
||||
headers={
|
||||
"Authorization": token})
|
||||
j = r.json()
|
||||
for d in j["uploads"]:
|
||||
self.downloads.append(d)
|
||||
|
||||
|
||||
def download(self, token):
|
||||
if os.path.exists(f"{self.publisher_slug}/{self.game_slug}.json"):
|
||||
print(f"Skipping Game {self.name}")
|
||||
|
|
@ -52,14 +55,17 @@ class Game:
|
|||
continue
|
||||
|
||||
# Get UUID
|
||||
r = requests.post(f"https://api.itch.io/games/{self.game_id}/download-sessions", headers={"Authorization": token})
|
||||
r = requests.post(
|
||||
f"https://api.itch.io/games/{self.game_id}/download-sessions",
|
||||
headers={
|
||||
"Authorization": token})
|
||||
j = r.json()
|
||||
|
||||
# Download
|
||||
url = f"https://api.itch.io/uploads/{d['id']}/download?api_key={token}&download_key_id={self.id}&uuid={j['uuid']}"
|
||||
# response_code = urllib.request.urlopen(url).getcode()
|
||||
try:
|
||||
itchiodl.utils.download(url, path, self.name +" - "+file)
|
||||
itchiodl.utils.download(url, path, self.name + " - " + file)
|
||||
except itchiodl.utils.NoDownloadError as e:
|
||||
print("Http response is not a download, skipping")
|
||||
|
||||
|
|
@ -87,11 +93,9 @@ class Game:
|
|||
Error Reason: {e.reason}
|
||||
This game/asset has been skipped please download manually
|
||||
---------------------------------------------------------\n """)
|
||||
|
||||
|
||||
continue
|
||||
|
||||
|
||||
|
||||
with open(f"{self.publisher_slug}/{self.game_slug}.json", "w") as f:
|
||||
json.dump({
|
||||
"name": self.name,
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import json
|
|||
|
||||
from itchiodl.game import Game
|
||||
|
||||
|
||||
class Library:
|
||||
def __init__(self, login):
|
||||
self.login = login
|
||||
|
|
@ -10,10 +11,12 @@ class Library:
|
|||
|
||||
def load_game_page(self, page):
|
||||
print("Loading page", page)
|
||||
r = requests.get(f"https://api.itch.io/profile/owned-keys?page={page}", headers={"Authorization": self.login})
|
||||
r = requests.get(
|
||||
f"https://api.itch.io/profile/owned-keys?page={page}",
|
||||
headers={
|
||||
"Authorization": self.login})
|
||||
j = json.loads(r.text)
|
||||
|
||||
|
||||
for s in j["owned_keys"]:
|
||||
self.games.append(Game(s))
|
||||
|
||||
|
|
|
|||
|
|
@ -3,30 +3,37 @@ import json
|
|||
from bs4 import BeautifulSoup as soup
|
||||
import requests
|
||||
|
||||
|
||||
def LoginWeb(user, password):
|
||||
session = requests.Session()
|
||||
|
||||
# GET the page first so we have a valid CSRF token value
|
||||
login1 = session.get("https://itch.io/login")
|
||||
s = soup(login1.text, "html.parser")
|
||||
csrf_token = s.find("input", {"name": "csrf_token"})["value"]
|
||||
|
||||
# Now POST the login
|
||||
r = session.post("https://itch.io/login", {"username": user, "password":password, "csrf_token": csrf_token})
|
||||
session = requests.Session()
|
||||
|
||||
if r.status_code != 200:
|
||||
raise RuntimeError
|
||||
# GET the page first so we have a valid CSRF token value
|
||||
login1 = session.get("https://itch.io/login")
|
||||
s = soup(login1.text, "html.parser")
|
||||
csrf_token = s.find("input", {"name": "csrf_token"})["value"]
|
||||
|
||||
# Now POST the login
|
||||
r = session.post("https://itch.io/login",
|
||||
{"username": user,
|
||||
"password": password,
|
||||
"csrf_token": csrf_token})
|
||||
|
||||
if r.status_code != 200:
|
||||
raise RuntimeError
|
||||
|
||||
return session
|
||||
|
||||
return session
|
||||
|
||||
def LoginAPI(user, password):
|
||||
r = requests.post("https://api.itch.io/login", {"username": user, "password":password, "source": "desktop"})
|
||||
r = requests.post("https://api.itch.io/login",
|
||||
{"username": user,
|
||||
"password": password,
|
||||
"source": "desktop"})
|
||||
if r.status_code != 200:
|
||||
raise RuntimeError
|
||||
t = json.loads(r.text)
|
||||
|
||||
|
||||
if not t["success"]:
|
||||
raise RuntimeError
|
||||
|
||||
|
||||
return t["key"]["key"]
|
||||
|
||||
|
|
@ -4,14 +4,17 @@ import os
|
|||
|
||||
from clint.textui import progress
|
||||
|
||||
|
||||
class NoDownloadError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def download(url, path, desc):
|
||||
print(f"Downloading {desc}")
|
||||
rsp = requests.get(url, stream=True)
|
||||
|
||||
if rsp.headers.get('content-length') is None or rsp.headers.get("Content-Disposition") is None:
|
||||
if rsp.headers.get(
|
||||
'content-length') is None or rsp.headers.get("Content-Disposition") is None:
|
||||
raise NoDownloadError("Http response is not a download, skipping")
|
||||
|
||||
cd = rsp.headers.get("Content-Disposition")
|
||||
|
|
@ -26,7 +29,10 @@ def download(url, path, desc):
|
|||
print(f"{filename} exists but is incomplete, downloading again")
|
||||
|
||||
with open(f"{path}/{filename}", "wb") as f:
|
||||
for chunk in progress.bar(rsp.iter_content(chunk_size=1024), expected_size=(total_length/1024) + 1):
|
||||
for chunk in progress.bar(
|
||||
rsp.iter_content(
|
||||
chunk_size=1024), expected_size=(
|
||||
total_length / 1024) + 1):
|
||||
if chunk:
|
||||
f.write(chunk)
|
||||
f.flush()
|
||||
|
|
|
|||
Loading…
Reference in a new issue