Merge pull request #242 from loathingKernel/fixups
Nuitka and another round of fixes for Windows
This commit is contained in:
commit
4ef755fa2e
44
.github/workflows/checks.yml
vendored
Normal file
44
.github/workflows/checks.yml
vendored
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
|
||||||
|
name: "Checks"
|
||||||
|
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
paths:
|
||||||
|
- 'rare/**'
|
||||||
|
pull_request:
|
||||||
|
types:
|
||||||
|
- opened
|
||||||
|
- reopened
|
||||||
|
- synchronize
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
paths:
|
||||||
|
- 'rare/**'
|
||||||
|
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
pylint:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
submodules: true
|
||||||
|
- name: Set up Python
|
||||||
|
uses: actions/setup-python@v2
|
||||||
|
with:
|
||||||
|
python-version: '3.9'
|
||||||
|
- name: Install Test Dependencies
|
||||||
|
run: |
|
||||||
|
python -m pip install --upgrade pip
|
||||||
|
pip install pylint
|
||||||
|
- name: Install Target Dependencies
|
||||||
|
run: |
|
||||||
|
pip3 install -r requirements.txt
|
||||||
|
pip3 install -r requirements-presence.txt
|
||||||
|
- name: Analysis with pylint
|
||||||
|
run: |
|
||||||
|
pylint -E rare --disable=E0611,E1123,E1120 --ignore=ui,singleton.py --extension-pkg-whitelist=PyQt5
|
|
@ -1,30 +1,12 @@
|
||||||
|
|
||||||
name: "Test"
|
name: "Release Tests"
|
||||||
|
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
jobs:
|
|
||||||
pylint:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
with:
|
|
||||||
submodules: true
|
|
||||||
- name: Set up Python 3.10
|
|
||||||
uses: actions/setup-python@v2
|
|
||||||
with:
|
|
||||||
python-version: '3.10'
|
|
||||||
- name: Install dependencies
|
|
||||||
run: |
|
|
||||||
python -m pip install --upgrade pip
|
|
||||||
pip install pylint
|
|
||||||
pip install -r requirements.txt
|
|
||||||
pip install pypresence
|
|
||||||
- name: Analysing the code with pylint
|
|
||||||
run: |
|
|
||||||
pylint -E rare --disable=E0611,E1123,E1120 --ignore=ui,singleton.py --extension-pkg-whitelist=PyQt5
|
|
||||||
|
|
||||||
|
jobs:
|
||||||
deb-package:
|
deb-package:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
|
@ -46,7 +28,8 @@ jobs:
|
||||||
makedeb -d
|
makedeb -d
|
||||||
mv *.deb Rare.deb
|
mv *.deb Rare.deb
|
||||||
|
|
||||||
- uses: actions/upload-artifact@v2
|
- name: Upload to Artifacts
|
||||||
|
uses: actions/upload-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: Rare.deb
|
name: Rare.deb
|
||||||
path: build/Rare.deb
|
path: build/Rare.deb
|
||||||
|
@ -72,11 +55,55 @@ jobs:
|
||||||
appimage-builder --skip-test
|
appimage-builder --skip-test
|
||||||
mv Rare-*.AppImage Rare.AppImage
|
mv Rare-*.AppImage Rare.AppImage
|
||||||
|
|
||||||
- uses: actions/upload-artifact@v2
|
- name: Upload to Artifacts
|
||||||
|
uses: actions/upload-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: Rare.AppImage
|
name: Rare.AppImage
|
||||||
path: Rare.AppImage
|
path: Rare.AppImage
|
||||||
|
|
||||||
|
nuitka:
|
||||||
|
runs-on: "windows-latest"
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
submodules: true
|
||||||
|
- uses: actions/setup-python@v2
|
||||||
|
with:
|
||||||
|
python-version: '3.9'
|
||||||
|
- name: Install build dependencies
|
||||||
|
run: pip3 install nuitka ordered-set
|
||||||
|
- name: Install target dependencies
|
||||||
|
run: |
|
||||||
|
pip3 install -r requirements.txt
|
||||||
|
pip3 install -r requirements-presence.txt
|
||||||
|
- name: Version
|
||||||
|
id: version
|
||||||
|
run: |
|
||||||
|
git fetch --prune --unshallow
|
||||||
|
echo "::set-output name=tag_offset::$(git describe --long --tags)"
|
||||||
|
echo "::set-output name=sha_short::$(git rev-parse --short HEAD)"
|
||||||
|
- name: Build
|
||||||
|
run: >-
|
||||||
|
python -m nuitka
|
||||||
|
--assume-yes-for-downloads
|
||||||
|
--follow-imports --prefer-source-code --mingw64 --lto=no --jobs=2 --static-libpython=no --standalone
|
||||||
|
--enable-plugin=anti-bloat --enable-plugin=pyqt5 --show-anti-bloat-changes --nofollow-import-to="*.tests"
|
||||||
|
--nofollow-import-to="*.distutils" --include-package-data=qtawesome
|
||||||
|
--include-data-dir=rare\resources\images=rare\resources\images
|
||||||
|
--include-data-files=rare\resources\languages=rare\resources\languages="*.qm"
|
||||||
|
--windows-icon-from-ico=rare\resources\images\Rare.ico
|
||||||
|
--windows-company-name=Rare --windows-product-name=Rare --windows-file-description=rare.exe
|
||||||
|
--windows-file-version=0.0.0.0
|
||||||
|
--windows-product-version=0.0.0.0
|
||||||
|
--windows-disable-console
|
||||||
|
rare
|
||||||
|
|
||||||
|
- name: Upload to Artifacts
|
||||||
|
uses: actions/upload-artifact@v2
|
||||||
|
with:
|
||||||
|
name: Rare-Windows-${{ steps.version.outputs.tag_offset }}
|
||||||
|
path: rare.dist
|
||||||
|
|
||||||
cx_freeze:
|
cx_freeze:
|
||||||
runs-on: "windows-latest"
|
runs-on: "windows-latest"
|
||||||
steps:
|
steps:
|
||||||
|
@ -85,19 +112,28 @@ jobs:
|
||||||
submodules: true
|
submodules: true
|
||||||
- uses: actions/setup-python@v2
|
- uses: actions/setup-python@v2
|
||||||
with:
|
with:
|
||||||
python-version: '3.10'
|
python-version: '3.9'
|
||||||
- name: Dependencies
|
- name: Install Build Dependencies
|
||||||
run: pip3 install -r requirements.txt
|
|
||||||
- name: cx_freeze
|
|
||||||
run: pip3 install --upgrade cx_freeze wheel
|
run: pip3 install --upgrade cx_freeze wheel
|
||||||
- name: pypresence
|
- name: Install Target Dependencies
|
||||||
run: pip3 install pypresence
|
run: |
|
||||||
|
pip3 install -r requirements.txt
|
||||||
|
pip3 install -r requirements-presence.txt
|
||||||
|
- name: Version
|
||||||
|
id: version
|
||||||
|
run: |
|
||||||
|
git fetch --prune --unshallow
|
||||||
|
echo "::set-output name=tag_offset::$(git describe --long --tags)"
|
||||||
|
echo "::set-output name=sha_short::$(git rev-parse --short HEAD)"
|
||||||
- name: Build
|
- name: Build
|
||||||
run: python freeze.py bdist_msi
|
run: |
|
||||||
|
python freeze.py bdist_msi
|
||||||
|
mv dist/*.msi dist/Rare-Windows.msi
|
||||||
|
|
||||||
- uses: actions/upload-artifact@v2
|
- name: Upload to Artifacts
|
||||||
|
uses: actions/upload-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: Rare-Windows.msi
|
name: Rare-Windows-${{ steps.version.outputs.tag_offset }}.msi
|
||||||
path: dist/*.msi
|
path: dist/*.msi
|
||||||
|
|
||||||
mac_os:
|
mac_os:
|
||||||
|
@ -120,8 +156,12 @@ jobs:
|
||||||
run: mv rare/__main__.py __main__.py
|
run: mv rare/__main__.py __main__.py
|
||||||
|
|
||||||
- name: run pyinstaller
|
- name: run pyinstaller
|
||||||
run: |
|
run: >-
|
||||||
pyinstaller -F --name Rare --add-data "rare/resources/languages/*:rare/resources/languages" --add-data "rare/resources/images/*:rare/resources/images/" --windowed --icon rare/resources/images/Rare.icns --hidden-import=legendary __main__.py
|
pyinstaller -F --name Rare
|
||||||
|
--add-data "rare/resources/languages/*:rare/resources/languages"
|
||||||
|
--add-data "rare/resources/images/*:rare/resources/images/"
|
||||||
|
--windowed --icon rare/resources/images/Rare.icns
|
||||||
|
--hidden-import=legendary __main__.py
|
||||||
|
|
||||||
- name: create dmg
|
- name: create dmg
|
||||||
run: |
|
run: |
|
83
.github/workflows/release.yml
vendored
83
.github/workflows/release.yml
vendored
|
@ -1,9 +1,12 @@
|
||||||
name: New Release
|
|
||||||
|
name: "Release"
|
||||||
|
|
||||||
|
|
||||||
on:
|
on:
|
||||||
release:
|
release:
|
||||||
types: [ published ]
|
types: [ published ]
|
||||||
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
pypi-deploy:
|
pypi-deploy:
|
||||||
if: "!github.event.release.prerelease"
|
if: "!github.event.release.prerelease"
|
||||||
|
@ -48,7 +51,7 @@ jobs:
|
||||||
makedeb -d
|
makedeb -d
|
||||||
mv *.deb Rare.deb
|
mv *.deb Rare.deb
|
||||||
|
|
||||||
- name: Upload files to GitHub
|
- name: Upload to Releases
|
||||||
uses: svenstaro/upload-release-action@2.2.1
|
uses: svenstaro/upload-release-action@2.2.1
|
||||||
with:
|
with:
|
||||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
@ -79,7 +82,7 @@ jobs:
|
||||||
mv Rare-*.AppImage Rare.AppImage
|
mv Rare-*.AppImage Rare.AppImage
|
||||||
mv Rare-*.AppImage.zsync Rare.AppImage.zsync
|
mv Rare-*.AppImage.zsync Rare.AppImage.zsync
|
||||||
|
|
||||||
- name: Upload AppImage to GitHub
|
- name: Upload to Releases
|
||||||
uses: svenstaro/upload-release-action@2.2.1
|
uses: svenstaro/upload-release-action@2.2.1
|
||||||
with:
|
with:
|
||||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
@ -96,6 +99,49 @@ jobs:
|
||||||
tag: ${{ github.ref }}
|
tag: ${{ github.ref }}
|
||||||
overwrite: true
|
overwrite: true
|
||||||
|
|
||||||
|
nuitka:
|
||||||
|
runs-on: "windows-latest"
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
submodules: true
|
||||||
|
- uses: actions/setup-python@v2
|
||||||
|
with:
|
||||||
|
python-version: '3.9'
|
||||||
|
- name: Install build dependencies
|
||||||
|
run: pip3 install nuitka ordered-set
|
||||||
|
- name: Install target dependencies
|
||||||
|
run: |
|
||||||
|
pip3 install -r requirements.txt
|
||||||
|
pip3 install -r requirements-presence.txt
|
||||||
|
- name: Build
|
||||||
|
run: >-
|
||||||
|
python -m nuitka
|
||||||
|
--assume-yes-for-downloads
|
||||||
|
--follow-imports --prefer-source-code --mingw64 --lto=no --jobs=2 --static-libpython=no --standalone
|
||||||
|
--enable-plugin=anti-bloat --enable-plugin=pyqt5 --show-anti-bloat-changes --nofollow-import-to="*.tests"
|
||||||
|
--nofollow-import-to="*.distutils" --include-package-data=qtawesome
|
||||||
|
--include-data-dir=rare\resources\images=rare\resources\images
|
||||||
|
--include-data-files=rare\resources\languages=rare\resources\languages="*.qm"
|
||||||
|
--windows-icon-from-ico=rare\resources\images\Rare.ico
|
||||||
|
--windows-company-name=Rare --windows-product-name=Rare --windows-file-description=rare.exe
|
||||||
|
--windows-file-version=${{ github.event.release.tag_name }}
|
||||||
|
--windows-product-version=${{ github.event.release.tag_name }}
|
||||||
|
--windows-disable-console
|
||||||
|
rare
|
||||||
|
- name: Compress
|
||||||
|
run: |
|
||||||
|
python -c "import shutil; shutil.make_archive('Rare-Windows', 'zip', 'rare.dist')"
|
||||||
|
|
||||||
|
- name: Upload to Releases
|
||||||
|
uses: svenstaro/upload-release-action@2.2.1
|
||||||
|
with:
|
||||||
|
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
file: Rare-Windows.zip
|
||||||
|
asset_name: Rare-Windows-${{ github.event.release.tag_name }}.zip
|
||||||
|
tag: ${{ github.ref }}
|
||||||
|
overwrite: true
|
||||||
|
|
||||||
cx_freeze:
|
cx_freeze:
|
||||||
runs-on: "windows-latest"
|
runs-on: "windows-latest"
|
||||||
steps:
|
steps:
|
||||||
|
@ -104,24 +150,27 @@ jobs:
|
||||||
submodules: true
|
submodules: true
|
||||||
- uses: actions/setup-python@v2
|
- uses: actions/setup-python@v2
|
||||||
with:
|
with:
|
||||||
python-version: '3.8'
|
python-version: '3.9'
|
||||||
- name: Dependencies
|
- name: Install Build Dependencies
|
||||||
run: pip3 install -r requirements.txt
|
|
||||||
- name: cx_freeze
|
|
||||||
run: pip3 install --upgrade cx_freeze wheel
|
run: pip3 install --upgrade cx_freeze wheel
|
||||||
|
- name: Install Target Dependencies
|
||||||
|
run: |
|
||||||
|
pip3 install -r requirements.txt
|
||||||
|
pip3 install -r requirements-presence.txt
|
||||||
- name: Build
|
- name: Build
|
||||||
run: python freeze.py bdist_msi
|
run: |
|
||||||
|
python freeze.py bdist_msi
|
||||||
|
mv dist/*.msi dist/Rare-Windows.msi
|
||||||
|
|
||||||
- name: Rename File
|
- name: Upload to Releases
|
||||||
run: mv dist/*.msi dist/Rare.msi
|
|
||||||
- name: Upload to GitHub
|
|
||||||
uses: svenstaro/upload-release-action@2.2.1
|
uses: svenstaro/upload-release-action@2.2.1
|
||||||
with:
|
with:
|
||||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
file: dist/Rare.msi
|
file: dist/Rare-Windows.msi
|
||||||
asset_name: Rare-${{ github.event.release.tag_name }}.msi
|
asset_name: Rare-Windows-${{ github.event.release.tag_name }}.msi
|
||||||
tag: ${{ github.ref }}
|
tag: ${{ github.ref }}
|
||||||
overwrite: true
|
overwrite: true
|
||||||
|
|
||||||
mac_os:
|
mac_os:
|
||||||
runs-on: macos-latest
|
runs-on: macos-latest
|
||||||
steps:
|
steps:
|
||||||
|
@ -142,8 +191,12 @@ jobs:
|
||||||
run: mv rare/__main__.py __main__.py
|
run: mv rare/__main__.py __main__.py
|
||||||
|
|
||||||
- name: run pyinstaller
|
- name: run pyinstaller
|
||||||
run: |
|
run: >-
|
||||||
pyinstaller -F --name Rare --add-data "rare/resources/languages/*:rare/resources/languages" --add-data "rare/resources/images/*:rare/resources/images/" --windowed --icon rare/resources/images/Rare.icns --hidden-import=legendary __main__.py
|
pyinstaller -F --name Rare
|
||||||
|
--add-data "rare/resources/languages/*:rare/resources/languages"
|
||||||
|
--add-data "rare/resources/images/*:rare/resources/images/"
|
||||||
|
--windowed --icon rare/resources/images/Rare.icns
|
||||||
|
--hidden-import=legendary __main__.py
|
||||||
|
|
||||||
- name: create dmg
|
- name: create dmg
|
||||||
run: |
|
run: |
|
||||||
|
|
1
misc/nuitka_rare.bat
Normal file
1
misc/nuitka_rare.bat
Normal file
|
@ -0,0 +1 @@
|
||||||
|
python -m nuitka --assume-yes-for-downloads --follow-imports --prefer-source-code --mingw64 --lto=no --jobs=2 --static-libpython=no --standalone --enable-plugin=anti-bloat --enable-plugin=pyqt5 --show-anti-bloat-changes --nofollow-import-to="*.tests" --nofollow-import-to="*.distutils" --include-package-data=qtawesome --include-data-dir=rare\resources\images=rare\resources\images --include-data-files=rare\resources\languages=rare\resources\languages="*.qm" --windows-icon-from-ico=rare\resources\images\Rare.ico --windows-company-name=Rare --windows-product-name=Rare --windows-file-description=rare.exe --windows-file-version=1.9.0 --windows-product-version=1.9.0 --windows-disable-console rare
|
5
misc/pip_upgrade_venv.py
Normal file
5
misc/pip_upgrade_venv.py
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
import pkg_resources
|
||||||
|
from subprocess import call
|
||||||
|
|
||||||
|
for dist in pkg_resources.working_set:
|
||||||
|
call("python -m pip install --upgrade " + dist.project_name, shell=True)
|
|
@ -33,24 +33,36 @@ pywebview = [
|
||||||
legendary-gl = "^0.20.28"
|
legendary-gl = "^0.20.28"
|
||||||
typing-extensions = "^4.3.0"
|
typing-extensions = "^4.3.0"
|
||||||
|
|
||||||
|
|
||||||
[tool.poetry.scripts]
|
[tool.poetry.scripts]
|
||||||
start = "rare.__main__:main"
|
start = "rare.__main__:main"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[tool.poetry.dev-dependencies]
|
[tool.poetry.dev-dependencies]
|
||||||
Nuitka = "^1.0.6"
|
Nuitka = "^1.0.6"
|
||||||
pylint = "^2.15.0"
|
pylint = "^2.15.0"
|
||||||
black = "^22.6.0"
|
black = "^22.6.0"
|
||||||
|
|
||||||
#[build-system]
|
#[build-system]
|
||||||
#requires = ["setuptools>=42"z, "wheel", "nuitka", "toml"]
|
#requires = ["setuptools>=42", "wheel", "nuitka", "toml"]
|
||||||
#build-backend = "nuitka.distutils.Build"
|
#build-backend = "nuitka.distutils.Build"
|
||||||
|
|
||||||
|
|
||||||
[nuitka]
|
[nuitka]
|
||||||
show-scons = true
|
assume-yes-for-downloads = true
|
||||||
enable-plugin = ["pyqt5", "anti-bloat"]
|
follow-imports = true
|
||||||
|
prefer-source-code = true
|
||||||
|
mingw64 = true
|
||||||
|
lto = true
|
||||||
|
static-libpython = false
|
||||||
|
standalone = true
|
||||||
|
show-scons = false
|
||||||
|
enable-plugin = ["anti-bloat", "pyqt5"]
|
||||||
show-anti-bloat-changes = true
|
show-anti-bloat-changes = true
|
||||||
nofollow-import-to = ["*.tests", "*.distutils"]
|
nofollow-import-to = ["*.tests", "*.distutils"]
|
||||||
|
include-package-data = "qtawesome"
|
||||||
|
include-data-dir = "rare/resources/images=rare/resources/images"
|
||||||
|
include-data-files = "rare/resources/languages=rare/resources/laguanges=*.qm"
|
||||||
|
windows-icon-from-ico = "rare/resources/images/Rare.ico"
|
||||||
|
windows-company-name = "Rare"
|
||||||
|
windows-product-name = "Rare"
|
||||||
|
windows-file-version = "1.9.0"
|
||||||
|
windows-product-version = "1.9.0"
|
||||||
|
windows-disable-console = true
|
||||||
|
|
|
@ -117,4 +117,12 @@ if __name__ == "__main__":
|
||||||
if "__compiled__" not in globals():
|
if "__compiled__" not in globals():
|
||||||
sys.path.insert(0, str(pathlib.Path(__file__).parents[1].absolute()))
|
sys.path.insert(0, str(pathlib.Path(__file__).parents[1].absolute()))
|
||||||
|
|
||||||
|
# If we are on Windows, and we are in a "compiled" GUI application form
|
||||||
|
# stdout (and stderr?) will be None. So to avoid `'NoneType' object has no attribute 'write'`
|
||||||
|
# errors, redirect both of them to devnull
|
||||||
|
if os.name == "nt" and (getattr(sys, "frozen", False) or ("__compiled__" in globals())):
|
||||||
|
f = open(os.devnull, 'w')
|
||||||
|
sys.stdout = f
|
||||||
|
sys.stderr = f
|
||||||
|
|
||||||
main()
|
main()
|
||||||
|
|
48
rare/app.py
48
rare/app.py
|
@ -20,7 +20,7 @@ from rare.shared import (
|
||||||
ArgumentsSingleton,
|
ArgumentsSingleton,
|
||||||
)
|
)
|
||||||
from rare.shared.rare_core import RareCore
|
from rare.shared.rare_core import RareCore
|
||||||
from rare.utils import legendary_utils, config_helper, paths
|
from rare.utils import config_helper, paths
|
||||||
from rare.widgets.rare_app import RareApp
|
from rare.widgets.rare_app import RareApp
|
||||||
|
|
||||||
logger = logging.getLogger("Rare")
|
logger = logging.getLogger("Rare")
|
||||||
|
@ -60,23 +60,23 @@ class App(RareApp):
|
||||||
self.load_translator(lang)
|
self.load_translator(lang)
|
||||||
|
|
||||||
# set Application name for settings
|
# set Application name for settings
|
||||||
self.mainwindow: Optional[MainWindow] = None
|
self.main_window: Optional[MainWindow] = None
|
||||||
self.launch_dialog: Optional[LaunchDialog] = None
|
self.launch_dialog: Optional[LaunchDialog] = None
|
||||||
self.timer = QTimer()
|
self.timer: Optional[QTimer] = None
|
||||||
|
|
||||||
# launch app
|
# launch app
|
||||||
self.launch_dialog = LaunchDialog(parent=None)
|
self.launch_dialog = LaunchDialog(parent=None)
|
||||||
self.launch_dialog.quit_app.connect(self.launch_dialog.close)
|
self.launch_dialog.quit_app.connect(self.launch_dialog.close)
|
||||||
self.launch_dialog.quit_app.connect(lambda ec: exit(ec))
|
self.launch_dialog.quit_app.connect(lambda x: sys.exit(x))
|
||||||
self.launch_dialog.start_app.connect(self.start_app)
|
self.launch_dialog.start_app.connect(self.start_app)
|
||||||
self.launch_dialog.start_app.connect(self.launch_dialog.close)
|
self.launch_dialog.start_app.connect(self.launch_dialog.close)
|
||||||
|
|
||||||
self.launch_dialog.login()
|
self.launch_dialog.login()
|
||||||
|
|
||||||
|
def poke_timer(self):
|
||||||
dt_exp = datetime.fromisoformat(self.core.lgd.userdata['expires_at'][:-1])
|
dt_exp = datetime.fromisoformat(self.core.lgd.userdata['expires_at'][:-1])
|
||||||
dt_now = datetime.utcnow()
|
dt_now = datetime.utcnow()
|
||||||
td = abs(dt_exp - dt_now)
|
td = abs(dt_exp - dt_now)
|
||||||
self.timer.timeout.connect(self.re_login)
|
|
||||||
self.timer.start(int(td.total_seconds() - 60) * 1000)
|
self.timer.start(int(td.total_seconds() - 60) * 1000)
|
||||||
|
|
||||||
def re_login(self):
|
def re_login(self):
|
||||||
|
@ -86,36 +86,18 @@ class App(RareApp):
|
||||||
except requests.exceptions.ConnectionError:
|
except requests.exceptions.ConnectionError:
|
||||||
self.timer.start(3000) # try again if no connection
|
self.timer.start(3000) # try again if no connection
|
||||||
return
|
return
|
||||||
dt_exp = datetime.fromisoformat(self.core.lgd.userdata['expires_at'][:-1])
|
self.poke_timer()
|
||||||
dt_now = datetime.utcnow()
|
|
||||||
td = abs(dt_exp - dt_now)
|
|
||||||
self.timer.start(int(td.total_seconds() - 60) * 1000)
|
|
||||||
|
|
||||||
def start_app(self):
|
def start_app(self):
|
||||||
for igame in self.core.get_installed_list():
|
self.timer = QTimer()
|
||||||
if not os.path.exists(igame.install_path):
|
self.timer.timeout.connect(self.re_login)
|
||||||
# lk; since install_path is lost anyway, set keep_files to True
|
self.poke_timer()
|
||||||
# lk: to avoid spamming the log with "file not found" errors
|
|
||||||
legendary_utils.uninstall_game(self.core, igame.app_name, keep_files=True)
|
|
||||||
logger.info(f"Uninstalled {igame.title}, because no game files exist")
|
|
||||||
continue
|
|
||||||
# lk: games that don't have an override and can't find their executable due to case sensitivity
|
|
||||||
# lk: will still erroneously require verification. This might need to be removed completely
|
|
||||||
# lk: or be decoupled from the verification requirement
|
|
||||||
if override_exe := self.core.lgd.config.get(igame.app_name, "override_exe", fallback=""):
|
|
||||||
igame_executable = override_exe
|
|
||||||
else:
|
|
||||||
igame_executable = igame.executable
|
|
||||||
if not os.path.exists(os.path.join(igame.install_path, igame_executable.replace("\\", "/").lstrip("/"))):
|
|
||||||
igame.needs_verification = True
|
|
||||||
self.core.lgd.set_installed_game(igame.app_name, igame)
|
|
||||||
logger.info(f"{igame.title} needs verification")
|
|
||||||
|
|
||||||
self.mainwindow = MainWindow()
|
self.main_window = MainWindow()
|
||||||
self.mainwindow.exit_app.connect(self.exit_app)
|
self.main_window.exit_app.connect(self.exit_app)
|
||||||
|
|
||||||
if not self.args.silent:
|
if not self.args.silent:
|
||||||
self.mainwindow.show()
|
self.main_window.show()
|
||||||
|
|
||||||
if self.args.test_start:
|
if self.args.test_start:
|
||||||
self.exit_app(0)
|
self.exit_app(0)
|
||||||
|
@ -127,9 +109,9 @@ class App(RareApp):
|
||||||
self.timer.stop()
|
self.timer.stop()
|
||||||
self.timer.deleteLater()
|
self.timer.deleteLater()
|
||||||
self.timer = None
|
self.timer = None
|
||||||
if self.mainwindow is not None:
|
if self.main_window is not None:
|
||||||
self.mainwindow.close()
|
self.main_window.close()
|
||||||
self.mainwindow = None
|
self.main_window = None
|
||||||
self.rare_core.deleteLater()
|
self.rare_core.deleteLater()
|
||||||
del self.rare_core
|
del self.rare_core
|
||||||
self.processEvents()
|
self.processEvents()
|
||||||
|
|
|
@ -1,22 +1,26 @@
|
||||||
|
import os
|
||||||
import platform
|
import platform
|
||||||
from logging import getLogger
|
from logging import getLogger
|
||||||
|
|
||||||
from PyQt5.QtCore import Qt, pyqtSignal, QRunnable, QObject, QThreadPool, QSettings
|
from PyQt5.QtCore import Qt, pyqtSignal, QRunnable, QObject, QThreadPool, QSettings, pyqtSlot
|
||||||
from PyQt5.QtWidgets import QDialog, QApplication
|
from PyQt5.QtWidgets import QDialog, QApplication
|
||||||
|
from legendary.models.game import Game
|
||||||
from requests.exceptions import ConnectionError, HTTPError
|
from requests.exceptions import ConnectionError, HTTPError
|
||||||
|
|
||||||
from rare.components.dialogs.login import LoginDialog
|
from rare.components.dialogs.login import LoginDialog
|
||||||
from rare.models.apiresults import ApiResults
|
from rare.models.apiresults import ApiResults
|
||||||
from rare.shared import LegendaryCoreSingleton, ArgumentsSingleton, ApiResultsSingleton, ImageManagerSingleton
|
from rare.shared import LegendaryCoreSingleton, ArgumentsSingleton, ApiResultsSingleton, ImageManagerSingleton
|
||||||
from rare.ui.components.dialogs.launch_dialog import Ui_LaunchDialog
|
from rare.ui.components.dialogs.launch_dialog import Ui_LaunchDialog
|
||||||
|
from rare.utils import legendary_utils
|
||||||
from rare.utils.misc import CloudWorker
|
from rare.utils.misc import CloudWorker
|
||||||
|
from rare.widgets.elide_label import ElideLabel
|
||||||
|
|
||||||
logger = getLogger("LaunchDialog")
|
logger = getLogger("LaunchDialog")
|
||||||
|
|
||||||
|
|
||||||
class LaunchWorker(QRunnable):
|
class LaunchWorker(QRunnable):
|
||||||
class Signals(QObject):
|
class Signals(QObject):
|
||||||
progress = pyqtSignal(int)
|
progress = pyqtSignal(int, str)
|
||||||
result = pyqtSignal(object, str)
|
result = pyqtSignal(object, str)
|
||||||
finished = pyqtSignal()
|
finished = pyqtSignal()
|
||||||
|
|
||||||
|
@ -26,16 +30,41 @@ class LaunchWorker(QRunnable):
|
||||||
self.signals = LaunchWorker.Signals()
|
self.signals = LaunchWorker.Signals()
|
||||||
self.core = LegendaryCoreSingleton()
|
self.core = LegendaryCoreSingleton()
|
||||||
|
|
||||||
def run(self):
|
def run_real(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
self.run_real()
|
||||||
|
self.signals.deleteLater()
|
||||||
|
|
||||||
|
|
||||||
class ImageWorker(LaunchWorker):
|
class ImageWorker(LaunchWorker):
|
||||||
|
# FIXME: this is a middle-ground solution for concurrent downloads
|
||||||
|
class DownloadSlot(QObject):
|
||||||
|
def __init__(self, signals: LaunchWorker.Signals):
|
||||||
|
super(ImageWorker.DownloadSlot, self).__init__()
|
||||||
|
self.signals = signals
|
||||||
|
self.counter = 0
|
||||||
|
self.length = 0
|
||||||
|
|
||||||
|
@pyqtSlot(object)
|
||||||
|
def counter_inc(self, game: Game):
|
||||||
|
self.signals.progress.emit(
|
||||||
|
int(self.counter / self.length * 75),
|
||||||
|
self.tr("Downloading image for <b>{}</b>").format(game.app_title)
|
||||||
|
)
|
||||||
|
self.counter += 1
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(ImageWorker, self).__init__()
|
super(ImageWorker, self).__init__()
|
||||||
|
# FIXME: this is a middle-ground solution for concurrent downloads
|
||||||
|
self.dl_slot = ImageWorker.DownloadSlot(self.signals)
|
||||||
self.image_manager = ImageManagerSingleton()
|
self.image_manager = ImageManagerSingleton()
|
||||||
|
|
||||||
def run(self):
|
def tr(self, t) -> str:
|
||||||
|
return QApplication.instance().translate(self.__class__.__name__, t)
|
||||||
|
|
||||||
|
def run_real(self):
|
||||||
# Download Images
|
# Download Images
|
||||||
games, dlcs = self.core.get_game_and_dlc_list(update_assets=True, skip_ue=False)
|
games, dlcs = self.core.get_game_and_dlc_list(update_assets=True, skip_ue=False)
|
||||||
self.signals.result.emit((games, dlcs), "gamelist")
|
self.signals.result.emit((games, dlcs), "gamelist")
|
||||||
|
@ -47,12 +76,46 @@ class ImageWorker(LaunchWorker):
|
||||||
|
|
||||||
game_list = games + dlc_list + na_games + na_dlc_list
|
game_list = games + dlc_list + na_games + na_dlc_list
|
||||||
|
|
||||||
|
self.dl_slot.length = len(game_list)
|
||||||
for i, game in enumerate(game_list):
|
for i, game in enumerate(game_list):
|
||||||
if game.app_title == "Unreal Engine":
|
if game.app_title == "Unreal Engine":
|
||||||
game.app_title += f" {game.app_name.split('_')[-1]}"
|
game.app_title += f" {game.app_name.split('_')[-1]}"
|
||||||
self.core.lgd.set_game_meta(game.app_name, game)
|
self.core.lgd.set_game_meta(game.app_name, game)
|
||||||
self.image_manager.download_image_blocking(game)
|
# self.image_manager.download_image_blocking(game)
|
||||||
self.signals.progress.emit(int(i / len(game_list) * 100))
|
self.image_manager.download_image(game, self.dl_slot.counter_inc, priority=0)
|
||||||
|
# FIXME: this is a middle-ground solution for concurrent downloads
|
||||||
|
while self.dl_slot.counter < len(game_list):
|
||||||
|
QApplication.instance().processEvents()
|
||||||
|
self.dl_slot.deleteLater()
|
||||||
|
|
||||||
|
igame_list = self.core.get_installed_list(include_dlc=True)
|
||||||
|
|
||||||
|
# FIXME: incorporate installed game status checking here for now, still slow
|
||||||
|
for i, igame in enumerate(igame_list):
|
||||||
|
self.signals.progress.emit(
|
||||||
|
int(i / len(igame_list) * 25) + 75,
|
||||||
|
self.tr("Validating install for <b>{}</b>").format(igame.title)
|
||||||
|
)
|
||||||
|
if not os.path.exists(igame.install_path):
|
||||||
|
# lk; since install_path is lost anyway, set keep_files to True
|
||||||
|
# lk: to avoid spamming the log with "file not found" errors
|
||||||
|
legendary_utils.uninstall_game(self.core, igame.app_name, keep_files=True)
|
||||||
|
logger.info(f"Uninstalled {igame.title}, because no game files exist")
|
||||||
|
continue
|
||||||
|
# lk: games that don't have an override and can't find their executable due to case sensitivity
|
||||||
|
# lk: will still erroneously require verification. This might need to be removed completely
|
||||||
|
# lk: or be decoupled from the verification requirement
|
||||||
|
if override_exe := self.core.lgd.config.get(igame.app_name, "override_exe", fallback=""):
|
||||||
|
igame_executable = override_exe
|
||||||
|
else:
|
||||||
|
igame_executable = igame.executable
|
||||||
|
if not os.path.exists(os.path.join(igame.install_path, igame_executable.replace("\\", "/").lstrip("/"))):
|
||||||
|
igame.needs_verification = True
|
||||||
|
self.core.lgd.set_installed_game(igame.app_name, igame)
|
||||||
|
logger.info(f"{igame.title} needs verification")
|
||||||
|
# FIXME: end
|
||||||
|
|
||||||
|
self.signals.progress.emit(100, self.tr("Launching Rare"))
|
||||||
self.signals.finished.emit()
|
self.signals.finished.emit()
|
||||||
|
|
||||||
|
|
||||||
|
@ -61,7 +124,7 @@ class ApiRequestWorker(LaunchWorker):
|
||||||
super(ApiRequestWorker, self).__init__()
|
super(ApiRequestWorker, self).__init__()
|
||||||
self.settings = QSettings()
|
self.settings = QSettings()
|
||||||
|
|
||||||
def run(self) -> None:
|
def run_real(self) -> None:
|
||||||
if self.settings.value("mac_meta", platform.system() == "Darwin", bool):
|
if self.settings.value("mac_meta", platform.system() == "Darwin", bool):
|
||||||
try:
|
try:
|
||||||
result = self.core.get_game_and_dlc_list(update_assets=False, platform="Mac")
|
result = self.core.get_game_and_dlc_list(update_assets=False, platform="Mac")
|
||||||
|
@ -102,12 +165,15 @@ class LaunchDialog(QDialog):
|
||||||
self.ui = Ui_LaunchDialog()
|
self.ui = Ui_LaunchDialog()
|
||||||
self.ui.setupUi(self)
|
self.ui.setupUi(self)
|
||||||
|
|
||||||
|
self.progress_info = ElideLabel(parent=self)
|
||||||
|
self.layout().addWidget(self.progress_info)
|
||||||
|
|
||||||
self.core = LegendaryCoreSingleton()
|
self.core = LegendaryCoreSingleton()
|
||||||
self.args = ArgumentsSingleton()
|
self.args = ArgumentsSingleton()
|
||||||
self.thread_pool = QThreadPool().globalInstance()
|
self.thread_pool = QThreadPool().globalInstance()
|
||||||
self.api_results = ApiResults()
|
self.api_results = ApiResults()
|
||||||
|
|
||||||
self.login_dialog = LoginDialog(core=self.core, parent=self)
|
self.login_dialog = LoginDialog(core=self.core, parent=parent)
|
||||||
|
|
||||||
def login(self):
|
def login(self):
|
||||||
do_launch = True
|
do_launch = True
|
||||||
|
@ -146,12 +212,12 @@ class LaunchDialog(QDialog):
|
||||||
self.thread_pool.start(api_worker)
|
self.thread_pool.start(api_worker)
|
||||||
|
|
||||||
def launch(self):
|
def launch(self):
|
||||||
|
self.progress_info.setText(self.tr("Preparing Rare"))
|
||||||
|
|
||||||
if not self.args.offline:
|
if not self.args.offline:
|
||||||
self.ui.image_info.setText(self.tr("Downloading Images"))
|
|
||||||
image_worker = ImageWorker()
|
image_worker = ImageWorker()
|
||||||
image_worker.signals.result.connect(self.handle_api_worker_result)
|
image_worker.signals.result.connect(self.handle_api_worker_result)
|
||||||
image_worker.signals.progress.connect(self.update_image_progbar)
|
image_worker.signals.progress.connect(self.update_progress)
|
||||||
# lk: start the api requests worker after the manifests have been downloaded
|
# lk: start the api requests worker after the manifests have been downloaded
|
||||||
# lk: to avoid force updating the assets twice and causing inconsistencies
|
# lk: to avoid force updating the assets twice and causing inconsistencies
|
||||||
image_worker.signals.finished.connect(self.start_api_requests)
|
image_worker.signals.finished.connect(self.start_api_requests)
|
||||||
|
@ -206,14 +272,15 @@ class LaunchDialog(QDialog):
|
||||||
if self.api_results:
|
if self.api_results:
|
||||||
self.finish()
|
self.finish()
|
||||||
|
|
||||||
def update_image_progbar(self, i: int):
|
@pyqtSlot(int, str)
|
||||||
self.ui.image_prog_bar.setValue(i)
|
def update_progress(self, i: int, m: str):
|
||||||
|
self.ui.progress_bar.setValue(i)
|
||||||
|
self.progress_info.setText(m)
|
||||||
|
|
||||||
def finish(self):
|
def finish(self):
|
||||||
self.completed += 1
|
self.completed += 1
|
||||||
if self.completed == 2:
|
if self.completed == 2:
|
||||||
logger.info("App starting")
|
logger.info("App starting")
|
||||||
self.ui.image_info.setText(self.tr("Starting..."))
|
|
||||||
ApiResultsSingleton(self.api_results)
|
ApiResultsSingleton(self.api_results)
|
||||||
self.completed += 1
|
self.completed += 1
|
||||||
self.start_app.emit()
|
self.start_app.emit()
|
||||||
|
|
|
@ -63,8 +63,8 @@ class GameInfo(QWidget, Ui_GameInfo):
|
||||||
self.lbl_grade.setVisible(False)
|
self.lbl_grade.setVisible(False)
|
||||||
self.grade.setVisible(False)
|
self.grade.setVisible(False)
|
||||||
else:
|
else:
|
||||||
self.steam_worker = SteamWorker(self.core)
|
self.steam_worker: SteamWorker = SteamWorker(self.core)
|
||||||
self.steam_worker.signals.rating_signal.connect(self.grade.setText)
|
self.steam_worker.signals.rating.connect(self.grade.setText)
|
||||||
self.steam_worker.setAutoDelete(False)
|
self.steam_worker.setAutoDelete(False)
|
||||||
|
|
||||||
self.game_actions_stack.setCurrentIndex(0)
|
self.game_actions_stack.setCurrentIndex(0)
|
||||||
|
|
|
@ -135,11 +135,15 @@ class MoveGamePopUp(QWidget):
|
||||||
return True, dir_selected, str()
|
return True, dir_selected, str()
|
||||||
|
|
||||||
def update_game(self, app_name):
|
def update_game(self, app_name):
|
||||||
igame = self.core.get_installed_game(app_name, False)
|
igame = self.core.get_installed_game(app_name, skip_sync=True)
|
||||||
if igame is None:
|
if igame is None:
|
||||||
return
|
return
|
||||||
self.install_path = igame.install_path
|
self.install_path = igame.install_path
|
||||||
|
# FIXME: Make edit_func lighter instead of blocking signals
|
||||||
|
self.move_path_edit.line_edit.blockSignals(True)
|
||||||
self.move_path_edit.setText(igame.install_path)
|
self.move_path_edit.setText(igame.install_path)
|
||||||
|
# FIXME: Make edit_func lighter instead of blocking signals
|
||||||
|
self.move_path_edit.line_edit.blockSignals(False)
|
||||||
self.warn_overwriting.setText(
|
self.warn_overwriting.setText(
|
||||||
self.tr("Moving here will overwrite the dir/file {}/").format(Path(self.install_path).stem)
|
self.tr("Moving here will overwrite the dir/file {}/").format(Path(self.install_path).stem)
|
||||||
)
|
)
|
||||||
|
|
|
@ -87,7 +87,7 @@ class UninstalledInfo(QWidget, Ui_GameInfo):
|
||||||
self.install_button.clicked.connect(self.install_game)
|
self.install_button.clicked.connect(self.install_game)
|
||||||
if platform.system() != "Windows":
|
if platform.system() != "Windows":
|
||||||
self.steam_worker = SteamWorker(self.core)
|
self.steam_worker = SteamWorker(self.core)
|
||||||
self.steam_worker.signals.rating_signal.connect(self.grade.setText)
|
self.steam_worker.signals.rating.connect(self.grade.setText)
|
||||||
self.steam_worker.setAutoDelete(False)
|
self.steam_worker.setAutoDelete(False)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
import hashlib
|
import hashlib
|
||||||
import json
|
import json
|
||||||
import pickle
|
import pickle
|
||||||
import zlib
|
import zlib
|
||||||
|
# from concurrent import futures
|
||||||
from logging import getLogger
|
from logging import getLogger
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
@ -30,6 +29,8 @@ from rare.lgndr.core import LegendaryCore
|
||||||
from rare.models.signals import GlobalSignals
|
from rare.models.signals import GlobalSignals
|
||||||
from rare.utils.paths import image_dir, resources_path
|
from rare.utils.paths import image_dir, resources_path
|
||||||
|
|
||||||
|
# from requests_futures.sessions import FuturesSession
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -86,8 +87,8 @@ class ImageSize:
|
||||||
class ImageManager(QObject):
|
class ImageManager(QObject):
|
||||||
class Worker(QRunnable):
|
class Worker(QRunnable):
|
||||||
class Signals(QObject):
|
class Signals(QObject):
|
||||||
# str: app_name
|
# object: Game
|
||||||
completed = pyqtSignal(str)
|
completed = pyqtSignal(object)
|
||||||
|
|
||||||
def __init__(self, func: Callable, updates: List, json_data: Dict, game: Game):
|
def __init__(self, func: Callable, updates: List, json_data: Dict, game: Game):
|
||||||
super(ImageManager.Worker, self).__init__()
|
super(ImageManager.Worker, self).__init__()
|
||||||
|
@ -101,7 +102,7 @@ class ImageManager(QObject):
|
||||||
def run(self):
|
def run(self):
|
||||||
self.func(self.updates, self.json_data, self.game)
|
self.func(self.updates, self.json_data, self.game)
|
||||||
logger.debug(f" Emitting singal for game {self.game.app_name} - {self.game.app_title}")
|
logger.debug(f" Emitting singal for game {self.game.app_name} - {self.game.app_title}")
|
||||||
self.signals.completed.emit(self.game.app_name)
|
self.signals.completed.emit(self.game)
|
||||||
|
|
||||||
def __init__(self, signals: GlobalSignals, core: LegendaryCore):
|
def __init__(self, signals: GlobalSignals, core: LegendaryCore):
|
||||||
# lk: the ordering in __img_types matters for the order of fallbacks
|
# lk: the ordering in __img_types matters for the order of fallbacks
|
||||||
|
@ -179,7 +180,7 @@ class ImageManager(QObject):
|
||||||
|
|
||||||
return updates, json_data
|
return updates, json_data
|
||||||
|
|
||||||
def __download(self, updates, json_data, game) -> bool:
|
def __download(self, updates, json_data, game, use_async: bool = False) -> bool:
|
||||||
# Decompress existing image.cache
|
# Decompress existing image.cache
|
||||||
if not self.__img_cache(game.app_name).is_file():
|
if not self.__img_cache(game.app_name).is_file():
|
||||||
cache_data = dict(zip(self.__img_types, [None] * len(self.__img_types)))
|
cache_data = dict(zip(self.__img_types, [None] * len(self.__img_types)))
|
||||||
|
@ -193,6 +194,22 @@ class ImageManager(QObject):
|
||||||
if cache_data[image["type"]] is None or json_data[image["type"]] != image["md5"]
|
if cache_data[image["type"]] is None or json_data[image["type"]] != image["md5"]
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# Download
|
||||||
|
# # lk: Keep this so I don't have to go looking for it again,
|
||||||
|
# # lk: it might be useful in the future.
|
||||||
|
# if use_async and len(updates) > 1:
|
||||||
|
# session = FuturesSession(max_workers=len(self.__img_types))
|
||||||
|
# image_requests = []
|
||||||
|
# for image in updates:
|
||||||
|
# logger.info(f"Downloading {image['type']} for {game.app_title}")
|
||||||
|
# json_data[image["type"]] = image["md5"]
|
||||||
|
# payload = {"resize": 1, "w": ImageSize.Image.size.width(), "h": ImageSize.Image.size.height()}
|
||||||
|
# req = session.get(image["url"], params=payload)
|
||||||
|
# req.image_type = image["type"]
|
||||||
|
# image_requests.append(req)
|
||||||
|
# for req in futures.as_completed(image_requests):
|
||||||
|
# cache_data[req.image_type] = req.result().content
|
||||||
|
# else:
|
||||||
for image in updates:
|
for image in updates:
|
||||||
logger.info(f"Downloading {image['type']} for {game.app_title}")
|
logger.info(f"Downloading {image['type']} for {game.app_title}")
|
||||||
json_data[image["type"]] = image["md5"]
|
json_data[image["type"]] = image["md5"]
|
||||||
|
@ -291,18 +308,18 @@ class ImageManager(QObject):
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def download_image(
|
def download_image(
|
||||||
self, game: Game, load_callback: Callable[[], None], priority: int, force: bool = False
|
self, game: Game, load_callback: Callable[[Game], None], priority: int, force: bool = False
|
||||||
) -> None:
|
) -> None:
|
||||||
updates, json_data = self.__prepare_download(game, force)
|
updates, json_data = self.__prepare_download(game, force)
|
||||||
if not updates:
|
if not updates:
|
||||||
load_callback()
|
load_callback(game)
|
||||||
return
|
return
|
||||||
if updates and game.app_name not in self.__worker_app_names:
|
if updates and game.app_name not in self.__worker_app_names:
|
||||||
image_worker = ImageManager.Worker(self.__download, updates, json_data, game)
|
image_worker = ImageManager.Worker(self.__download, updates, json_data, game)
|
||||||
self.__worker_app_names.append(game.app_name)
|
self.__worker_app_names.append(game.app_name)
|
||||||
|
|
||||||
image_worker.signals.completed.connect(load_callback)
|
image_worker.signals.completed.connect(load_callback)
|
||||||
image_worker.signals.completed.connect(lambda app_name: self.__worker_app_names.remove(app_name))
|
image_worker.signals.completed.connect(lambda g: self.__worker_app_names.remove(g.app_name))
|
||||||
self.threadpool.start(image_worker, priority)
|
self.threadpool.start(image_worker, priority)
|
||||||
|
|
||||||
def download_image_blocking(self, game: Game, force: bool = False) -> None:
|
def download_image_blocking(self, game: Game, force: bool = False) -> None:
|
||||||
|
@ -310,7 +327,7 @@ class ImageManager(QObject):
|
||||||
if not updates:
|
if not updates:
|
||||||
return
|
return
|
||||||
if updates:
|
if updates:
|
||||||
self.__download(updates, json_data, game)
|
self.__download(updates, json_data, game, use_async=True)
|
||||||
|
|
||||||
def __get_cover(
|
def __get_cover(
|
||||||
self, container: Union[Type[QPixmap], Type[QImage]], app_name: str, color: bool = True
|
self, container: Union[Type[QPixmap], Type[QImage]], app_name: str, color: bool = True
|
||||||
|
|
|
@ -1,32 +1,36 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
# Form implementation generated from reading ui file 'launch_dialog.ui'
|
# Form implementation generated from reading ui file 'rare/ui/components/dialogs/launch_dialog.ui'
|
||||||
#
|
#
|
||||||
# Created by: PyQt5 UI code generator 5.15.4
|
# Created by: PyQt5 UI code generator 5.15.7
|
||||||
#
|
#
|
||||||
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
|
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
|
||||||
# run again. Do not edit this file unless you know what you are doing.
|
# run again. Do not edit this file unless you know what you are doing.
|
||||||
|
|
||||||
|
|
||||||
from PyQt5 import QtCore, QtWidgets
|
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||||
|
|
||||||
|
|
||||||
class Ui_LaunchDialog(object):
|
class Ui_LaunchDialog(object):
|
||||||
def setupUi(self, LaunchDialog):
|
def setupUi(self, LaunchDialog):
|
||||||
LaunchDialog.setObjectName("LaunchDialog")
|
LaunchDialog.setObjectName("LaunchDialog")
|
||||||
LaunchDialog.resize(400, 168)
|
LaunchDialog.resize(400, 160)
|
||||||
self.verticalLayout = QtWidgets.QVBoxLayout(LaunchDialog)
|
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
|
||||||
self.verticalLayout.setObjectName("verticalLayout")
|
sizePolicy.setHorizontalStretch(0)
|
||||||
|
sizePolicy.setVerticalStretch(0)
|
||||||
|
sizePolicy.setHeightForWidth(LaunchDialog.sizePolicy().hasHeightForWidth())
|
||||||
|
LaunchDialog.setSizePolicy(sizePolicy)
|
||||||
|
LaunchDialog.setMinimumSize(QtCore.QSize(400, 160))
|
||||||
|
LaunchDialog.setMaximumSize(QtCore.QSize(400, 160))
|
||||||
|
self.launch_dialog_layout = QtWidgets.QVBoxLayout(LaunchDialog)
|
||||||
|
self.launch_dialog_layout.setObjectName("launch_dialog_layout")
|
||||||
self.title_label = QtWidgets.QLabel(LaunchDialog)
|
self.title_label = QtWidgets.QLabel(LaunchDialog)
|
||||||
self.title_label.setObjectName("title_label")
|
self.title_label.setObjectName("title_label")
|
||||||
self.verticalLayout.addWidget(self.title_label)
|
self.launch_dialog_layout.addWidget(self.title_label)
|
||||||
self.image_prog_bar = QtWidgets.QProgressBar(LaunchDialog)
|
self.progress_bar = QtWidgets.QProgressBar(LaunchDialog)
|
||||||
self.image_prog_bar.setProperty("value", 0)
|
self.progress_bar.setProperty("value", 0)
|
||||||
self.image_prog_bar.setObjectName("image_prog_bar")
|
self.progress_bar.setObjectName("progress_bar")
|
||||||
self.verticalLayout.addWidget(self.image_prog_bar)
|
self.launch_dialog_layout.addWidget(self.progress_bar)
|
||||||
self.image_info = QtWidgets.QLabel(LaunchDialog)
|
|
||||||
self.image_info.setObjectName("image_info")
|
|
||||||
self.verticalLayout.addWidget(self.image_info)
|
|
||||||
|
|
||||||
self.retranslateUi(LaunchDialog)
|
self.retranslateUi(LaunchDialog)
|
||||||
QtCore.QMetaObject.connectSlotsByName(LaunchDialog)
|
QtCore.QMetaObject.connectSlotsByName(LaunchDialog)
|
||||||
|
@ -35,7 +39,6 @@ class Ui_LaunchDialog(object):
|
||||||
_translate = QtCore.QCoreApplication.translate
|
_translate = QtCore.QCoreApplication.translate
|
||||||
LaunchDialog.setWindowTitle(_translate("LaunchDialog", "Launching Rare"))
|
LaunchDialog.setWindowTitle(_translate("LaunchDialog", "Launching Rare"))
|
||||||
self.title_label.setText(_translate("LaunchDialog", "<h2>Launching Rare</h2>"))
|
self.title_label.setText(_translate("LaunchDialog", "<h2>Launching Rare</h2>"))
|
||||||
self.image_info.setText(_translate("LaunchDialog", "Downloading images"))
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
|
@ -7,13 +7,31 @@
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>400</width>
|
<width>400</width>
|
||||||
<height>168</height>
|
<height>160</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>400</width>
|
||||||
|
<height>160</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>400</width>
|
||||||
|
<height>160</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
<string>Launching Rare</string>
|
<string>Launching Rare</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
<layout class="QVBoxLayout" name="launch_dialog_layout">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="title_label">
|
<widget class="QLabel" name="title_label">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
|
@ -22,19 +40,12 @@
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QProgressBar" name="image_prog_bar">
|
<widget class="QProgressBar" name="progress_bar">
|
||||||
<property name="value">
|
<property name="value">
|
||||||
<number>0</number>
|
<number>0</number>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="image_info">
|
|
||||||
<property name="text">
|
|
||||||
<string>Downloading images</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
<resources/>
|
<resources/>
|
||||||
|
|
|
@ -16,7 +16,7 @@ url = "https://api.steampowered.com/ISteamApps/GetAppList/v2/"
|
||||||
|
|
||||||
class SteamWorker(QRunnable):
|
class SteamWorker(QRunnable):
|
||||||
class Signals(QObject):
|
class Signals(QObject):
|
||||||
rating_signal = pyqtSignal(str)
|
rating = pyqtSignal(str)
|
||||||
|
|
||||||
app_name: str = ""
|
app_name: str = ""
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ class SteamWorker(QRunnable):
|
||||||
self.app_name = app_name
|
self.app_name = app_name
|
||||||
|
|
||||||
def run(self) -> None:
|
def run(self) -> None:
|
||||||
self.signals.rating_signal.emit(
|
self.signals.rating.emit(
|
||||||
self.ratings.get(get_rating(self.app_name), self.ratings["fail"])
|
self.ratings.get(get_rating(self.app_name), self.ratings["fail"])
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
7
requirements-dev.txt
Normal file
7
requirements-dev.txt
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
build
|
||||||
|
wheel
|
||||||
|
black
|
||||||
|
toml
|
||||||
|
nuitka
|
||||||
|
ordered-set
|
||||||
|
PyQt5-stubs
|
2
setup.py
2
setup.py
|
@ -47,5 +47,5 @@ setuptools.setup(
|
||||||
python_requires=">=3.8",
|
python_requires=">=3.8",
|
||||||
entry_points=dict(console_scripts=["rare=rare.__main__:main"]),
|
entry_points=dict(console_scripts=["rare=rare.__main__:main"]),
|
||||||
install_requires=requirements,
|
install_requires=requirements,
|
||||||
extras_require=optional_reqs
|
extras_require=optional_reqs,
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in a new issue