Compare commits
25 Commits
2753e53a4d
...
main
Author | SHA1 | Date | |
---|---|---|---|
0294c90c54
|
|||
17dfef2d27
|
|||
|
f0690f8811
|
||
ac20447ba3
|
|||
ba143c15a8
|
|||
13068f3959
|
|||
|
c8360d08ca | ||
b070ff1fca
|
|||
b5a2f41bdf
|
|||
9a37f31841
|
|||
aeed0112cd
|
|||
027ae68d4d
|
|||
37d41fef8d
|
|||
e37422fc95
|
|||
d7951e8587
|
|||
556533785a
|
|||
a13aca4d84
|
|||
35736e1723
|
|||
|
24a7c2e657
|
||
|
279f7ec36b
|
||
41f6943998
|
|||
3bf10dc4cd
|
|||
33b96d3185
|
|||
3573b8e373
|
|||
582ddd2218
|
@@ -8,11 +8,24 @@ on:
|
|||||||
jobs:
|
jobs:
|
||||||
renovate:
|
renovate:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
container: ghcr.io/renovatebot/renovate:41.1.4
|
container: ghcr.io/renovatebot/renovate:latest
|
||||||
steps:
|
steps:
|
||||||
- uses: https://gitea.com/actions/checkout@v4
|
- uses: https://gitea.com/actions/checkout@v4
|
||||||
- run: renovate
|
|
||||||
|
- name: Install uv
|
||||||
|
uses: https://github.com/astral-sh/setup-uv@v6
|
||||||
|
with:
|
||||||
|
enable-cache: true
|
||||||
|
|
||||||
|
- name: Download external renovate config
|
||||||
|
run: |
|
||||||
|
mkdir -p /tmp/renovate-config
|
||||||
|
curl -fsSL "https://git.linux-gaming.ru/Linux-Gaming/renovate-config/raw/branch/main/config.js" \
|
||||||
|
-o /tmp/renovate-config/config.js
|
||||||
|
|
||||||
|
- name: Run Renovate
|
||||||
|
run: renovate
|
||||||
env:
|
env:
|
||||||
RENOVATE_CONFIG_FILE: "/workspace/Boria138/PortProtonQt/config.js"
|
RENOVATE_CONFIG_FILE: "/tmp/renovate-config/config.js"
|
||||||
LOG_LEVEL: "debug"
|
LOG_LEVEL: "debug"
|
||||||
RENOVATE_TOKEN: ${{ secrets.RENOVATE_TOKEN }}
|
RENOVATE_TOKEN: ${{ secrets.RENOVATE_TOKEN }}
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
exclude: '(data/|documentation/|portprotonqt/locales/|portprotonqt/custom_data/|dev-scripts/|\.venv/|venv/|.*\.svg$)'
|
exclude: '(data/|documentation/|portprotonqt/locales/|portprotonqt/custom_data/|dev-scripts/|\.venv/|venv/|.*\.svg$)'
|
||||||
repos:
|
repos:
|
||||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||||
rev: v5.0.0
|
rev: v6.0.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: trailing-whitespace
|
- id: trailing-whitespace
|
||||||
- id: end-of-file-fixer
|
- id: end-of-file-fixer
|
||||||
@@ -11,15 +11,14 @@ repos:
|
|||||||
- id: check-yaml
|
- id: check-yaml
|
||||||
|
|
||||||
- repo: https://github.com/astral-sh/uv-pre-commit
|
- repo: https://github.com/astral-sh/uv-pre-commit
|
||||||
rev: 0.6.14
|
rev: 0.8.9
|
||||||
hooks:
|
hooks:
|
||||||
- id: uv-lock
|
- id: uv-lock
|
||||||
|
|
||||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||||
rev: v0.11.5
|
rev: v0.12.8
|
||||||
hooks:
|
hooks:
|
||||||
- id: ruff
|
- id: ruff-check
|
||||||
args: [--fix]
|
|
||||||
|
|
||||||
- repo: local
|
- repo: local
|
||||||
hooks:
|
hooks:
|
||||||
|
@@ -7,12 +7,17 @@
|
|||||||
|
|
||||||
### Added
|
### Added
|
||||||
- Больше типов анимаций при открытии карточки игры (за подробностями в документацию)
|
- Больше типов анимаций при открытии карточки игры (за подробностями в документацию)
|
||||||
|
- Анимация при выходе из карточки игры (за подробностями в документацию)
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- Уменьшена длительность анимации открытия карточки с 800 до 350мс
|
- Уменьшена длительность анимации открытия карточки с 800 до 350мс
|
||||||
- Контекстное меню при открытие теперь сразу фокусируется на первом элементе
|
- Контекстное меню при открытие теперь сразу фокусируется на первом элементе
|
||||||
- Анимации теперь можно настраивать через темы (за подробностями в документацию)
|
- Анимации теперь можно настраивать через темы (за подробностями в документацию)
|
||||||
- Общие json (steam_apps и anticheat_games) теперь перекачиваются если сломаны
|
- Общие json (steam_apps и anticheat_games) теперь перекачиваются если сломаны
|
||||||
|
- Временно удалена светлая тема
|
||||||
|
- Добавление и удаление игр из Steam теперь не требует перезагрузки Steam
|
||||||
|
- Обновлены все зависимости (затрагивает только AppImage)
|
||||||
|
- Удалён отдельный трей так как у PortProton есть свой трей
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- legendary list теперь не вызывается если вход в EGS не был произведён
|
- legendary list теперь не вызывается если вход в EGS не был произведён
|
||||||
@@ -20,8 +25,8 @@
|
|||||||
- Данные от HLTB теперь не отображаются в карточке если нет данных о времени прохождения
|
- Данные от HLTB теперь не отображаются в карточке если нет данных о времени прохождения
|
||||||
- Диалог добавления игры теперь не добавляет игру если exe не существует
|
- Диалог добавления игры теперь не добавляет игру если exe не существует
|
||||||
|
|
||||||
|
|
||||||
### Contributors
|
### Contributors
|
||||||
|
- @Alex Smith
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
2
TODO.md
@@ -41,7 +41,7 @@
|
|||||||
- [X] Получать slug через GraphQL [запрос](https://launcher.store.epicgames.com/graphql)
|
- [X] Получать slug через GraphQL [запрос](https://launcher.store.epicgames.com/graphql)
|
||||||
- [X] Добавить на карточку бейдж, указывающий, что игра из Steam
|
- [X] Добавить на карточку бейдж, указывающий, что игра из Steam
|
||||||
- [X] Добавить поддержку версий Steam для Flatpak и Snap
|
- [X] Добавить поддержку версий Steam для Flatpak и Snap
|
||||||
- [ ] Реализовать добавление игры как сторонней в Steam без перезапуска
|
- [X] Реализовать добавление игры как сторонней в Steam без перезапуска
|
||||||
- [X] Отображать данные о самом последнем пользователе Steam, а не первом попавшемся
|
- [X] Отображать данные о самом последнем пользователе Steam, а не первом попавшемся
|
||||||
- [X] Исправить склонения в детальном выводе времени, например, не «3 часов назад», а «3 часа назад»
|
- [X] Исправить склонения в детальном выводе времени, например, не «3 часов назад», а «3 часа назад»
|
||||||
- [X] Добавить перевод через gettext [Документация](documentation/localization_guide)
|
- [X] Добавить перевод через gettext [Документация](documentation/localization_guide)
|
||||||
|
@@ -6,7 +6,7 @@ arch=('any')
|
|||||||
url="https://git.linux-gaming.ru/Boria138/PortProtonQt"
|
url="https://git.linux-gaming.ru/Boria138/PortProtonQt"
|
||||||
license=('GPL-3.0')
|
license=('GPL-3.0')
|
||||||
depends=('python-numpy' 'python-requests' 'python-babel' 'python-evdev' 'python-pyudev' 'python-orjson'
|
depends=('python-numpy' 'python-requests' 'python-babel' 'python-evdev' 'python-pyudev' 'python-orjson'
|
||||||
'python-psutil' 'python-tqdm' 'python-vdf' 'pyside6' 'icoextract' 'python-pillow' 'perl-image-exiftool' 'xdg-utils' 'python-beautifulsoup4')
|
'python-psutil' 'python-tqdm' 'python-vdf' 'pyside6' 'icoextract' 'python-pillow' 'perl-image-exiftool' 'xdg-utils' 'python-beautifulsoup4' 'python-websocket-client')
|
||||||
makedepends=('python-'{'build','installer','setuptools','wheel'})
|
makedepends=('python-'{'build','installer','setuptools','wheel'})
|
||||||
source=("git+https://git.linux-gaming.ru/Boria138/PortProtonQt#tag=v$pkgver")
|
source=("git+https://git.linux-gaming.ru/Boria138/PortProtonQt#tag=v$pkgver")
|
||||||
sha256sums=('SKIP')
|
sha256sums=('SKIP')
|
||||||
|
@@ -6,7 +6,7 @@ arch=('any')
|
|||||||
url="https://git.linux-gaming.ru/Boria138/PortProtonQt"
|
url="https://git.linux-gaming.ru/Boria138/PortProtonQt"
|
||||||
license=('GPL-3.0')
|
license=('GPL-3.0')
|
||||||
depends=('python-numpy' 'python-requests' 'python-babel' 'python-evdev' 'python-pyudev' 'python-orjson'
|
depends=('python-numpy' 'python-requests' 'python-babel' 'python-evdev' 'python-pyudev' 'python-orjson'
|
||||||
'python-psutil' 'python-tqdm' 'python-vdf' 'pyside6' 'icoextract' 'python-pillow' 'perl-image-exiftool' 'xdg-utils' 'python-beautifulsoup4')
|
'python-psutil' 'python-tqdm' 'python-vdf' 'pyside6' 'icoextract' 'python-pillow' 'perl-image-exiftool' 'xdg-utils' 'python-beautifulsoup4' 'python-websocket-client')
|
||||||
makedepends=('python-'{'build','installer','setuptools','wheel'})
|
makedepends=('python-'{'build','installer','setuptools','wheel'})
|
||||||
source=("git+https://git.linux-gaming.ru/Boria138/PortProtonQt.git")
|
source=("git+https://git.linux-gaming.ru/Boria138/PortProtonQt.git")
|
||||||
sha256sums=('SKIP')
|
sha256sums=('SKIP')
|
||||||
|
@@ -33,6 +33,7 @@ Requires: python3-babel
|
|||||||
Requires: python3-evdev
|
Requires: python3-evdev
|
||||||
Requires: python3-icoextract
|
Requires: python3-icoextract
|
||||||
Requires: python3-numpy
|
Requires: python3-numpy
|
||||||
|
Requires: python3-websocket-client
|
||||||
Requires: python3-orjson
|
Requires: python3-orjson
|
||||||
Requires: python3-psutil
|
Requires: python3-psutil
|
||||||
Requires: python3-pyside6
|
Requires: python3-pyside6
|
||||||
|
@@ -30,6 +30,7 @@ Requires: python3-babel
|
|||||||
Requires: python3-evdev
|
Requires: python3-evdev
|
||||||
Requires: python3-icoextract
|
Requires: python3-icoextract
|
||||||
Requires: python3-numpy
|
Requires: python3-numpy
|
||||||
|
Requires: python3-websocket-client
|
||||||
Requires: python3-orjson
|
Requires: python3-orjson
|
||||||
Requires: python3-psutil
|
Requires: python3-psutil
|
||||||
Requires: python3-pyside6
|
Requires: python3-pyside6
|
||||||
|
@@ -1,8 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
"endpoint": "https://git.linux-gaming.ru/api/v1",
|
|
||||||
"gitAuthor": "Renovate Bot <noreply@linux-gaming.ru>",
|
|
||||||
"platform": "gitea",
|
|
||||||
"onboardingConfigFileName": "renovate.json",
|
|
||||||
"autodiscover": true,
|
|
||||||
"optimizeForDisabled": true,
|
|
||||||
};
|
|
@@ -3,10 +3,11 @@
|
|||||||
---
|
---
|
||||||
|
|
||||||
## 📋 Contents
|
## 📋 Contents
|
||||||
- [Overview](#overview)
|
- [Overview](#-overview)
|
||||||
- [Adding a New Translation](#adding-a-new-translation)
|
- [Adding a New Translation](#-adding-a-new-translation)
|
||||||
- [Updating Existing Translations](#updating-existing-translations)
|
- [Updating Existing Translations](#-updating-existing-translations)
|
||||||
- [Compiling Translations](#compiling-translations)
|
- [Compiling Translations](#-compiling-translations)
|
||||||
|
- [Spell Check](#-spell-check)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
@@ -3,10 +3,11 @@
|
|||||||
---
|
---
|
||||||
|
|
||||||
## 📋 Содержание
|
## 📋 Содержание
|
||||||
- [Обзор](#обзор)
|
- [Обзор](#-обзор)
|
||||||
- [Добавление нового перевода](#добавление-нового-перевода)
|
- [Добавление нового перевода](#-добавление-нового-перевода)
|
||||||
- [Обновление существующих переводов](#обновление-существующих-переводов)
|
- [Обновление существующих переводов](#-обновление-существующих-переводов)
|
||||||
- [Компиляция переводов](#компиляция-переводов)
|
- [Компиляция переводов](#-компиляция-переводов)
|
||||||
|
- [Проверка орфографии](#-проверка-орфографии)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
@@ -3,15 +3,10 @@
|
|||||||
---
|
---
|
||||||
|
|
||||||
## 📋 Contents
|
## 📋 Contents
|
||||||
- [Overview](#overview)
|
- [Overview](#-overview)
|
||||||
- [How It Works](#how-it-works)
|
- [How It Works](#-how-it-works)
|
||||||
- [Data Priorities](#data-priorities)
|
- [For Users](#-for-users)
|
||||||
- [File Structure](#file-structure)
|
- [For Developers](#-for-developers)
|
||||||
- [For Users](#for-users)
|
|
||||||
- [Creating User Overrides](#creating-user-overrides)
|
|
||||||
- [Example](#example)
|
|
||||||
- [For Developers](#for-developers)
|
|
||||||
- [Adding Built-In Overrides](#adding-built-in-overrides)
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
@@ -3,15 +3,10 @@
|
|||||||
---
|
---
|
||||||
|
|
||||||
## 📋 Содержание
|
## 📋 Содержание
|
||||||
- [Обзор](#обзор)
|
- [Обзор](#-обзор)
|
||||||
- [Как это работает](#как-это-работает)
|
- [Как это работает](#-как-это-работает)
|
||||||
- [Приоритеты данных](#приоритеты-данных)
|
- [Для пользователей](#-для-пользователей)
|
||||||
- [Структура файлов](#структура-файлов)
|
- [Для разработчиков](#-для-разработчиков)
|
||||||
- [Для пользователей](#для-пользователей)
|
|
||||||
- [Создание пользовательских переопределений](#создание-пользовательских-переопределений)
|
|
||||||
- [Пример](#пример)
|
|
||||||
- [Для разработчиков](#для-разработчиков)
|
|
||||||
- [Добавление встроенных переопределений](#добавление-встроенных-переопределений)
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
@@ -52,42 +52,103 @@ The `GAME_CARD_ANIMATION` dictionary controls all animation parameters for game
|
|||||||
|
|
||||||
```python
|
```python
|
||||||
GAME_CARD_ANIMATION = {
|
GAME_CARD_ANIMATION = {
|
||||||
# Animation type when transitioning to a detailed page
|
# Type of animation when entering and exiting the detail page
|
||||||
# Available values: "fade", "slide_left", "slide_right", "slide_up", "slide_down", "bounce"
|
# Possible values: "fade", "slide_left", "slide_right", "slide_up", "slide_down", "bounce"
|
||||||
"detail_page_animation_type": "fade",
|
"detail_page_animation_type": "fade",
|
||||||
|
|
||||||
# Border width settings (in pixels)
|
# Border width of the card in idle state (no hover or focus).
|
||||||
|
# Affects the thickness of the border when the card is not highlighted.
|
||||||
|
# Value in pixels.
|
||||||
"default_border_width": 2,
|
"default_border_width": 2,
|
||||||
|
|
||||||
|
# Border width on hover.
|
||||||
|
# Increases the border thickness when the cursor is over the card.
|
||||||
|
# Value in pixels.
|
||||||
"hover_border_width": 8,
|
"hover_border_width": 8,
|
||||||
|
|
||||||
|
# Border width on focus (e.g., selected via keyboard).
|
||||||
|
# Increases the border thickness when the card is focused.
|
||||||
|
# Value in pixels.
|
||||||
"focus_border_width": 12,
|
"focus_border_width": 12,
|
||||||
|
|
||||||
|
# Minimum border width during pulsing animation.
|
||||||
|
# Sets the minimum border thickness during the "breathing" animation.
|
||||||
|
# Value in pixels.
|
||||||
"pulse_min_border_width": 8,
|
"pulse_min_border_width": 8,
|
||||||
|
|
||||||
|
# Maximum border width during pulsing animation.
|
||||||
|
# Sets the maximum border thickness during pulsing.
|
||||||
|
# Value in pixels.
|
||||||
"pulse_max_border_width": 10,
|
"pulse_max_border_width": 10,
|
||||||
|
|
||||||
# Animation duration (in milliseconds)
|
# Duration of the border thickness animation (e.g., on hover or focus).
|
||||||
|
# Affects the speed of transition between different border widths.
|
||||||
|
# Value in milliseconds.
|
||||||
"thickness_anim_duration": 300,
|
"thickness_anim_duration": 300,
|
||||||
|
|
||||||
|
# Duration of one pulsing animation cycle.
|
||||||
|
# Defines how fast the border "pulses" between min and max values.
|
||||||
|
# Value in milliseconds.
|
||||||
"pulse_anim_duration": 800,
|
"pulse_anim_duration": 800,
|
||||||
|
|
||||||
|
# Duration of the gradient rotation animation.
|
||||||
|
# Affects how fast the gradient border rotates around the card.
|
||||||
|
# Value in milliseconds.
|
||||||
"gradient_anim_duration": 3000,
|
"gradient_anim_duration": 3000,
|
||||||
|
|
||||||
# Gradient animation angles (in degrees)
|
# Starting angle of the gradient (in degrees).
|
||||||
|
# Defines the initial rotation point of the gradient when the animation starts.
|
||||||
"gradient_start_angle": 360,
|
"gradient_start_angle": 360,
|
||||||
|
|
||||||
|
# Ending angle of the gradient (in degrees).
|
||||||
|
# Defines the end rotation point of the gradient.
|
||||||
|
# A value of 0 means a full 360-degree rotation.
|
||||||
"gradient_end_angle": 0,
|
"gradient_end_angle": 0,
|
||||||
|
|
||||||
# Smoothing curves for smooth animations
|
# Easing curve type for border expansion animation (on hover/focus).
|
||||||
|
# Affects the "feel" of the animation (e.g., smooth acceleration or deceleration).
|
||||||
|
# Possible values: strings corresponding to QEasingCurve.Type (e.g., "OutBack", "InOutQuad").
|
||||||
"thickness_easing_curve": "OutBack",
|
"thickness_easing_curve": "OutBack",
|
||||||
|
|
||||||
|
# Easing curve type for border contraction animation (on mouse leave/focus loss).
|
||||||
|
# Affects the "feel" of returning to the original border width.
|
||||||
"thickness_easing_curve_out": "InBack",
|
"thickness_easing_curve_out": "InBack",
|
||||||
|
|
||||||
# Gradient colors for animated stroke
|
# Gradient colors for the animated border.
|
||||||
|
# A list of dictionaries where each defines a position (0.0–1.0) and color in hex format.
|
||||||
|
# Affects the appearance of the border on hover or focus.
|
||||||
"gradient_colors": [
|
"gradient_colors": [
|
||||||
{"position": 0, "color": "#00fff5"},
|
{"position": 0, "color": "#00fff5"}, # Start color (cyan)
|
||||||
{"position": 0.33, "color": "#FF5733"},
|
{"position": 0.33, "color": "#FF5733"}, # 33% color (orange)
|
||||||
{"position": 0.66, "color": "#9B59B6"},
|
{"position": 0.66, "color": "#9B59B6"}, # 66% color (purple)
|
||||||
{"position": 1, "color": "#00fff5"}
|
{"position": 1, "color": "#00fff5"} # End color (back to cyan)
|
||||||
],
|
],
|
||||||
|
|
||||||
# Duration of transitions to the detailed page
|
# Duration of the fade animation when entering the detail page
|
||||||
"detail_page_fade_duration": 350,
|
"detail_page_fade_duration": 350,
|
||||||
|
|
||||||
|
# Duration of the slide animation when entering the detail page
|
||||||
"detail_page_slide_duration": 500,
|
"detail_page_slide_duration": 500,
|
||||||
"detail_page_zoom_duration": 400
|
|
||||||
|
# Duration of the bounce animation when entering the detail page
|
||||||
|
"detail_page_bounce_duration": 400,
|
||||||
|
|
||||||
|
# Duration of the fade animation when exiting the detail page
|
||||||
|
"detail_page_fade_duration_exit": 350,
|
||||||
|
|
||||||
|
# Duration of the slide animation when exiting the detail page
|
||||||
|
"detail_page_slide_duration_exit": 500,
|
||||||
|
|
||||||
|
# Duration of the bounce animation when exiting the detail page
|
||||||
|
"detail_page_bounce_duration_exit": 400,
|
||||||
|
|
||||||
|
# Easing curve type for animation when entering the detail page
|
||||||
|
# Applies to slide and bounce animations
|
||||||
|
"detail_page_easing_curve": "OutCubic",
|
||||||
|
|
||||||
|
# Easing curve type for animation when exiting the detail page
|
||||||
|
# Applies to slide and bounce animations
|
||||||
|
"detail_page_easing_curve_exit": "InCubic"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@@ -52,42 +52,103 @@ def custom_button_style(color1, color2):
|
|||||||
|
|
||||||
```python
|
```python
|
||||||
GAME_CARD_ANIMATION = {
|
GAME_CARD_ANIMATION = {
|
||||||
# Тип анимации при переходе на детальную страницу
|
# Тип анимации при входе и выходе на детальную страницу
|
||||||
# Доступные значения: "fade", "slide_left", "slide_right", "slide_up", "slide_down", "bounce"
|
# Возможные значения: "fade", "slide_left", "slide_right", "slide_up", "slide_down", "bounce"
|
||||||
"detail_page_animation_type": "fade",
|
"detail_page_animation_type": "fade",
|
||||||
|
|
||||||
# Настройки ширины обводки (в пикселях)
|
# Ширина обводки карточки в состоянии покоя (без наведения или фокуса).
|
||||||
|
# Влияет на толщину рамки вокруг карточки, когда она не выделена.
|
||||||
|
# Значение в пикселях.
|
||||||
"default_border_width": 2,
|
"default_border_width": 2,
|
||||||
|
|
||||||
|
# Ширина обводки при наведении курсора.
|
||||||
|
# Увеличивает толщину рамки, когда курсор находится над карточкой.
|
||||||
|
# Значение в пикселях.
|
||||||
"hover_border_width": 8,
|
"hover_border_width": 8,
|
||||||
|
|
||||||
|
# Ширина обводки при фокусе (например, при выборе с клавиатуры).
|
||||||
|
# Увеличивает толщину рамки, когда карточка в фокусе.
|
||||||
|
# Значение в пикселях.
|
||||||
"focus_border_width": 12,
|
"focus_border_width": 12,
|
||||||
|
|
||||||
|
# Минимальная ширина обводки во время пульсирующей анимации.
|
||||||
|
# Определяет минимальную толщину рамки при пульсации (анимация "дыхания").
|
||||||
|
# Значение в пикселях.
|
||||||
"pulse_min_border_width": 8,
|
"pulse_min_border_width": 8,
|
||||||
|
|
||||||
|
# Максимальная ширина обводки во время пульсирующей анимации.
|
||||||
|
# Определяет максимальную толщину рамки при пульсации.
|
||||||
|
# Значение в пикселях.
|
||||||
"pulse_max_border_width": 10,
|
"pulse_max_border_width": 10,
|
||||||
|
|
||||||
# Длительности анимаций (в миллисекундах)
|
# Длительность анимации изменения толщины обводки (например, при наведении или фокусе).
|
||||||
|
# Влияет на скорость перехода от одной ширины обводки к другой.
|
||||||
|
# Значение в миллисекундах.
|
||||||
"thickness_anim_duration": 300,
|
"thickness_anim_duration": 300,
|
||||||
|
|
||||||
|
# Длительность одного цикла пульсирующей анимации.
|
||||||
|
# Определяет, как быстро рамка "пульсирует" между min и max значениями.
|
||||||
|
# Значение в миллисекундах.
|
||||||
"pulse_anim_duration": 800,
|
"pulse_anim_duration": 800,
|
||||||
|
|
||||||
|
# Длительность анимации вращения градиента.
|
||||||
|
# Влияет на скорость, с которой градиентная обводка вращается вокруг карточки.
|
||||||
|
# Значение в миллисекундах.
|
||||||
"gradient_anim_duration": 3000,
|
"gradient_anim_duration": 3000,
|
||||||
|
|
||||||
# Углы анимации градиента (в градусах)
|
# Начальный угол градиента (в градусах).
|
||||||
|
# Определяет начальную точку вращения градиента при старте анимации.
|
||||||
"gradient_start_angle": 360,
|
"gradient_start_angle": 360,
|
||||||
|
|
||||||
|
# Конечный угол градиента (в градусах).
|
||||||
|
# Определяет конечную точку вращения градиента.
|
||||||
|
# Значение 0 означает полный поворот на 360 градусов.
|
||||||
"gradient_end_angle": 0,
|
"gradient_end_angle": 0,
|
||||||
|
|
||||||
# Кривые сглаживания для плавных анимаций
|
# Тип кривой сглаживания для анимации увеличения обводки (при наведении/фокусе).
|
||||||
|
# Влияет на "чувство" анимации (например, плавное ускорение или замедление).
|
||||||
|
# Возможные значения: строки, соответствующие QEasingCurve.Type (например, "OutBack", "InOutQuad").
|
||||||
"thickness_easing_curve": "OutBack",
|
"thickness_easing_curve": "OutBack",
|
||||||
|
|
||||||
|
# Тип кривой сглаживания для анимации уменьшения обводки (при уходе курсора/потере фокуса).
|
||||||
|
# Влияет на "чувство" возврата к исходной ширине обводки.
|
||||||
"thickness_easing_curve_out": "InBack",
|
"thickness_easing_curve_out": "InBack",
|
||||||
|
|
||||||
# Цвета градиента для анимированной обводки
|
# Цвета градиента для анимированной обводки.
|
||||||
|
# Список словарей, где каждый словарь задает позицию (0.0–1.0) и цвет в формате hex.
|
||||||
|
# Влияет на внешний вид обводки при наведении или фокусе.
|
||||||
"gradient_colors": [
|
"gradient_colors": [
|
||||||
{"position": 0, "color": "#00fff5"},
|
{"position": 0, "color": "#00fff5"}, # Начальный цвет (циан)
|
||||||
{"position": 0.33, "color": "#FF5733"},
|
{"position": 0.33, "color": "#FF5733"}, # Цвет на 33% (оранжевый)
|
||||||
{"position": 0.66, "color": "#9B59B6"},
|
{"position": 0.66, "color": "#9B59B6"}, # Цвет на 66% (пурпурный)
|
||||||
{"position": 1, "color": "#00fff5"}
|
{"position": 1, "color": "#00fff5"} # Конечный цвет (возвращение к циану)
|
||||||
],
|
],
|
||||||
|
|
||||||
# Длительности переходов на детальную страницу
|
# Длительность анимации fade при входе на детальную страницу
|
||||||
"detail_page_fade_duration": 350,
|
"detail_page_fade_duration": 350,
|
||||||
|
|
||||||
|
# Длительность анимации slide при входе на детальную страницу
|
||||||
"detail_page_slide_duration": 500,
|
"detail_page_slide_duration": 500,
|
||||||
"detail_page_zoom_duration": 400
|
|
||||||
|
# Длительность анимации bounce при входе на детальную страницу
|
||||||
|
"detail_page_bounce_duration": 400,
|
||||||
|
|
||||||
|
# Длительность анимации fade при выходе из детальной страницы
|
||||||
|
"detail_page_fade_duration_exit": 350,
|
||||||
|
|
||||||
|
# Длительность анимации slide при выходе из детальной страницы
|
||||||
|
"detail_page_slide_duration_exit": 500,
|
||||||
|
|
||||||
|
# Длительность анимации bounce при выходе из детальной страницы
|
||||||
|
"detail_page_bounce_duration_exit": 400,
|
||||||
|
|
||||||
|
# Тип кривой сглаживания для анимации при входе на детальную страницу
|
||||||
|
# Применяется к slide и bounce анимациям
|
||||||
|
"detail_page_easing_curve": "OutCubic",
|
||||||
|
|
||||||
|
# Тип кривой сглаживания для анимации при выходе из детальной страницы
|
||||||
|
# Применяется к slide и bounce анимациям
|
||||||
|
"detail_page_easing_curve_exit": "InCubic"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@@ -1,8 +1,24 @@
|
|||||||
from PySide6.QtCore import QPropertyAnimation, QByteArray, QEasingCurve, QAbstractAnimation, QParallelAnimationGroup, QRect, Qt
|
from PySide6.QtCore import QPropertyAnimation, QByteArray, QEasingCurve, QAbstractAnimation, QParallelAnimationGroup, QRect, Qt, QPoint
|
||||||
from PySide6.QtGui import QPainter, QPen, QColor, QConicalGradient, QBrush
|
from PySide6.QtGui import QPainter, QPen, QColor, QConicalGradient, QBrush
|
||||||
from PySide6.QtWidgets import QWidget, QGraphicsOpacityEffect
|
from PySide6.QtWidgets import QWidget, QGraphicsOpacityEffect
|
||||||
from collections.abc import Callable
|
from collections.abc import Callable
|
||||||
import portprotonqt.themes.standart.styles as default_styles
|
import portprotonqt.themes.standart.styles as default_styles
|
||||||
|
from portprotonqt.logger import get_logger
|
||||||
|
|
||||||
|
logger = get_logger(__name__)
|
||||||
|
|
||||||
|
class SafeOpacityEffect(QGraphicsOpacityEffect):
|
||||||
|
def __init__(self, parent=None, disable_at_full=True):
|
||||||
|
super().__init__(parent)
|
||||||
|
self.disable_at_full = disable_at_full
|
||||||
|
|
||||||
|
def setOpacity(self, opacity: float):
|
||||||
|
opacity = max(0.0, min(1.0, opacity))
|
||||||
|
super().setOpacity(opacity)
|
||||||
|
if opacity < 1.0:
|
||||||
|
self.setEnabled(True)
|
||||||
|
elif self.disable_at_full:
|
||||||
|
self.setEnabled(False)
|
||||||
|
|
||||||
class GameCardAnimations:
|
class GameCardAnimations:
|
||||||
def __init__(self, game_card, theme=None):
|
def __init__(self, game_card, theme=None):
|
||||||
@@ -38,7 +54,6 @@ class GameCardAnimations:
|
|||||||
self.game_card.hoverChanged.emit(self.game_card.name, True)
|
self.game_card.hoverChanged.emit(self.game_card.name, True)
|
||||||
self.game_card.setFocus(Qt.FocusReason.MouseFocusReason)
|
self.game_card.setFocus(Qt.FocusReason.MouseFocusReason)
|
||||||
|
|
||||||
# Ensure thickness_anim is initialized
|
|
||||||
if not self.thickness_anim:
|
if not self.thickness_anim:
|
||||||
self.setup_animations()
|
self.setup_animations()
|
||||||
|
|
||||||
@@ -90,7 +105,6 @@ class GameCardAnimations:
|
|||||||
self.game_card._focused = True
|
self.game_card._focused = True
|
||||||
self.game_card.focusChanged.emit(self.game_card.name, True)
|
self.game_card.focusChanged.emit(self.game_card.name, True)
|
||||||
|
|
||||||
# Ensure thickness_anim is initialized
|
|
||||||
if not self.thickness_anim:
|
if not self.thickness_anim:
|
||||||
self.setup_animations()
|
self.setup_animations()
|
||||||
|
|
||||||
@@ -137,7 +151,9 @@ class GameCardAnimations:
|
|||||||
self.thickness_anim.start()
|
self.thickness_anim.start()
|
||||||
|
|
||||||
def paint_border(self, painter: QPainter):
|
def paint_border(self, painter: QPainter):
|
||||||
"""Paint the animated border for the GameCard."""
|
if not painter.isActive():
|
||||||
|
logger.warning("Painter is not active; skipping border paint")
|
||||||
|
return
|
||||||
painter.setRenderHint(QPainter.RenderHint.Antialiasing)
|
painter.setRenderHint(QPainter.RenderHint.Antialiasing)
|
||||||
pen = QPen()
|
pen = QPen()
|
||||||
pen.setWidth(self.game_card._borderWidth)
|
pen.setWidth(self.game_card._borderWidth)
|
||||||
@@ -153,6 +169,8 @@ class GameCardAnimations:
|
|||||||
radius = 18
|
radius = 18
|
||||||
bw = round(self.game_card._borderWidth / 2)
|
bw = round(self.game_card._borderWidth / 2)
|
||||||
rect = self.game_card.rect().adjusted(bw, bw, -bw, -bw)
|
rect = self.game_card.rect().adjusted(bw, bw, -bw, -bw)
|
||||||
|
if rect.isEmpty():
|
||||||
|
return # Avoid drawing invalid rect
|
||||||
painter.drawRoundedRect(rect, radius, radius)
|
painter.drawRoundedRect(rect, radius, radius)
|
||||||
|
|
||||||
class DetailPageAnimations:
|
class DetailPageAnimations:
|
||||||
@@ -163,71 +181,50 @@ class DetailPageAnimations:
|
|||||||
|
|
||||||
def animate_detail_page(self, detail_page: QWidget, load_image_and_restore_effect: Callable, cleanup_animation: Callable):
|
def animate_detail_page(self, detail_page: QWidget, load_image_and_restore_effect: Callable, cleanup_animation: Callable):
|
||||||
"""Animate the detail page based on theme settings."""
|
"""Animate the detail page based on theme settings."""
|
||||||
shadow = detail_page.graphicsEffect()
|
|
||||||
animation_type = self.theme.GAME_CARD_ANIMATION.get("detail_page_animation_type", "fade")
|
animation_type = self.theme.GAME_CARD_ANIMATION.get("detail_page_animation_type", "fade")
|
||||||
duration = self.theme.GAME_CARD_ANIMATION.get("detail_page_fade_duration", 350)
|
duration = self.theme.GAME_CARD_ANIMATION.get("detail_page_fade_duration", 350)
|
||||||
|
|
||||||
if animation_type == "fade":
|
if animation_type == "fade":
|
||||||
opacity_effect = QGraphicsOpacityEffect(detail_page)
|
original_effect = detail_page.graphicsEffect()
|
||||||
|
opacity_effect = SafeOpacityEffect(detail_page, disable_at_full=True)
|
||||||
|
opacity_effect.setOpacity(0.0)
|
||||||
detail_page.setGraphicsEffect(opacity_effect)
|
detail_page.setGraphicsEffect(opacity_effect)
|
||||||
animation = QPropertyAnimation(opacity_effect, QByteArray(b"opacity"))
|
animation = QPropertyAnimation(opacity_effect, QByteArray(b"opacity"))
|
||||||
animation.setDuration(duration)
|
animation.setDuration(duration)
|
||||||
animation.setStartValue(0)
|
animation.setStartValue(0.0)
|
||||||
animation.setEndValue(1)
|
animation.setEndValue(0.999)
|
||||||
animation.start(QAbstractAnimation.DeletionPolicy.DeleteWhenStopped)
|
animation.start(QAbstractAnimation.DeletionPolicy.DeleteWhenStopped)
|
||||||
self.animations[detail_page] = animation
|
self.animations[detail_page] = animation
|
||||||
animation.finished.connect(lambda: detail_page.setGraphicsEffect(shadow) if shadow is not None else detail_page.setGraphicsEffect(None)) # type: ignore
|
def restore_effect():
|
||||||
|
try:
|
||||||
|
detail_page.setGraphicsEffect(original_effect) # type: ignore
|
||||||
|
except RuntimeError:
|
||||||
|
logger.debug("Original effect already deleted")
|
||||||
|
animation.finished.connect(restore_effect)
|
||||||
animation.finished.connect(load_image_and_restore_effect)
|
animation.finished.connect(load_image_and_restore_effect)
|
||||||
elif animation_type == "slide_left":
|
animation.finished.connect(opacity_effect.deleteLater)
|
||||||
|
elif animation_type in ["slide_left", "slide_right", "slide_up", "slide_down"]:
|
||||||
duration = self.theme.GAME_CARD_ANIMATION.get("detail_page_slide_duration", 500)
|
duration = self.theme.GAME_CARD_ANIMATION.get("detail_page_slide_duration", 500)
|
||||||
detail_page.move(self.main_window.width(), 0)
|
easing_curve = QEasingCurve(QEasingCurve.Type[self.theme.GAME_CARD_ANIMATION.get("detail_page_easing_curve", "OutCubic")])
|
||||||
|
start_pos = {
|
||||||
|
"slide_left": QPoint(self.main_window.width(), 0),
|
||||||
|
"slide_right": QPoint(-self.main_window.width(), 0),
|
||||||
|
"slide_up": QPoint(0, self.main_window.height()),
|
||||||
|
"slide_down": QPoint(0, -self.main_window.height())
|
||||||
|
}[animation_type]
|
||||||
|
detail_page.move(start_pos)
|
||||||
animation = QPropertyAnimation(detail_page, QByteArray(b"pos"))
|
animation = QPropertyAnimation(detail_page, QByteArray(b"pos"))
|
||||||
animation.setDuration(duration)
|
animation.setDuration(duration)
|
||||||
animation.setStartValue(detail_page.pos())
|
animation.setStartValue(start_pos)
|
||||||
animation.setEndValue(self.main_window.stackedWidget.rect().topLeft())
|
animation.setEndValue(self.main_window.stackedWidget.rect().topLeft())
|
||||||
animation.setEasingCurve(QEasingCurve.Type.OutCubic)
|
animation.setEasingCurve(easing_curve)
|
||||||
animation.start(QAbstractAnimation.DeletionPolicy.DeleteWhenStopped)
|
|
||||||
self.animations[detail_page] = animation
|
|
||||||
animation.finished.connect(cleanup_animation)
|
|
||||||
animation.finished.connect(load_image_and_restore_effect)
|
|
||||||
elif animation_type == "slide_right":
|
|
||||||
duration = self.theme.GAME_CARD_ANIMATION.get("detail_page_slide_duration", 500)
|
|
||||||
detail_page.move(-self.main_window.width(), 0)
|
|
||||||
animation = QPropertyAnimation(detail_page, QByteArray(b"pos"))
|
|
||||||
animation.setDuration(duration)
|
|
||||||
animation.setStartValue(detail_page.pos())
|
|
||||||
animation.setEndValue(self.main_window.stackedWidget.rect().topLeft())
|
|
||||||
animation.setEasingCurve(QEasingCurve.Type.OutCubic)
|
|
||||||
animation.start(QAbstractAnimation.DeletionPolicy.DeleteWhenStopped)
|
|
||||||
self.animations[detail_page] = animation
|
|
||||||
animation.finished.connect(cleanup_animation)
|
|
||||||
animation.finished.connect(load_image_and_restore_effect)
|
|
||||||
elif animation_type == "slide_up":
|
|
||||||
duration = self.theme.GAME_CARD_ANIMATION.get("detail_page_slide_duration", 500)
|
|
||||||
detail_page.move(0, self.main_window.height())
|
|
||||||
animation = QPropertyAnimation(detail_page, QByteArray(b"pos"))
|
|
||||||
animation.setDuration(duration)
|
|
||||||
animation.setStartValue(detail_page.pos())
|
|
||||||
animation.setEndValue(self.main_window.stackedWidget.rect().topLeft())
|
|
||||||
animation.setEasingCurve(QEasingCurve.Type.OutCubic)
|
|
||||||
animation.start(QAbstractAnimation.DeletionPolicy.DeleteWhenStopped)
|
|
||||||
self.animations[detail_page] = animation
|
|
||||||
animation.finished.connect(cleanup_animation)
|
|
||||||
animation.finished.connect(load_image_and_restore_effect)
|
|
||||||
elif animation_type == "slide_down":
|
|
||||||
duration = self.theme.GAME_CARD_ANIMATION.get("detail_page_slide_duration", 500)
|
|
||||||
detail_page.move(0, -self.main_window.height())
|
|
||||||
animation = QPropertyAnimation(detail_page, QByteArray(b"pos"))
|
|
||||||
animation.setDuration(duration)
|
|
||||||
animation.setStartValue(detail_page.pos())
|
|
||||||
animation.setEndValue(self.main_window.stackedWidget.rect().topLeft())
|
|
||||||
animation.setEasingCurve(QEasingCurve.Type.OutCubic)
|
|
||||||
animation.start(QAbstractAnimation.DeletionPolicy.DeleteWhenStopped)
|
animation.start(QAbstractAnimation.DeletionPolicy.DeleteWhenStopped)
|
||||||
self.animations[detail_page] = animation
|
self.animations[detail_page] = animation
|
||||||
animation.finished.connect(cleanup_animation)
|
animation.finished.connect(cleanup_animation)
|
||||||
animation.finished.connect(load_image_and_restore_effect)
|
animation.finished.connect(load_image_and_restore_effect)
|
||||||
elif animation_type == "bounce":
|
elif animation_type == "bounce":
|
||||||
duration = self.theme.GAME_CARD_ANIMATION.get("detail_page_zoom_duration", 400)
|
duration = self.theme.GAME_CARD_ANIMATION.get("detail_page_bounce_duration", 400)
|
||||||
|
easing_curve = QEasingCurve(QEasingCurve.Type[self.theme.GAME_CARD_ANIMATION.get("detail_page_easing_curve", "OutCubic")])
|
||||||
detail_page.setWindowOpacity(0.0)
|
detail_page.setWindowOpacity(0.0)
|
||||||
opacity_anim = QPropertyAnimation(detail_page, QByteArray(b"windowOpacity"))
|
opacity_anim = QPropertyAnimation(detail_page, QByteArray(b"windowOpacity"))
|
||||||
opacity_anim.setDuration(duration)
|
opacity_anim.setDuration(duration)
|
||||||
@@ -240,7 +237,7 @@ class DetailPageAnimations:
|
|||||||
geometry_anim.setDuration(duration)
|
geometry_anim.setDuration(duration)
|
||||||
geometry_anim.setStartValue(initial_rect)
|
geometry_anim.setStartValue(initial_rect)
|
||||||
geometry_anim.setEndValue(final_rect)
|
geometry_anim.setEndValue(final_rect)
|
||||||
geometry_anim.setEasingCurve(QEasingCurve.Type.OutBack)
|
geometry_anim.setEasingCurve(easing_curve)
|
||||||
group_anim = QParallelAnimationGroup()
|
group_anim = QParallelAnimationGroup()
|
||||||
group_anim.addAnimation(opacity_anim)
|
group_anim.addAnimation(opacity_anim)
|
||||||
group_anim.addAnimation(geometry_anim)
|
group_anim.addAnimation(geometry_anim)
|
||||||
@@ -248,3 +245,84 @@ class DetailPageAnimations:
|
|||||||
group_anim.finished.connect(cleanup_animation)
|
group_anim.finished.connect(cleanup_animation)
|
||||||
group_anim.start(QAbstractAnimation.DeletionPolicy.DeleteWhenStopped)
|
group_anim.start(QAbstractAnimation.DeletionPolicy.DeleteWhenStopped)
|
||||||
self.animations[detail_page] = group_anim
|
self.animations[detail_page] = group_anim
|
||||||
|
|
||||||
|
def animate_detail_page_exit(self, detail_page: QWidget, cleanup_callback: Callable):
|
||||||
|
"""Animate the detail page exit based on theme settings."""
|
||||||
|
try:
|
||||||
|
animation_type = self.theme.GAME_CARD_ANIMATION.get("detail_page_animation_type", "fade")
|
||||||
|
|
||||||
|
# Safely stop and remove any existing animation
|
||||||
|
if detail_page in self.animations:
|
||||||
|
try:
|
||||||
|
animation = self.animations[detail_page]
|
||||||
|
if isinstance(animation, QAbstractAnimation) and animation.state() == QAbstractAnimation.State.Running:
|
||||||
|
animation.stop()
|
||||||
|
except RuntimeError:
|
||||||
|
logger.debug("Animation already deleted for page")
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error stopping existing animation: {e}", exc_info=True)
|
||||||
|
finally:
|
||||||
|
self.animations.pop(detail_page, None)
|
||||||
|
|
||||||
|
# Define animation based on type
|
||||||
|
if animation_type == "fade":
|
||||||
|
duration = self.theme.GAME_CARD_ANIMATION.get("detail_page_fade_duration_exit", 350)
|
||||||
|
original_effect = detail_page.graphicsEffect()
|
||||||
|
opacity_effect = SafeOpacityEffect(detail_page, disable_at_full=False)
|
||||||
|
opacity_effect.setOpacity(0.999)
|
||||||
|
detail_page.setGraphicsEffect(opacity_effect)
|
||||||
|
animation = QPropertyAnimation(opacity_effect, QByteArray(b"opacity"))
|
||||||
|
animation.setDuration(duration)
|
||||||
|
animation.setStartValue(0.999)
|
||||||
|
animation.setEndValue(0.0)
|
||||||
|
animation.start(QAbstractAnimation.DeletionPolicy.DeleteWhenStopped)
|
||||||
|
self.animations[detail_page] = animation
|
||||||
|
def restore_and_cleanup():
|
||||||
|
try:
|
||||||
|
detail_page.setGraphicsEffect(original_effect) # type: ignore
|
||||||
|
except RuntimeError:
|
||||||
|
logger.debug("Original effect already deleted")
|
||||||
|
cleanup_callback()
|
||||||
|
animation.finished.connect(restore_and_cleanup)
|
||||||
|
animation.finished.connect(opacity_effect.deleteLater) # Clean up effect
|
||||||
|
elif animation_type in ["slide_left", "slide_right", "slide_up", "slide_down"]:
|
||||||
|
duration = self.theme.GAME_CARD_ANIMATION.get("detail_page_slide_duration_exit", 500)
|
||||||
|
easing_curve = QEasingCurve(QEasingCurve.Type[self.theme.GAME_CARD_ANIMATION.get("detail_page_easing_curve_exit", "InCubic")])
|
||||||
|
end_pos = {
|
||||||
|
"slide_left": QPoint(-self.main_window.width(), 0), # Exit to left (opposite of entry)
|
||||||
|
"slide_right": QPoint(self.main_window.width(), 0), # Exit to right
|
||||||
|
"slide_up": QPoint(0, self.main_window.height()), # Exit downward
|
||||||
|
"slide_down": QPoint(0, -self.main_window.height()) # Exit upward
|
||||||
|
}[animation_type]
|
||||||
|
animation = QPropertyAnimation(detail_page, QByteArray(b"pos"))
|
||||||
|
animation.setDuration(duration)
|
||||||
|
animation.setStartValue(detail_page.pos())
|
||||||
|
animation.setEndValue(end_pos)
|
||||||
|
animation.setEasingCurve(easing_curve)
|
||||||
|
animation.start(QAbstractAnimation.DeletionPolicy.DeleteWhenStopped)
|
||||||
|
self.animations[detail_page] = animation
|
||||||
|
animation.finished.connect(cleanup_callback)
|
||||||
|
elif animation_type == "bounce":
|
||||||
|
duration = self.theme.GAME_CARD_ANIMATION.get("detail_page_bounce_duration_exit", 400)
|
||||||
|
easing_curve = QEasingCurve(QEasingCurve.Type[self.theme.GAME_CARD_ANIMATION.get("detail_page_easing_curve_exit", "InCubic")])
|
||||||
|
opacity_anim = QPropertyAnimation(detail_page, QByteArray(b"windowOpacity"))
|
||||||
|
opacity_anim.setDuration(duration)
|
||||||
|
opacity_anim.setStartValue(1.0)
|
||||||
|
opacity_anim.setEndValue(0.0)
|
||||||
|
final_rect = QRect(detail_page.x() + detail_page.width() // 4, detail_page.y() + detail_page.height() // 4,
|
||||||
|
detail_page.width() // 2, detail_page.height() // 2)
|
||||||
|
geometry_anim = QPropertyAnimation(detail_page, QByteArray(b"geometry"))
|
||||||
|
geometry_anim.setDuration(duration)
|
||||||
|
geometry_anim.setStartValue(detail_page.geometry())
|
||||||
|
geometry_anim.setEndValue(final_rect)
|
||||||
|
geometry_anim.setEasingCurve(easing_curve)
|
||||||
|
group_anim = QParallelAnimationGroup()
|
||||||
|
group_anim.addAnimation(opacity_anim)
|
||||||
|
group_anim.addAnimation(geometry_anim)
|
||||||
|
group_anim.finished.connect(cleanup_callback)
|
||||||
|
group_anim.start(QAbstractAnimation.DeletionPolicy.DeleteWhenStopped)
|
||||||
|
self.animations[detail_page] = group_anim
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error in animate_detail_page_exit: {e}", exc_info=True)
|
||||||
|
self.animations.pop(detail_page, None)
|
||||||
|
cleanup_callback() # Fallback to cleanup if animation setup fails
|
||||||
|
@@ -3,8 +3,7 @@ from PySide6.QtCore import QLocale, QTranslator, QLibraryInfo
|
|||||||
from PySide6.QtWidgets import QApplication
|
from PySide6.QtWidgets import QApplication
|
||||||
from PySide6.QtGui import QIcon
|
from PySide6.QtGui import QIcon
|
||||||
from portprotonqt.main_window import MainWindow
|
from portprotonqt.main_window import MainWindow
|
||||||
from portprotonqt.tray import SystemTray
|
from portprotonqt.config_utils import save_fullscreen_config
|
||||||
from portprotonqt.config_utils import read_theme_from_config, save_fullscreen_config
|
|
||||||
from portprotonqt.logger import get_logger
|
from portprotonqt.logger import get_logger
|
||||||
from portprotonqt.cli import parse_args
|
from portprotonqt.cli import parse_args
|
||||||
|
|
||||||
@@ -38,35 +37,13 @@ def main():
|
|||||||
save_fullscreen_config(True)
|
save_fullscreen_config(True)
|
||||||
window.showFullScreen()
|
window.showFullScreen()
|
||||||
|
|
||||||
current_theme_name = read_theme_from_config()
|
|
||||||
tray = SystemTray(app, current_theme_name)
|
|
||||||
tray.show_action.triggered.connect(window.show)
|
|
||||||
tray.hide_action.triggered.connect(window.hide)
|
|
||||||
|
|
||||||
def recreate_tray():
|
|
||||||
nonlocal tray
|
|
||||||
if tray:
|
|
||||||
logger.debug("Recreating system tray")
|
|
||||||
tray.cleanup()
|
|
||||||
tray = None
|
|
||||||
current_theme = read_theme_from_config()
|
|
||||||
tray = SystemTray(app, current_theme)
|
|
||||||
# Ensure window is not None before connecting signals
|
|
||||||
if window:
|
|
||||||
tray.show_action.triggered.connect(window.show)
|
|
||||||
tray.hide_action.triggered.connect(window.hide)
|
|
||||||
|
|
||||||
def cleanup_on_exit():
|
def cleanup_on_exit():
|
||||||
nonlocal tray, window
|
nonlocal window
|
||||||
app.aboutToQuit.disconnect()
|
app.aboutToQuit.disconnect()
|
||||||
if tray:
|
|
||||||
tray.cleanup()
|
|
||||||
tray = None
|
|
||||||
if window:
|
if window:
|
||||||
window.close()
|
window.close()
|
||||||
app.quit()
|
app.quit()
|
||||||
|
|
||||||
window.settings_saved.connect(recreate_tray)
|
|
||||||
app.aboutToQuit.connect(cleanup_on_exit)
|
app.aboutToQuit.connect(cleanup_on_exit)
|
||||||
|
|
||||||
window.show()
|
window.show()
|
||||||
|
@@ -144,14 +144,21 @@ class Downloader(QObject):
|
|||||||
logger.warning(f"Предыдущая ошибка загрузки для {url}, пропускаем")
|
logger.warning(f"Предыдущая ошибка загрузки для {url}, пропускаем")
|
||||||
return None
|
return None
|
||||||
if url in self._cache:
|
if url in self._cache:
|
||||||
return self._cache[url]
|
cached_path = self._cache[url]
|
||||||
|
if os.path.exists(cached_path):
|
||||||
|
if os.path.abspath(cached_path) == os.path.abspath(local_path):
|
||||||
|
return cached_path
|
||||||
|
else:
|
||||||
|
del self._cache[url]
|
||||||
url_lock = self._get_url_lock(url)
|
url_lock = self._get_url_lock(url)
|
||||||
with url_lock:
|
with url_lock:
|
||||||
with self._global_lock:
|
with self._global_lock:
|
||||||
if url in self._last_error:
|
if url in self._last_error:
|
||||||
return None
|
return None
|
||||||
if url in self._cache:
|
if url in self._cache:
|
||||||
return self._cache[url]
|
cached_path = self._cache[url]
|
||||||
|
if os.path.exists(cached_path) and os.path.abspath(cached_path) == os.path.abspath(local_path):
|
||||||
|
return cached_path
|
||||||
result = download_with_cache(url, local_path, timeout, self)
|
result = download_with_cache(url, local_path, timeout, self)
|
||||||
with self._global_lock:
|
with self._global_lock:
|
||||||
if result:
|
if result:
|
||||||
|
@@ -16,13 +16,14 @@ from portprotonqt.time_utils import parse_playtime_file, format_playtime, get_la
|
|||||||
from portprotonqt.config_utils import get_portproton_location
|
from portprotonqt.config_utils import get_portproton_location
|
||||||
from portprotonqt.steam_api import (
|
from portprotonqt.steam_api import (
|
||||||
get_weanticheatyet_status_async, get_steam_apps_and_index_async, get_protondb_tier_async,
|
get_weanticheatyet_status_async, get_steam_apps_and_index_async, get_protondb_tier_async,
|
||||||
search_app, get_steam_home, get_last_steam_user, convert_steam_id, generate_thumbnail
|
search_app, get_steam_home, get_last_steam_user, convert_steam_id, generate_thumbnail, call_steam_api
|
||||||
)
|
)
|
||||||
import vdf
|
import vdf
|
||||||
import shutil
|
import shutil
|
||||||
import zlib
|
import zlib
|
||||||
from portprotonqt.downloader import Downloader
|
from portprotonqt.downloader import Downloader
|
||||||
from PySide6.QtGui import QPixmap
|
from PySide6.QtGui import QPixmap
|
||||||
|
import base64
|
||||||
|
|
||||||
logger = get_logger(__name__)
|
logger = get_logger(__name__)
|
||||||
downloader = Downloader()
|
downloader = Downloader()
|
||||||
@@ -66,7 +67,8 @@ def get_cache_dir() -> Path:
|
|||||||
|
|
||||||
def remove_egs_from_steam(game_name: str, portproton_dir: str, callback: Callable[[tuple[bool, str]], None]) -> None:
|
def remove_egs_from_steam(game_name: str, portproton_dir: str, callback: Callable[[tuple[bool, str]], None]) -> None:
|
||||||
"""
|
"""
|
||||||
Removes an EGS game from Steam by modifying shortcuts.vdf and deleting the launch script.
|
Removes an EGS game from Steam using CEF API or by modifying shortcuts.vdf and deleting the launch script.
|
||||||
|
Also deletes associated cover files in the Steam grid directory.
|
||||||
Calls the callback with (success, message).
|
Calls the callback with (success, message).
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -74,6 +76,7 @@ def remove_egs_from_steam(game_name: str, portproton_dir: str, callback: Callabl
|
|||||||
portproton_dir: Path to the PortProton directory.
|
portproton_dir: Path to the PortProton directory.
|
||||||
callback: Callback function to handle the result (success, message).
|
callback: Callback function to handle the result (success, message).
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if not portproton_dir:
|
if not portproton_dir:
|
||||||
logger.error("PortProton directory not found")
|
logger.error("PortProton directory not found")
|
||||||
callback((False, "PortProton directory not found"))
|
callback((False, "PortProton directory not found"))
|
||||||
@@ -101,51 +104,89 @@ def remove_egs_from_steam(game_name: str, portproton_dir: str, callback: Callabl
|
|||||||
unsigned_id = convert_steam_id(user_id)
|
unsigned_id = convert_steam_id(user_id)
|
||||||
user_dir = os.path.join(userdata_dir, str(unsigned_id))
|
user_dir = os.path.join(userdata_dir, str(unsigned_id))
|
||||||
steam_shortcuts_path = os.path.join(user_dir, "config", "shortcuts.vdf")
|
steam_shortcuts_path = os.path.join(user_dir, "config", "shortcuts.vdf")
|
||||||
backup_path = f"{steam_shortcuts_path}.backup"
|
grid_dir = os.path.join(user_dir, "config", "grid")
|
||||||
|
|
||||||
if not os.path.exists(steam_shortcuts_path):
|
if not os.path.exists(steam_shortcuts_path):
|
||||||
logger.error("Steam shortcuts file not found")
|
logger.error("Steam shortcuts file not found")
|
||||||
callback((False, "Steam shortcuts file not found"))
|
callback((False, "Steam shortcuts file not found"))
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# Find appid for the shortcut
|
||||||
|
try:
|
||||||
|
with open(steam_shortcuts_path, 'rb') as f:
|
||||||
|
shortcuts_data = vdf.binary_load(f)
|
||||||
|
shortcuts = shortcuts_data.get("shortcuts", {})
|
||||||
|
appid = None
|
||||||
|
for _key, entry in shortcuts.items():
|
||||||
|
if entry.get("AppName") == game_name and entry.get("Exe") == quoted_script_path:
|
||||||
|
appid = convert_steam_id(int(entry.get("appid")))
|
||||||
|
logger.info(f"Found matching shortcut for '{game_name}' with AppID {appid}")
|
||||||
|
break
|
||||||
|
if not appid:
|
||||||
|
logger.info(f"Game '{game_name}' not found in Steam shortcuts")
|
||||||
|
callback((False, f"Game '{game_name}' not found in Steam"))
|
||||||
|
return
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Failed to load shortcuts.vdf: {e}")
|
||||||
|
callback((False, f"Failed to load shortcuts.vdf: {e}"))
|
||||||
|
return
|
||||||
|
|
||||||
|
# Try CEF API first
|
||||||
|
logger.info(f"Attempting to remove EGS game '{game_name}' via Steam CEF API with AppID {appid}")
|
||||||
|
api_response = call_steam_api("removeShortcut", appid)
|
||||||
|
if api_response is not None: # API responded, even if empty
|
||||||
|
logger.info(f"Shortcut for AppID {appid} successfully removed via CEF API")
|
||||||
|
|
||||||
|
# Delete cover files
|
||||||
|
cover_files = [
|
||||||
|
os.path.join(grid_dir, f"{appid}.jpg"),
|
||||||
|
os.path.join(grid_dir, f"{appid}p.jpg"),
|
||||||
|
os.path.join(grid_dir, f"{appid}_hero.jpg"),
|
||||||
|
os.path.join(grid_dir, f"{appid}_logo.png")
|
||||||
|
]
|
||||||
|
for cover_file in cover_files:
|
||||||
|
if os.path.exists(cover_file):
|
||||||
|
try:
|
||||||
|
os.remove(cover_file)
|
||||||
|
logger.info(f"Deleted cover file: {cover_file}")
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Failed to delete cover file {cover_file}: {e}")
|
||||||
|
|
||||||
|
# Delete launch script
|
||||||
|
if os.path.exists(script_path):
|
||||||
|
try:
|
||||||
|
os.remove(script_path)
|
||||||
|
logger.info(f"Removed EGS script: {script_path}")
|
||||||
|
except OSError as e:
|
||||||
|
logger.warning(f"Failed to remove EGS script '{script_path}': {str(e)}")
|
||||||
|
|
||||||
|
callback((True, f"Game '{game_name}' was removed from Steam. Please restart Steam for changes to take effect."))
|
||||||
|
return
|
||||||
|
|
||||||
|
# Fallback to VDF modification
|
||||||
|
logger.warning("CEF API failed for EGS game removal; falling back to VDF modification")
|
||||||
|
backup_path = f"{steam_shortcuts_path}.backup"
|
||||||
try:
|
try:
|
||||||
shutil.copy2(steam_shortcuts_path, backup_path)
|
shutil.copy2(steam_shortcuts_path, backup_path)
|
||||||
logger.info("Created backup of shortcuts.vdf at %s", backup_path)
|
logger.info(f"Created backup of shortcuts.vdf at {backup_path}")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Failed to create backup of shortcuts.vdf: {e}")
|
logger.error(f"Failed to create backup of shortcuts.vdf: {e}")
|
||||||
callback((False, f"Failed to create backup of shortcuts.vdf: {e}"))
|
callback((False, f"Failed to create backup of shortcuts.vdf: {e}"))
|
||||||
return
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with open(steam_shortcuts_path, 'rb') as f:
|
new_shortcuts = {}
|
||||||
shortcuts_data = vdf.binary_load(f)
|
index = 0
|
||||||
except Exception as e:
|
for _key, entry in shortcuts.items():
|
||||||
logger.error(f"Failed to load shortcuts.vdf: {e}")
|
if entry.get("AppName") == game_name and entry.get("Exe") == quoted_script_path:
|
||||||
callback((False, f"Failed to load shortcuts.vdf: {e}"))
|
logger.info(f"Removing EGS game '{game_name}' from Steam shortcuts")
|
||||||
return
|
continue
|
||||||
|
new_shortcuts[str(index)] = entry
|
||||||
|
index += 1
|
||||||
|
|
||||||
shortcuts = shortcuts_data.get("shortcuts", {})
|
|
||||||
modified = False
|
|
||||||
new_shortcuts = {}
|
|
||||||
index = 0
|
|
||||||
|
|
||||||
for _key, entry in shortcuts.items():
|
|
||||||
if entry.get("AppName") == game_name and entry.get("Exe") == quoted_script_path:
|
|
||||||
modified = True
|
|
||||||
logger.info("Removing EGS game '%s' from Steam shortcuts", game_name)
|
|
||||||
continue
|
|
||||||
new_shortcuts[str(index)] = entry
|
|
||||||
index += 1
|
|
||||||
|
|
||||||
if not modified:
|
|
||||||
logger.error("Game '%s' not found in Steam shortcuts", game_name)
|
|
||||||
callback((False, f"Game '{game_name}' not found in Steam shortcuts"))
|
|
||||||
return
|
|
||||||
|
|
||||||
try:
|
|
||||||
with open(steam_shortcuts_path, 'wb') as f:
|
with open(steam_shortcuts_path, 'wb') as f:
|
||||||
vdf.binary_dump({"shortcuts": new_shortcuts}, f)
|
vdf.binary_dump({"shortcuts": new_shortcuts}, f)
|
||||||
logger.info("Updated shortcuts.vdf, removed '%s'", game_name)
|
logger.info(f"Updated shortcuts.vdf, removed '{game_name}'")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Failed to update shortcuts.vdf: {e}")
|
logger.error(f"Failed to update shortcuts.vdf: {e}")
|
||||||
if os.path.exists(backup_path):
|
if os.path.exists(backup_path):
|
||||||
@@ -157,10 +198,26 @@ def remove_egs_from_steam(game_name: str, portproton_dir: str, callback: Callabl
|
|||||||
callback((False, f"Failed to update shortcuts.vdf: {e}"))
|
callback((False, f"Failed to update shortcuts.vdf: {e}"))
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# Delete cover files
|
||||||
|
cover_files = [
|
||||||
|
os.path.join(grid_dir, f"{appid}.jpg"),
|
||||||
|
os.path.join(grid_dir, f"{appid}p.jpg"),
|
||||||
|
os.path.join(grid_dir, f"{appid}_hero.jpg"),
|
||||||
|
os.path.join(grid_dir, f"{appid}_logo.png")
|
||||||
|
]
|
||||||
|
for cover_file in cover_files:
|
||||||
|
if os.path.exists(cover_file):
|
||||||
|
try:
|
||||||
|
os.remove(cover_file)
|
||||||
|
logger.info(f"Deleted cover file: {cover_file}")
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Failed to delete cover file {cover_file}: {e}")
|
||||||
|
|
||||||
|
# Delete launch script
|
||||||
if os.path.exists(script_path):
|
if os.path.exists(script_path):
|
||||||
try:
|
try:
|
||||||
os.remove(script_path)
|
os.remove(script_path)
|
||||||
logger.info("Removed EGS script: %s", script_path)
|
logger.info(f"Removed EGS script: {script_path}")
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
logger.warning(f"Failed to remove EGS script '{script_path}': {str(e)}")
|
logger.warning(f"Failed to remove EGS script '{script_path}': {str(e)}")
|
||||||
|
|
||||||
@@ -168,11 +225,17 @@ def remove_egs_from_steam(game_name: str, portproton_dir: str, callback: Callabl
|
|||||||
|
|
||||||
def add_egs_to_steam(app_name: str, game_title: str, legendary_path: str, callback: Callable[[tuple[bool, str]], None]) -> None:
|
def add_egs_to_steam(app_name: str, game_title: str, legendary_path: str, callback: Callable[[tuple[bool, str]], None]) -> None:
|
||||||
"""
|
"""
|
||||||
Asynchronously adds an EGS game to Steam via shortcuts.vdf with PortProton tag.
|
Asynchronously adds an EGS game to Steam via CEF API or shortcuts.vdf with PortProton tag.
|
||||||
Creates a launch script using legendary CLI with --no-wine and PortProton wrapper.
|
Creates a launch script using legendary CLI with --no-wine and PortProton wrapper.
|
||||||
Wrapper is flatpak run if portproton_location is None or contains .var, otherwise start.sh.
|
Wrapper is flatpak run if portproton_location is None or contains .var, otherwise start.sh.
|
||||||
Downloads Steam Grid covers if the game exists in Steam, and generates a thumbnail.
|
Downloads Steam Grid covers if the game exists in Steam, and generates a thumbnail.
|
||||||
Calls the callback with (success, message).
|
Calls the callback with (success, message).
|
||||||
|
|
||||||
|
Args:
|
||||||
|
app_name: The Legendary app_name (unique identifier for the game).
|
||||||
|
game_title: The display name of the game.
|
||||||
|
legendary_path: Path to the Legendary CLI executable.
|
||||||
|
callback: Callback function to handle the result (success, message).
|
||||||
"""
|
"""
|
||||||
if not app_name or not app_name.strip() or not game_title or not game_title.strip():
|
if not app_name or not app_name.strip() or not game_title or not game_title.strip():
|
||||||
logger.error("Invalid app_name or game_title: empty or whitespace")
|
logger.error("Invalid app_name or game_title: empty or whitespace")
|
||||||
@@ -267,47 +330,47 @@ export LEGENDARY_CONFIG_PATH="{legendary_config_path}"
|
|||||||
grid_dir = user_dir / "config" / "grid"
|
grid_dir = user_dir / "config" / "grid"
|
||||||
os.makedirs(grid_dir, exist_ok=True)
|
os.makedirs(grid_dir, exist_ok=True)
|
||||||
|
|
||||||
# Backup shortcuts.vdf
|
# Try CEF API first
|
||||||
backup_path = f"{steam_shortcuts_path}.backup"
|
logger.info(f"Attempting to add EGS game '{game_title}' via Steam CEF API")
|
||||||
if os.path.exists(steam_shortcuts_path):
|
api_response = call_steam_api(
|
||||||
try:
|
"createShortcut",
|
||||||
shutil.copy2(steam_shortcuts_path, backup_path)
|
game_title,
|
||||||
logger.info(f"Created backup of shortcuts.vdf at {backup_path}")
|
script_path,
|
||||||
except Exception as e:
|
str(Path(script_path).parent),
|
||||||
logger.error(f"Failed to create backup of shortcuts.vdf: {e}")
|
icon_path,
|
||||||
callback((False, f"Failed to create backup of shortcuts.vdf: {e}"))
|
""
|
||||||
return
|
)
|
||||||
|
|
||||||
# Generate unique appid
|
appid = None
|
||||||
unique_string = f"{script_path}{game_title}"
|
was_api_used = False
|
||||||
baseid = zlib.crc32(unique_string.encode('utf-8')) & 0xffffffff
|
|
||||||
appid = baseid | 0x80000000
|
if api_response and isinstance(api_response, dict) and 'id' in api_response:
|
||||||
if appid > 0x7FFFFFFF:
|
appid = api_response['id']
|
||||||
aidvdf = appid - 0x100000000
|
was_api_used = True
|
||||||
|
logger.info(f"EGS game '{game_title}' successfully added via CEF API. AppID: {appid}")
|
||||||
else:
|
else:
|
||||||
aidvdf = appid
|
logger.warning("CEF API failed for EGS game addition; falling back to VDF modification")
|
||||||
|
# Backup shortcuts.vdf
|
||||||
|
backup_path = f"{steam_shortcuts_path}.backup"
|
||||||
|
if os.path.exists(steam_shortcuts_path):
|
||||||
|
try:
|
||||||
|
shutil.copy2(steam_shortcuts_path, backup_path)
|
||||||
|
logger.info(f"Created backup of shortcuts.vdf at {backup_path}")
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Failed to create backup of shortcuts.vdf: {e}")
|
||||||
|
callback((False, f"Failed to create backup of shortcuts.vdf: {e}"))
|
||||||
|
return
|
||||||
|
|
||||||
steam_appid = None
|
# Generate unique appid
|
||||||
downloaded_count = 0
|
unique_string = f"{script_path}{game_title}"
|
||||||
total_covers = 4
|
baseid = zlib.crc32(unique_string.encode('utf-8')) & 0xffffffff
|
||||||
download_lock = threading.Lock()
|
appid = baseid | 0x80000000
|
||||||
|
if appid > 0x7FFFFFFF:
|
||||||
|
aidvdf = appid - 0x100000000
|
||||||
|
else:
|
||||||
|
aidvdf = appid
|
||||||
|
|
||||||
def on_cover_download(cover_file: str, cover_type: str):
|
# Create shortcut entry
|
||||||
nonlocal downloaded_count
|
|
||||||
try:
|
|
||||||
if cover_file and os.path.exists(cover_file):
|
|
||||||
logger.info(f"Downloaded cover {cover_type} to {cover_file}")
|
|
||||||
else:
|
|
||||||
logger.warning(f"Failed to download cover {cover_type} for appid {steam_appid}")
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"Error processing cover {cover_type} for appid {steam_appid}: {e}")
|
|
||||||
with download_lock:
|
|
||||||
downloaded_count += 1
|
|
||||||
if downloaded_count == total_covers:
|
|
||||||
finalize_shortcut()
|
|
||||||
|
|
||||||
def finalize_shortcut():
|
|
||||||
tags_dict = {'0': 'PortProton'}
|
|
||||||
shortcut = {
|
shortcut = {
|
||||||
"appid": aidvdf,
|
"appid": aidvdf,
|
||||||
"AppName": game_title,
|
"AppName": game_title,
|
||||||
@@ -322,7 +385,7 @@ export LEGENDARY_CONFIG_PATH="{legendary_config_path}"
|
|||||||
"Devkit": 0,
|
"Devkit": 0,
|
||||||
"DevkitGameID": "",
|
"DevkitGameID": "",
|
||||||
"LastPlayTime": 0,
|
"LastPlayTime": 0,
|
||||||
"tags": tags_dict
|
"tags": {'0': 'PortProton'}
|
||||||
}
|
}
|
||||||
logger.info(f"Shortcut entry for EGS game: {shortcut}")
|
logger.info(f"Shortcut entry for EGS game: {shortcut}")
|
||||||
|
|
||||||
@@ -353,6 +416,7 @@ export LEGENDARY_CONFIG_PATH="{legendary_config_path}"
|
|||||||
|
|
||||||
with open(steam_shortcuts_path, 'wb') as f:
|
with open(steam_shortcuts_path, 'wb') as f:
|
||||||
vdf.binary_dump({"shortcuts": shortcuts}, f)
|
vdf.binary_dump({"shortcuts": shortcuts}, f)
|
||||||
|
logger.info(f"EGS game '{game_title}' added to Steam via VDF")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Failed to update shortcuts.vdf: {e}")
|
logger.error(f"Failed to update shortcuts.vdf: {e}")
|
||||||
if os.path.exists(backup_path):
|
if os.path.exists(backup_path):
|
||||||
@@ -364,8 +428,42 @@ export LEGENDARY_CONFIG_PATH="{legendary_config_path}"
|
|||||||
callback((False, f"Failed to update shortcuts.vdf: {e}"))
|
callback((False, f"Failed to update shortcuts.vdf: {e}"))
|
||||||
return
|
return
|
||||||
|
|
||||||
logger.info(f"EGS game '{game_title}' added to Steam")
|
if not appid:
|
||||||
callback((True, f"Game '{game_title}' added to Steam with covers"))
|
callback((False, "Failed to create shortcut via any method"))
|
||||||
|
return
|
||||||
|
|
||||||
|
steam_appid = None
|
||||||
|
downloaded_count = 0
|
||||||
|
total_covers = 4
|
||||||
|
download_lock = threading.Lock()
|
||||||
|
|
||||||
|
def on_cover_download(cover_file: str | None, cover_type: str, index: int):
|
||||||
|
nonlocal downloaded_count
|
||||||
|
try:
|
||||||
|
if cover_file is None or not os.path.exists(cover_file):
|
||||||
|
logger.warning(f"Failed to download cover {cover_type} for appid {steam_appid}")
|
||||||
|
with download_lock:
|
||||||
|
downloaded_count += 1
|
||||||
|
if downloaded_count == total_covers:
|
||||||
|
callback((True, f"Game '{game_title}' added to Steam with covers"))
|
||||||
|
return
|
||||||
|
|
||||||
|
logger.info(f"Downloaded cover {cover_type} to {cover_file}")
|
||||||
|
if was_api_used:
|
||||||
|
try:
|
||||||
|
with open(cover_file, 'rb') as f:
|
||||||
|
img_b64 = base64.b64encode(f.read()).decode('utf-8')
|
||||||
|
logger.info(f"Applying cover type '{cover_type}' via API for AppID {appid}")
|
||||||
|
ext = Path(cover_type).suffix.lstrip('.')
|
||||||
|
call_steam_api("setGrid", appid, index, ext, img_b64)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error applying cover '{cover_type}' via API: {e}")
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error processing cover {cover_type} for appid {steam_appid}: {e}")
|
||||||
|
with download_lock:
|
||||||
|
downloaded_count += 1
|
||||||
|
if downloaded_count == total_covers:
|
||||||
|
callback((True, f"Game '{game_title}' added to Steam with covers"))
|
||||||
|
|
||||||
def on_steam_apps(steam_data: tuple[list, dict]):
|
def on_steam_apps(steam_data: tuple[list, dict]):
|
||||||
nonlocal steam_appid
|
nonlocal steam_appid
|
||||||
@@ -375,24 +473,24 @@ export LEGENDARY_CONFIG_PATH="{legendary_config_path}"
|
|||||||
|
|
||||||
if not steam_appid:
|
if not steam_appid:
|
||||||
logger.info(f"No Steam appid found for EGS game {game_title}, skipping cover download")
|
logger.info(f"No Steam appid found for EGS game {game_title}, skipping cover download")
|
||||||
finalize_shortcut()
|
callback((True, f"Game '{game_title}' added to Steam"))
|
||||||
return
|
return
|
||||||
|
|
||||||
cover_types = [
|
cover_types = [
|
||||||
(".jpg", "header.jpg"),
|
(".jpg", "header.jpg", 0),
|
||||||
("p.jpg", "library_600x900_2x.jpg"),
|
("p.jpg", "library_600x900_2x.jpg", 1),
|
||||||
("_hero.jpg", "library_hero.jpg"),
|
("_hero.jpg", "library_hero.jpg", 2),
|
||||||
("_logo.png", "logo.png")
|
("_logo.png", "logo.png", 3)
|
||||||
]
|
]
|
||||||
|
|
||||||
for suffix, cover_type in cover_types:
|
for suffix, cover_type, index in cover_types:
|
||||||
cover_file = os.path.join(grid_dir, f"{appid}{suffix}")
|
cover_file = os.path.join(grid_dir, f"{appid}{suffix}")
|
||||||
cover_url = f"https://cdn.cloudflare.steamstatic.com/steam/apps/{steam_appid}/{cover_type}"
|
cover_url = f"https://cdn.cloudflare.steamstatic.com/steam/apps/{steam_appid}/{cover_type}"
|
||||||
downloader.download_async(
|
downloader.download_async(
|
||||||
cover_url,
|
cover_url,
|
||||||
cover_file,
|
cover_file,
|
||||||
timeout=5,
|
timeout=5,
|
||||||
callback=lambda result, cfile=cover_file, ctype=cover_type: on_cover_download(cfile, ctype)
|
callback=lambda result, ctype=cover_type, idx=index: on_cover_download(result, ctype, idx)
|
||||||
)
|
)
|
||||||
|
|
||||||
get_steam_apps_and_index_async(on_steam_apps)
|
get_steam_apps_and_index_async(on_steam_apps)
|
||||||
|
@@ -188,7 +188,7 @@ class GameCard(QFrame):
|
|||||||
self.egsLabel.setVisible(self.egs_visible)
|
self.egsLabel.setVisible(self.egs_visible)
|
||||||
|
|
||||||
# PortProton бейдж
|
# PortProton бейдж
|
||||||
portproton_icon = self.theme_manager.get_icon("ppqt-tray")
|
portproton_icon = self.theme_manager.get_icon("portproton")
|
||||||
self.portprotonLabel = ClickableLabel(
|
self.portprotonLabel = ClickableLabel(
|
||||||
"PortProton",
|
"PortProton",
|
||||||
icon=portproton_icon,
|
icon=portproton_icon,
|
||||||
|
@@ -48,7 +48,6 @@ logger = get_logger(__name__)
|
|||||||
|
|
||||||
class MainWindow(QMainWindow):
|
class MainWindow(QMainWindow):
|
||||||
"""Main window of PortProtonQt."""
|
"""Main window of PortProtonQt."""
|
||||||
settings_saved = Signal()
|
|
||||||
games_loaded = Signal(list)
|
games_loaded = Signal(list)
|
||||||
update_progress = Signal(int) # Signal to update progress bar
|
update_progress = Signal(int) # Signal to update progress bar
|
||||||
update_status_message = Signal(str, int) # Signal to update status message
|
update_status_message = Signal(str, int) # Signal to update status message
|
||||||
@@ -1331,7 +1330,6 @@ class MainWindow(QMainWindow):
|
|||||||
|
|
||||||
self.settingsDebounceTimer.start()
|
self.settingsDebounceTimer.start()
|
||||||
|
|
||||||
self.settings_saved.emit()
|
|
||||||
|
|
||||||
# Управление полноэкранным режимом
|
# Управление полноэкранным режимом
|
||||||
gamepad_connected = self.input_manager.find_gamepad() is not None
|
gamepad_connected = self.input_manager.find_gamepad() is not None
|
||||||
@@ -1676,7 +1674,7 @@ class MainWindow(QMainWindow):
|
|||||||
egsLabel.setVisible(egs_visible)
|
egsLabel.setVisible(egs_visible)
|
||||||
|
|
||||||
# PortProton badge
|
# PortProton badge
|
||||||
portproton_icon = self.theme_manager.get_icon("ppqt-tray")
|
portproton_icon = self.theme_manager.get_icon("portproton")
|
||||||
portprotonLabel = ClickableLabel(
|
portprotonLabel = ClickableLabel(
|
||||||
"PortProton",
|
"PortProton",
|
||||||
icon=portproton_icon,
|
icon=portproton_icon,
|
||||||
@@ -1967,24 +1965,42 @@ class MainWindow(QMainWindow):
|
|||||||
parent = parent.parent()
|
parent = parent.parent()
|
||||||
|
|
||||||
def goBackDetailPage(self, page: QWidget | None) -> None:
|
def goBackDetailPage(self, page: QWidget | None) -> None:
|
||||||
if page is None or page != self.stackedWidget.currentWidget():
|
if page is None or page != self.stackedWidget.currentWidget() or getattr(self, '_exit_animation_in_progress', False):
|
||||||
return
|
return
|
||||||
|
self._exit_animation_in_progress = True
|
||||||
self._detail_page_active = False
|
self._detail_page_active = False
|
||||||
self._current_detail_page = None
|
self._current_detail_page = None
|
||||||
if hasattr(self, '_animations') and page in self._animations:
|
|
||||||
|
def cleanup():
|
||||||
|
"""Helper function to clean up after animation."""
|
||||||
try:
|
try:
|
||||||
animation = self._animations[page]
|
if page in self._animations:
|
||||||
if animation.state() == QAbstractAnimation.State.Running:
|
animation = self._animations[page]
|
||||||
animation.stop()
|
try:
|
||||||
del self._animations[page]
|
if animation.state() == QAbstractAnimation.State.Running:
|
||||||
except RuntimeError:
|
animation.stop()
|
||||||
del self._animations[page]
|
except RuntimeError:
|
||||||
self.stackedWidget.setCurrentIndex(0)
|
pass # Animation already deleted
|
||||||
self.stackedWidget.removeWidget(page)
|
finally:
|
||||||
page.deleteLater()
|
del self._animations[page]
|
||||||
self.currentDetailPage = None
|
self.stackedWidget.setCurrentIndex(0)
|
||||||
self.current_exec_line = None
|
self.stackedWidget.removeWidget(page)
|
||||||
self.current_play_button = None
|
page.deleteLater()
|
||||||
|
self.currentDetailPage = None
|
||||||
|
self.current_exec_line = None
|
||||||
|
self.current_play_button = None
|
||||||
|
self._exit_animation_in_progress = False
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error in cleanup: {e}", exc_info=True)
|
||||||
|
self._exit_animation_in_progress = False
|
||||||
|
|
||||||
|
# Start exit animation
|
||||||
|
try:
|
||||||
|
self.detail_animations.animate_detail_page_exit(page, cleanup)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error starting exit animation: {e}", exc_info=True)
|
||||||
|
self._exit_animation_in_progress = False
|
||||||
|
cleanup() # Fallback to cleanup if animation fails
|
||||||
|
|
||||||
def is_target_exe_running(self):
|
def is_target_exe_running(self):
|
||||||
"""Проверяет, запущен ли процесс с именем self.target_exe через psutil."""
|
"""Проверяет, запущен ли процесс с именем self.target_exe через psutil."""
|
||||||
|
@@ -18,6 +18,10 @@ from collections.abc import Callable
|
|||||||
import re
|
import re
|
||||||
import shutil
|
import shutil
|
||||||
import zlib
|
import zlib
|
||||||
|
import websocket
|
||||||
|
import requests
|
||||||
|
import random
|
||||||
|
import base64
|
||||||
|
|
||||||
downloader = Downloader()
|
downloader = Downloader()
|
||||||
logger = get_logger(__name__)
|
logger = get_logger(__name__)
|
||||||
@@ -771,6 +775,126 @@ def get_steam_apps_and_index_async(callback: Callable[[tuple[list, dict]], None]
|
|||||||
|
|
||||||
load_steam_apps_async(on_steam_apps)
|
load_steam_apps_async(on_steam_apps)
|
||||||
|
|
||||||
|
def enable_steam_cef() -> tuple[bool, str]:
|
||||||
|
"""
|
||||||
|
Проверяет и при необходимости активирует режим удаленной отладки Steam CEF.
|
||||||
|
|
||||||
|
Создает файл .cef-enable-remote-debugging в директории Steam.
|
||||||
|
Steam необходимо перезапустить после первого создания этого файла.
|
||||||
|
|
||||||
|
Возвращает кортеж:
|
||||||
|
- (True, "already_enabled") если уже было активно.
|
||||||
|
- (True, "restart_needed") если было только что активировано и нужен перезапуск Steam.
|
||||||
|
- (False, "steam_not_found") если директория Steam не найдена.
|
||||||
|
"""
|
||||||
|
steam_home = get_steam_home()
|
||||||
|
if not steam_home:
|
||||||
|
return (False, "steam_not_found")
|
||||||
|
|
||||||
|
cef_flag_file = steam_home / ".cef-enable-remote-debugging"
|
||||||
|
logger.info(f"Проверка CEF флага: {cef_flag_file}")
|
||||||
|
|
||||||
|
if cef_flag_file.exists():
|
||||||
|
logger.info("CEF Remote Debugging уже активирован.")
|
||||||
|
return (True, "already_enabled")
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
os.makedirs(cef_flag_file.parent, exist_ok=True)
|
||||||
|
cef_flag_file.touch()
|
||||||
|
logger.info("CEF Remote Debugging активирован. Steam необходимо перезапустить.")
|
||||||
|
return (True, "restart_needed")
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Не удалось создать CEF флаг {cef_flag_file}: {e}")
|
||||||
|
return (False, str(e))
|
||||||
|
|
||||||
|
def call_steam_api(js_cmd: str, *args) -> dict | None:
|
||||||
|
"""
|
||||||
|
Выполняет JavaScript функцию в контексте Steam через CEF Remote Debugging.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
js_cmd: Имя JS функции для вызова (напр. 'createShortcut').
|
||||||
|
*args: Аргументы для передачи в JS функцию.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Словарь с результатом выполнения или None в случае ошибки.
|
||||||
|
"""
|
||||||
|
status, message = enable_steam_cef()
|
||||||
|
if not (status is True and message == "already_enabled"):
|
||||||
|
if message == "restart_needed":
|
||||||
|
logger.warning("Steam CEF API доступен, но требует перезапуска Steam для полной активации.")
|
||||||
|
elif message == "steam_not_found":
|
||||||
|
logger.error("Не удалось найти директорию Steam для проверки CEF API.")
|
||||||
|
else:
|
||||||
|
logger.error(f"Steam CEF API недоступен или не готов: {message}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
steam_debug_url = "http://localhost:8080/json"
|
||||||
|
|
||||||
|
try:
|
||||||
|
response = requests.get(steam_debug_url, timeout=2)
|
||||||
|
response.raise_for_status()
|
||||||
|
contexts = response.json()
|
||||||
|
ws_url = next((ctx['webSocketDebuggerUrl'] for ctx in contexts if ctx['title'] == 'SharedJSContext'), None)
|
||||||
|
if not ws_url:
|
||||||
|
logger.warning("Не удалось найти SharedJSContext. Steam запущен с флагом -cef-enable-remote-debugging?")
|
||||||
|
return None
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(f"Не удалось подключиться к Steam CEF API по адресу {steam_debug_url}. Steam запущен? {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
js_code = """
|
||||||
|
async function createShortcut(name, exe, dir, icon, args) {
|
||||||
|
const id = await SteamClient.Apps.AddShortcut(name, exe, dir, args);
|
||||||
|
console.log("Shortcut created with ID:", id);
|
||||||
|
await SteamClient.Apps.SetShortcutName(id, name);
|
||||||
|
if (icon)
|
||||||
|
await SteamClient.Apps.SetShortcutIcon(id, icon);
|
||||||
|
if (args)
|
||||||
|
await SteamClient.Apps.SetAppLaunchOptions(id, args);
|
||||||
|
return { id };
|
||||||
|
};
|
||||||
|
|
||||||
|
async function setGrid(id, i, ext, image) {
|
||||||
|
await SteamClient.Apps.SetCustomArtworkForApp(id, image, ext, i);
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
async function removeShortcut(id) {
|
||||||
|
await SteamClient.Apps.RemoveShortcut(+id);
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
ws = websocket.create_connection(ws_url, timeout=5)
|
||||||
|
js_args = ", ".join(orjson.dumps(arg).decode('utf-8') for arg in args)
|
||||||
|
expression = f"{js_code} {js_cmd}({js_args});"
|
||||||
|
payload = {
|
||||||
|
"id": random.randint(0, 32767),
|
||||||
|
"method": "Runtime.evaluate",
|
||||||
|
"params": {
|
||||||
|
"expression": expression,
|
||||||
|
"awaitPromise": True,
|
||||||
|
"returnByValue": True
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ws.send(orjson.dumps(payload))
|
||||||
|
response_str = ws.recv()
|
||||||
|
ws.close()
|
||||||
|
|
||||||
|
response_data = orjson.loads(response_str)
|
||||||
|
if "error" in response_data:
|
||||||
|
logger.error(f"Ошибка выполнения JS в Steam: {response_data['error']['message']}")
|
||||||
|
return None
|
||||||
|
result = response_data.get('result', {}).get('result', {})
|
||||||
|
if result.get('type') == 'object' and result.get('subtype') == 'error':
|
||||||
|
logger.error(f"Ошибка выполнения JS в Steam: {result.get('description')}")
|
||||||
|
return None
|
||||||
|
return result.get('value')
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Ошибка при взаимодействии с WebSocket Steam: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
def add_to_steam(game_name: str, exec_line: str, cover_path: str) -> tuple[bool, str]:
|
def add_to_steam(game_name: str, exec_line: str, cover_path: str) -> tuple[bool, str]:
|
||||||
"""
|
"""
|
||||||
Add a non-Steam game to Steam via shortcuts.vdf with PortProton tag,
|
Add a non-Steam game to Steam via shortcuts.vdf with PortProton tag,
|
||||||
@@ -872,45 +996,42 @@ export START_FROM_STEAM=1
|
|||||||
grid_dir = user_dir / "config" / "grid"
|
grid_dir = user_dir / "config" / "grid"
|
||||||
os.makedirs(grid_dir, exist_ok=True)
|
os.makedirs(grid_dir, exist_ok=True)
|
||||||
|
|
||||||
backup_path = f"{steam_shortcuts_path}.backup"
|
appid = None
|
||||||
if os.path.exists(steam_shortcuts_path):
|
was_api_used = False
|
||||||
try:
|
|
||||||
shutil.copy2(steam_shortcuts_path, backup_path)
|
|
||||||
logger.info(f"Created backup of shortcuts.vdf at {backup_path}")
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"Failed to create backup of shortcuts.vdf: {e}")
|
|
||||||
return (False, f"Failed to create backup of shortcuts.vdf: {e}")
|
|
||||||
|
|
||||||
unique_string = f"{script_path}{game_name}"
|
logger.info("Попытка добавления ярлыка через Steam CEF API...")
|
||||||
baseid = zlib.crc32(unique_string.encode('utf-8')) & 0xffffffff
|
api_response = call_steam_api(
|
||||||
appid = baseid | 0x80000000
|
"createShortcut",
|
||||||
if appid > 0x7FFFFFFF:
|
game_name,
|
||||||
aidvdf = appid - 0x100000000
|
script_path,
|
||||||
|
str(Path(script_path).parent),
|
||||||
|
icon_path,
|
||||||
|
""
|
||||||
|
)
|
||||||
|
|
||||||
|
if api_response and isinstance(api_response, dict) and 'id' in api_response:
|
||||||
|
appid = api_response['id']
|
||||||
|
was_api_used = True
|
||||||
|
logger.info(f"Ярлык успешно добавлен через API. AppID: {appid}")
|
||||||
else:
|
else:
|
||||||
aidvdf = appid
|
logger.warning("Не удалось добавить ярлык через API. Используется запасной метод (запись в shortcuts.vdf).")
|
||||||
|
backup_path = f"{steam_shortcuts_path}.backup"
|
||||||
|
if os.path.exists(steam_shortcuts_path):
|
||||||
|
try:
|
||||||
|
shutil.copy2(steam_shortcuts_path, backup_path)
|
||||||
|
logger.info(f"Created backup of shortcuts.vdf at {backup_path}")
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Failed to create backup of shortcuts.vdf: {e}")
|
||||||
|
return (False, f"Failed to create backup of shortcuts.vdf: {e}")
|
||||||
|
|
||||||
steam_appid = None
|
unique_string = f"{script_path}{game_name}"
|
||||||
downloaded_count = 0
|
baseid = zlib.crc32(unique_string.encode('utf-8')) & 0xffffffff
|
||||||
total_covers = 4 # количество обложек
|
appid = baseid | 0x80000000
|
||||||
|
if appid > 0x7FFFFFFF:
|
||||||
|
aidvdf = appid - 0x100000000
|
||||||
|
else:
|
||||||
|
aidvdf = appid
|
||||||
|
|
||||||
download_lock = threading.Lock()
|
|
||||||
|
|
||||||
def on_cover_download(cover_file: str, cover_type: str):
|
|
||||||
nonlocal downloaded_count
|
|
||||||
try:
|
|
||||||
if cover_file and os.path.exists(cover_file):
|
|
||||||
logger.info(f"Downloaded cover {cover_type} to {cover_file}")
|
|
||||||
else:
|
|
||||||
logger.warning(f"Failed to download cover {cover_type} for appid {steam_appid}")
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"Error processing cover {cover_type} for appid {steam_appid}: {e}")
|
|
||||||
with download_lock:
|
|
||||||
downloaded_count += 1
|
|
||||||
if downloaded_count == total_covers:
|
|
||||||
finalize_shortcut()
|
|
||||||
|
|
||||||
def finalize_shortcut():
|
|
||||||
tags_dict = {'0': 'PortProton'}
|
|
||||||
shortcut = {
|
shortcut = {
|
||||||
"appid": aidvdf,
|
"appid": aidvdf,
|
||||||
"AppName": game_name,
|
"AppName": game_name,
|
||||||
@@ -925,7 +1046,7 @@ export START_FROM_STEAM=1
|
|||||||
"Devkit": 0,
|
"Devkit": 0,
|
||||||
"DevkitGameID": "",
|
"DevkitGameID": "",
|
||||||
"LastPlayTime": 0,
|
"LastPlayTime": 0,
|
||||||
"tags": tags_dict
|
"tags": {'0': 'PortProton'}
|
||||||
}
|
}
|
||||||
logger.info(f"Shortcut entry to be written: {shortcut}")
|
logger.info(f"Shortcut entry to be written: {shortcut}")
|
||||||
|
|
||||||
@@ -955,6 +1076,7 @@ export START_FROM_STEAM=1
|
|||||||
|
|
||||||
with open(steam_shortcuts_path, 'wb') as f:
|
with open(steam_shortcuts_path, 'wb') as f:
|
||||||
vdf.binary_dump({"shortcuts": shortcuts}, f)
|
vdf.binary_dump({"shortcuts": shortcuts}, f)
|
||||||
|
logger.info(f"Game '{game_name}' successfully added to Steam with covers")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Failed to update shortcuts.vdf: {e}")
|
logger.error(f"Failed to update shortcuts.vdf: {e}")
|
||||||
if os.path.exists(backup_path):
|
if os.path.exists(backup_path):
|
||||||
@@ -963,34 +1085,54 @@ export START_FROM_STEAM=1
|
|||||||
logger.info("Restored shortcuts.vdf from backup due to update failure")
|
logger.info("Restored shortcuts.vdf from backup due to update failure")
|
||||||
except Exception as restore_err:
|
except Exception as restore_err:
|
||||||
logger.error(f"Failed to restore shortcuts.vdf from backup: {restore_err}")
|
logger.error(f"Failed to restore shortcuts.vdf from backup: {restore_err}")
|
||||||
return (False, f"Failed to update shortcuts.vdf: {e}")
|
appid = None
|
||||||
|
|
||||||
logger.info(f"Game '{game_name}' successfully added to Steam with covers")
|
if not appid:
|
||||||
return (True, f"Game '{game_name}' added to Steam with covers")
|
return (False, "Не удалось создать ярлык ни одним из способов.")
|
||||||
|
|
||||||
|
steam_appid = None
|
||||||
|
|
||||||
def on_game_info(game_info: dict):
|
def on_game_info(game_info: dict):
|
||||||
nonlocal steam_appid
|
nonlocal steam_appid
|
||||||
steam_appid = game_info.get("appid")
|
steam_appid = game_info.get("appid")
|
||||||
if not steam_appid or not isinstance(steam_appid, int):
|
if not steam_appid or not isinstance(steam_appid, int):
|
||||||
logger.info("No valid Steam appid found, skipping cover download")
|
logger.info("No valid Steam appid found, skipping cover download")
|
||||||
return finalize_shortcut()
|
return
|
||||||
|
logger.info(f"Найден Steam AppID {steam_appid} для загрузки обложек.")
|
||||||
|
|
||||||
# Обложки и имена, соответствующие bash-скрипту и твоим размерам
|
|
||||||
cover_types = [
|
cover_types = [
|
||||||
(".jpg", "header.jpg"), # базовый, сохранится как AppId.jpg
|
("p.jpg", "library_600x900_2x.jpg"),
|
||||||
("p.jpg", "library_600x900_2x.jpg"), # сохранится как AppIdp.jpg
|
("_hero.jpg", "library_hero.jpg"),
|
||||||
("_hero.jpg", "library_hero.jpg"), # AppId_hero.jpg
|
("_logo.png", "logo.png"),
|
||||||
("_logo.png", "logo.png") # AppId_logo.png
|
(".jpg", "header.jpg")
|
||||||
]
|
]
|
||||||
|
|
||||||
for suffix, cover_type in cover_types:
|
def on_cover_download(result_path: str | None, steam_name: str, index: int):
|
||||||
|
try:
|
||||||
|
if result_path and os.path.exists(result_path):
|
||||||
|
logger.info(f"Downloaded cover {steam_name} to {result_path}")
|
||||||
|
if was_api_used:
|
||||||
|
try:
|
||||||
|
with open(result_path, 'rb') as f:
|
||||||
|
img_b64 = base64.b64encode(f.read()).decode('utf-8')
|
||||||
|
logger.info(f"Применение обложки типа '{steam_name}' через API для AppID {appid}")
|
||||||
|
ext = Path(steam_name).suffix.lstrip('.')
|
||||||
|
call_steam_api("setGrid", appid, index, ext, img_b64)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Ошибка при применении обложки '{steam_name}' через API: {e}")
|
||||||
|
else:
|
||||||
|
logger.warning(f"Failed to download cover {steam_name} for appid {steam_appid}")
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error processing cover {steam_name} for appid {steam_appid}: {e}")
|
||||||
|
|
||||||
|
for i, (suffix, steam_name) in enumerate(cover_types):
|
||||||
cover_file = os.path.join(grid_dir, f"{appid}{suffix}")
|
cover_file = os.path.join(grid_dir, f"{appid}{suffix}")
|
||||||
cover_url = f"https://cdn.cloudflare.steamstatic.com/steam/apps/{steam_appid}/{cover_type}"
|
cover_url = f"https://cdn.cloudflare.steamstatic.com/steam/apps/{steam_appid}/{steam_name}"
|
||||||
downloader.download_async(
|
downloader.download_async(
|
||||||
cover_url,
|
cover_url,
|
||||||
cover_file,
|
cover_file,
|
||||||
timeout=5,
|
timeout=5,
|
||||||
callback=lambda result, cfile=cover_file, ctype=cover_type: on_cover_download(cfile, ctype)
|
callback=lambda result, index=i, name=steam_name: on_cover_download(result, name, index)
|
||||||
)
|
)
|
||||||
|
|
||||||
get_steam_game_info_async(game_name, exec_line, on_game_info)
|
get_steam_game_info_async(game_name, exec_line, on_game_info)
|
||||||
@@ -1043,19 +1185,7 @@ def remove_from_steam(game_name: str, exec_line: str) -> tuple[bool, str]:
|
|||||||
logger.info(f"shortcuts.vdf not found at {steam_shortcuts_path}")
|
logger.info(f"shortcuts.vdf not found at {steam_shortcuts_path}")
|
||||||
return (False, f"Game '{game_name}' not found in Steam")
|
return (False, f"Game '{game_name}' not found in Steam")
|
||||||
|
|
||||||
# Generate appid for identifying cover files
|
appid = None
|
||||||
unique_string = f"{script_path}{game_name}"
|
|
||||||
baseid = zlib.crc32(unique_string.encode('utf-8')) & 0xffffffff
|
|
||||||
appid = baseid | 0x80000000
|
|
||||||
|
|
||||||
# Create backup of shortcuts.vdf
|
|
||||||
backup_path = f"{steam_shortcuts_path}.backup"
|
|
||||||
try:
|
|
||||||
shutil.copy2(steam_shortcuts_path, backup_path)
|
|
||||||
logger.info(f"Created backup of shortcuts.vdf at {backup_path}")
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"Failed to create backup of shortcuts.vdf: {e}")
|
|
||||||
return (False, f"Failed to create backup of shortcuts.vdf: {e}")
|
|
||||||
|
|
||||||
# Load and modify shortcuts.vdf
|
# Load and modify shortcuts.vdf
|
||||||
try:
|
try:
|
||||||
@@ -1069,37 +1199,51 @@ def remove_from_steam(game_name: str, exec_line: str) -> tuple[bool, str]:
|
|||||||
return (False, f"Failed to load shortcuts.vdf: {load_err}")
|
return (False, f"Failed to load shortcuts.vdf: {load_err}")
|
||||||
|
|
||||||
shortcuts = shortcuts_data.get("shortcuts", {})
|
shortcuts = shortcuts_data.get("shortcuts", {})
|
||||||
found = False
|
|
||||||
new_shortcuts = {}
|
new_shortcuts = {}
|
||||||
index = 0
|
index = 0
|
||||||
|
|
||||||
# Filter out the matching shortcut
|
# Filter out the matching shortcut
|
||||||
for _key, entry in shortcuts.items():
|
for _key, entry in shortcuts.items():
|
||||||
if entry.get("AppName") == game_name and entry.get("Exe") == f'"{script_path}"':
|
if entry.get("AppName") == game_name and entry.get("Exe") == f'"{script_path}"':
|
||||||
found = True
|
appid = convert_steam_id(int(entry.get("appid")))
|
||||||
logger.info(f"Found matching shortcut for '{game_name}' to remove")
|
logger.info(f"Found matching shortcut for '{game_name}' to remove")
|
||||||
continue
|
continue
|
||||||
new_shortcuts[str(index)] = entry
|
new_shortcuts[str(index)] = entry
|
||||||
index += 1
|
index += 1
|
||||||
|
|
||||||
if not found:
|
if not appid:
|
||||||
logger.info(f"Game '{game_name}' not found in Steam shortcuts")
|
logger.info(f"Game '{game_name}' not found in Steam shortcuts")
|
||||||
return (False, f"Game '{game_name}' not found in Steam")
|
return (False, f"Game '{game_name}' not found in Steam")
|
||||||
|
|
||||||
# Save updated shortcuts.vdf
|
api_response = call_steam_api("removeShortcut", appid)
|
||||||
try:
|
if api_response is not None: # API ответил, даже если ответ пустой
|
||||||
with open(steam_shortcuts_path, 'wb') as f:
|
logger.info(f"Ярлык для AppID {appid} успешно удален через API.")
|
||||||
vdf.binary_dump({"shortcuts": new_shortcuts}, f)
|
else:
|
||||||
logger.info(f"Successfully updated shortcuts.vdf, removed '{game_name}'")
|
logger.warning("Не удалось удалить ярлык через API. Используется запасной метод (редактирование shortcuts.vdf).")
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"Failed to update shortcuts.vdf: {e}")
|
# Create backup of shortcuts.vdf
|
||||||
if os.path.exists(backup_path):
|
backup_path = f"{steam_shortcuts_path}.backup"
|
||||||
try:
|
try:
|
||||||
shutil.copy2(backup_path, steam_shortcuts_path)
|
shutil.copy2(steam_shortcuts_path, backup_path)
|
||||||
logger.info("Restored shortcuts.vdf from backup due to update failure")
|
logger.info(f"Created backup of shortcuts.vdf at {backup_path}")
|
||||||
except Exception as restore_err:
|
except Exception as e:
|
||||||
logger.error(f"Failed to restore shortcuts.vdf from backup: {restore_err}")
|
logger.error(f"Failed to create backup of shortcuts.vdf: {e}")
|
||||||
return (False, f"Failed to update shortcuts.vdf: {e}")
|
return (False, f"Failed to create backup of shortcuts.vdf: {e}")
|
||||||
|
|
||||||
|
# Save updated shortcuts.vdf
|
||||||
|
try:
|
||||||
|
with open(steam_shortcuts_path, 'wb') as f:
|
||||||
|
vdf.binary_dump({"shortcuts": new_shortcuts}, f)
|
||||||
|
logger.info(f"Successfully updated shortcuts.vdf, removed '{game_name}'")
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Failed to update shortcuts.vdf: {e}")
|
||||||
|
if os.path.exists(backup_path):
|
||||||
|
try:
|
||||||
|
shutil.copy2(backup_path, steam_shortcuts_path)
|
||||||
|
logger.info("Restored shortcuts.vdf from backup due to update failure")
|
||||||
|
except Exception as restore_err:
|
||||||
|
logger.error(f"Failed to restore shortcuts.vdf from backup: {restore_err}")
|
||||||
|
return (False, f"Failed to update shortcuts.vdf: {e}")
|
||||||
|
|
||||||
# Delete cover files
|
# Delete cover files
|
||||||
cover_files = [
|
cover_files = [
|
||||||
|
@@ -1 +0,0 @@
|
|||||||
<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><path d="m3.3334 1c-1.2926 0-2.3333 1.0408-2.3333 2.3333v9.3333c0 1.2926 1.0408 2.3333 2.3333 2.3333h9.3333c1.2926 0 2.3333-1.0408 2.3333-2.3333v-9.3333c0-1.2926-1.0408-2.3333-2.3333-2.3333zm4.6667 2.4979c0.41261 0 0.75035 0.33774 0.75035 0.75035v3.0014h3.0014c0.41261 0 0.75035 0.33774 0.75035 0.75035s-0.33774 0.75035-0.75035 0.75035h-3.0014v3.0014c0 0.41261-0.33774 0.75035-0.75035 0.75035s-0.75035-0.33774-0.75035-0.75035v-3.0014h-3.0014c-0.41261 0-0.75035-0.33774-0.75035-0.75035s0.33774-0.75035 0.75035-0.75035h3.0014v-3.0014c0-0.41261 0.33774-0.75035 0.75035-0.75035z" fill="#fff" fill-rule="evenodd"/></svg>
|
|
Before Width: | Height: | Size: 734 B |
@@ -1 +0,0 @@
|
|||||||
<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><path d="m12.13 2.2617-5.7389 5.7389 5.7389 5.7389-1.2604 1.2605-7-7 7-7z" fill="#fff"/></svg>
|
|
Before Width: | Height: | Size: 213 B |
@@ -1 +0,0 @@
|
|||||||
<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><path d="m5.48 11.5 2.52-2.52 2.52 2.52 0.98-0.98-2.52-2.52 2.52-2.52-0.98-0.98-2.52 2.52-2.52-2.52-0.98 0.98 2.52 2.52-2.52 2.52zm2.52 3.5q-1.4525 0-2.73-0.55125t-2.2225-1.4962-1.4962-2.2225-0.55125-2.73 0.55125-2.73 1.4962-2.2225 2.2225-1.4962 2.73-0.55125 2.73 0.55125 2.2225 1.4962 1.4962 2.2225 0.55125 2.73-0.55125 2.73-1.4962 2.2225-2.2225 1.4962-2.73 0.55125zm0-1.4q2.345 0 3.9725-1.6275t1.6275-3.9725-1.6275-3.9725-3.9725-1.6275-3.9725 1.6275-1.6275 3.9725 1.6275 3.9725 3.9725 1.6275z"/></svg>
|
|
Before Width: | Height: | Size: 622 B |
@@ -1 +0,0 @@
|
|||||||
<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><path d="m8 11.5-7-7h14z" fill="#fff"/></svg>
|
|
Before Width: | Height: | Size: 164 B |
@@ -1 +0,0 @@
|
|||||||
<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><path d="m7.02 11.22 4.935-4.935-0.98-0.98-3.955 3.955-1.995-1.995-0.98 0.98zm0.98 3.78q-1.4525 0-2.73-0.55125t-2.2225-1.4962-1.4962-2.2225-0.55125-2.73 0.55125-2.73 1.4962-2.2225 2.2225-1.4962 2.73-0.55125 2.73 0.55125 2.2225 1.4962 1.4962 2.2225 0.55125 2.73-0.55125 2.73-1.4962 2.2225-2.2225 1.4962-2.73 0.55125zm0-1.4q2.345 0 3.9725-1.6275t1.6275-3.9725-1.6275-3.9725-3.9725-1.6275-3.9725 1.6275-1.6275 3.9725 1.6275 3.9725 3.9725 1.6275z"/></svg>
|
|
Before Width: | Height: | Size: 570 B |
@@ -1 +0,0 @@
|
|||||||
<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><path d="m0.52495 13.312c0.03087 1.3036 1.3683 2.0929 2.541 1.4723l9.4303-5.3381c0.51362-0.29103 0.86214-0.82453 0.86214-1.4496 0-0.62514-0.34835-1.1586-0.86214-1.4497l-9.4303-5.3304c-1.1727-0.62059-2.5111 0.16139-2.541 1.4647z" fill="#fff"/></svg>
|
|
Before Width: | Height: | Size: 367 B |
@@ -1 +0,0 @@
|
|||||||
<svg width="64" height="64" version="1.1" viewBox="0 0 64 64" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><path d="m31.994 2c-3.5777 0.00874-6.7581 2.209-8.0469 5.5059-6.026 1.9949-11.103 6.1748-14.25 11.576 0.3198-0.03567 0.64498-0.05624 0.9668-0.05664 1.8247 4.03e-4 3.6022 0.57036 5.0801 1.6406 2.053-2.9466 4.892-5.3048 8.2148-6.7754 1.3182 3.2847 4.496 5.4368 8.0352 5.4375 4.7859 5.76e-4 8.6634-3.8782 8.6641-8.6641 0-4.787-3.8774-8.6647-8.6641-8.6641zm14.148 8.4629c0.001493 0.068825 1.08e-4 0.13229 0 0.20117 0 2.0592-0.7314 4.0514-2.0664 5.6191 2.6029 1.9979 4.687 4.6357 6.0332 7.6758-0.03487 0.01246-0.051814 0.019533-0.089844 0.033204-3.239 1.3412-5.3501 4.5078-5.3496 8.0137-5.6e-5 3.5056 2.111 6.6588 5.3496 8 1.0511 0.43551 2.1787 0.66386 3.3164 0.66406 0.37838-3.45e-4 0.74796-0.028635 1.123-0.078125 4.3115-0.56733 7.5408-4.2367 7.541-8.5859-2.29e-4 -0.38522-0.026915-0.77645-0.078125-1.1582-0.41836-3.1252-2.5021-5.7755-5.4395-6.9219-1.8429-5.5649-5.5319-10.293-10.34-13.463zm-35.479 12.867v0.011719c-4.7868-5.8e-4 -8.6645 3.8772-8.6641 8.6641 5.184e-4 3.5694 2.1832 6.7701 5.5078 8.0684 1.9494 5.8885 5.9701 10.844 11.191 14.004-0.02187-0.24765-0.032753-0.49357-0.033203-0.74219 0.0011-1.8915 0.6215-3.7301 1.7656-5.2363-2.8389-2.0415-5.1101-4.8211-6.541-8.0586-0.010718 0.00405-0.023854 0.005164-0.035156 0.007812 3.2771-1.2961 5.4686-4.4709 5.4746-8.043 7e-6 -4.787-3.8793-8.6762-8.666-8.6758zm18.264 2.9746c-1.1128 0.59718-2.0251 1.5031-2.627 2.6133 0.49567 0.91964 0.77734 1.9689 0.77734 3.082 0 1.1135-0.28142 2.168-0.77734 3.0879 0.60218 1.1114 1.5189 2.0216 2.6328 2.6191 0.9175-0.49216 1.9588-0.77148 3.0684-0.77148 1.1032 0 2.1508 0.27284 3.0645 0.75976 1.1182-0.60366 2.032-1.5238 2.6309-2.6445-0.48449-0.91196-0.76367-1.9505-0.76367-3.0508 0-1.1 0.27944-2.1331 0.76367-3.0449-0.59834-1.1194-1.5143-2.0409-2.6309-2.6445-0.91432 0.48781-1.9603 0.76367-3.0645 0.76367-1.1106 3e-6 -2.1561-0.27646-3.0742-0.76953zm19.328 17.041c-2.0547 2.9472-4.8918 5.3038-8.2148 6.7754-1.3171-3.2891-4.504-5.4498-8.0469-5.4492-4.7846 0.0017-8.6634 3.8796-8.6641 8.6641 0 4.7856 3.8788 8.6627 8.6641 8.6641 3.5711 7.48e-4 6.782-2.179 8.0801-5.5059 6.026-1.9954 11.081-6.1633 14.227-11.564-0.3202 0.03625-0.64263 0.05628-0.96484 0.05664-1.822-2.87e-4 -3.6033-0.57345-5.0801-1.6406z"/></svg>
|
|
Before Width: | Height: | Size: 2.3 KiB |
@@ -1 +0,0 @@
|
|||||||
<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><path d="m8 11.5-4.375-4.375 1.225-1.2688 2.275 2.275v-7.1312h1.75v7.1312l2.275-2.275 1.225 1.2688zm-5.25 3.5q-0.72188 0-1.2359-0.51406-0.51406-0.51406-0.51406-1.2359v-2.625h1.75v2.625h10.5v-2.625h1.75v2.625q0 0.72188-0.51406 1.2359-0.51406 0.51406-1.2359 0.51406z"/></svg>
|
|
Before Width: | Height: | Size: 392 B |
@@ -1 +0,0 @@
|
|||||||
<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><path d="m14.396 13.564-2.5415-2.5415c0.94769-1.0626 1.5364-2.4698 1.5364-4.0062 0-3.3169-2.6995-6.0164-6.0164-6.0164-3.3169 0-6.0164 2.6995-6.0164 6.0164s2.6995 6.0164 6.0164 6.0164c1.1774 0 2.2688-0.34469 3.1877-0.91896l2.6421 2.6421c0.15799 0.15799 0.37342 0.24416 0.58871 0.24416 0.21544 0 0.43079-0.08617 0.58874-0.24416 0.34469-0.33033 0.34469-0.86155 0.01512-1.1918zm-11.358-6.5477c0-2.3836 1.9384-4.3364 4.3364-4.3364 2.3979 0 4.3221 1.9528 4.3221 4.3364s-1.9384 4.3364-4.3221 4.3364-4.3364-1.9384-4.3364-4.3364z" fill="#fff"/></svg>
|
|
Before Width: | Height: | Size: 660 B |
Before Width: | Height: | Size: 7.9 KiB |
@@ -1 +0,0 @@
|
|||||||
<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><path d="m14.125 8.875h-1.75c-0.48386 0-0.87498-0.39113-0.87498-0.87498 0-0.48389 0.39113-0.87502 0.87498-0.87502h1.75c0.48386 0 0.87498 0.39113 0.87498 0.87502 0 0.48386-0.39113 0.87498-0.87498 0.87498zm-2.4133-3.3494c-0.34211 0.34211-0.89513 0.34211-1.2372 0-0.34211-0.34214-0.34211-0.89513 0-1.2373l1.2372-1.2372c0.34211-0.34211 0.89513-0.34211 1.2372 0 0.34211 0.34214 0.34211 0.89513 0 1.2372zm-3.7117 9.4744c-0.48389 0-0.87501-0.39113-0.87501-0.87498v-1.75c0-0.48386 0.39113-0.87498 0.87501-0.87498 0.48386 0 0.87498 0.39113 0.87498 0.87498v1.75c0 0.48386-0.39113 0.87498-0.87498 0.87498zm0-10.5c-0.48389 0-0.87501-0.39113-0.87501-0.87498v-1.75c0-0.48386 0.39113-0.87498 0.87501-0.87498 0.48386 0 0.87498 0.39113 0.87498 0.87498v1.75c0 0.48386-0.39113 0.87498-0.87498 0.87498zm-3.7117 8.449c-0.34211 0.34211-0.8951 0.34211-1.2372 0-0.34211-0.34211-0.34211-0.89513 0-1.2372l1.2372-1.2372c0.34214-0.34211 0.89513-0.34211 1.2373 0 0.34211 0.34211 0.34211 0.89513 0 1.2372zm0-7.4234-1.2372-1.2373c-0.34211-0.34211-0.34211-0.8951 0-1.2372 0.34214-0.34211 0.89513-0.34211 1.2372 0l1.2373 1.2372c0.34211 0.34214 0.34211 0.89513 0 1.2373-0.34214 0.34211-0.89513 0.34211-1.2373 0zm0.21165 2.4744c0 0.48386-0.39113 0.87498-0.87498 0.87498h-1.75c-0.48386 0-0.87498-0.39113-0.87498-0.87498 0-0.48389 0.39113-0.87501 0.87498-0.87501h1.75c0.48386 0 0.87498 0.39113 0.87498 0.87501zm7.2117 2.4744 1.2372 1.2372c0.34211 0.34211 0.34211 0.89598 0 1.2372-0.34211 0.34126-0.89513 0.34211-1.2372 0l-1.2372-1.2372c-0.34211-0.34211-0.34211-0.89513 0-1.2372s0.89513-0.34211 1.2372 0z" fill="#fff"/></svg>
|
|
Before Width: | Height: | Size: 1.7 KiB |
@@ -1 +0,0 @@
|
|||||||
<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><path d="m7.9881 1.001c-3.6755 0-6.6898 2.835-6.9751 6.4383l3.752 1.5505c0.31806-0.21655 0.70174-0.34431 1.1152-0.34431 0.03671 0 0.07309 0.0017 0.1098 0.0033l1.6691-2.4162v-0.03456c0-1.4556 1.183-2.639 2.639-2.639 1.4547 0 2.639 1.1847 2.639 2.6407 0 1.456-1.1843 2.6395-2.639 2.6395h-0.06118l-2.3778 1.6979c0 0.03009 0.0017 0.06118 0.0017 0.09276 0 1.0938-0.88376 1.981-1.9776 1.981-0.95374 0-1.7592-0.68426-1.9429-1.5907l-2.6863-1.1126c0.83168 2.9383 3.5292 5.0924 6.7335 5.0924 3.8657 0 6.9995-3.1343 6.9995-7s-3.1343-7-6.9995-7zm-2.5895 10.623-0.85924-0.35569c0.15262 0.31676 0.4165 0.58274 0.7665 0.72931 0.75645 0.31456 1.6293-0.04415 1.9438-0.80194 0.15361-0.3675 0.15394-0.76956 0.0033-1.1371-0.15097-0.3675-0.4375-0.65408-0.80324-0.80674-0.364-0.1518-0.7525-0.14535-1.0955-0.01753l0.88855 0.3675c0.55782 0.23318 0.82208 0.875 0.58845 1.4319-0.23145 0.55826-0.87326 0.8225-1.4315 0.59019zm6.6587-5.4267c0-0.96948-0.78926-1.7587-1.7587-1.7587-0.97126 0-1.7587 0.78926-1.7587 1.7587 0 0.97126 0.7875 1.7587 1.7587 1.7587 0.96994 0 1.7587-0.7875 1.7587-1.7587zm-3.0756-0.0033c0-0.73019 0.59106-1.3217 1.3212-1.3217 0.72844 0 1.3217 0.59148 1.3217 1.3217 0 0.72976-0.59326 1.3213-1.3217 1.3213-0.73106 0-1.3212-0.5915-1.3212-1.3213z" fill="#fff"/></svg>
|
|
Before Width: | Height: | Size: 1.3 KiB |
@@ -1 +0,0 @@
|
|||||||
<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><rect x="1" y="1" width="14" height="14" rx="2.8" fill="#fff" fill-rule="evenodd"/></svg>
|
|
Before Width: | Height: | Size: 208 B |
@@ -1 +0,0 @@
|
|||||||
<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><path d="m1 11.5 7-7 7 7z" fill="#fff"/></svg>
|
|
Before Width: | Height: | Size: 165 B |
@@ -1 +0,0 @@
|
|||||||
<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><path d="m8 15q-1.4583 0-2.7319-0.55417-1.2735-0.55417-2.2167-1.4972-0.94313-0.94306-1.4972-2.2167t-0.55417-2.7319q-7.699e-5 -1.4583 0.55417-2.7319 0.55424-1.2736 1.4972-2.2167 0.94298-0.94306 2.2167-1.4972 1.2737-0.55417 2.7319-0.55417 1.5944 0 3.0237 0.68056 1.4292 0.68056 2.4208 1.925v-1.8278h1.5556v4.6667h-4.6667v-1.5556h2.1389q-0.79722-1.0889-1.9639-1.7111-1.1667-0.62222-2.5083-0.62222-2.275 0-3.8596 1.5848t-1.5848 3.8596q-1.55e-4 2.2748 1.5848 3.8596 1.585 1.5848 3.8596 1.5848 2.0417 0 3.5681-1.3222t1.7985-3.3444h1.5944q-0.29167 2.6639-2.2848 4.443-1.9931 1.7791-4.6763 1.7792z"/></svg>
|
|
Before Width: | Height: | Size: 717 B |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.6 MiB |
Before Width: | Height: | Size: 475 KiB |
Before Width: | Height: | Size: 151 KiB |
@@ -1,5 +0,0 @@
|
|||||||
[Metainfo]
|
|
||||||
author = BlackSnaker
|
|
||||||
author_link =
|
|
||||||
description = Стандартная тема PortProtonQt (светлый вариант)
|
|
||||||
name = Light
|
|
@@ -1,712 +0,0 @@
|
|||||||
from portprotonqt.theme_manager import ThemeManager
|
|
||||||
from portprotonqt.config_utils import read_theme_from_config
|
|
||||||
|
|
||||||
theme_manager = ThemeManager()
|
|
||||||
current_theme_name = read_theme_from_config()
|
|
||||||
|
|
||||||
# КОНСТАНТЫ
|
|
||||||
favoriteLabelSize = 48, 48
|
|
||||||
pixmapsScaledSize = 60, 60
|
|
||||||
|
|
||||||
GAME_CARD_ANIMATION = {
|
|
||||||
# Тип анимации fade при входе на детальную страницу
|
|
||||||
# Возможные значения: "fade", "slide_left", "slide_right", "slide_up", "slide_down", "bounce", "none"
|
|
||||||
"detail_page_animation_type": "fade",
|
|
||||||
|
|
||||||
# Ширина обводки карточки в состоянии покоя (без наведения или фокуса).
|
|
||||||
# Влияет на толщину рамки вокруг карточки, когда она не выделена.
|
|
||||||
# Значение в пикселях.
|
|
||||||
"default_border_width": 2,
|
|
||||||
|
|
||||||
# Ширина обводки при наведении курсора.
|
|
||||||
# Увеличивает толщину рамки, когда курсор находится над карточкой.
|
|
||||||
# Значение в пикселях.
|
|
||||||
"hover_border_width": 8,
|
|
||||||
|
|
||||||
# Ширина обводки при фокусе (например, при выборе с клавиатуры).
|
|
||||||
# Увеличивает толщину рамки, когда карточка в фокусе.
|
|
||||||
# Значение в пикселях.
|
|
||||||
"focus_border_width": 12,
|
|
||||||
|
|
||||||
# Минимальная ширина обводки во время пульсирующей анимации.
|
|
||||||
# Определяет минимальную толщину рамки при пульсации (анимация "дыхания").
|
|
||||||
# Значение в пикселях.
|
|
||||||
"pulse_min_border_width": 8,
|
|
||||||
|
|
||||||
# Максимальная ширина обводки во время пульсирующей анимации.
|
|
||||||
# Определяет максимальную толщину рамки при пульсации.
|
|
||||||
# Значение в пикселях.
|
|
||||||
"pulse_max_border_width": 10,
|
|
||||||
|
|
||||||
# Длительность анимации изменения толщины обводки (например, при наведении или фокусе).
|
|
||||||
# Влияет на скорость перехода от одной ширины обводки к другой.
|
|
||||||
# Значение в миллисекундах.
|
|
||||||
"thickness_anim_duration": 300,
|
|
||||||
|
|
||||||
# Длительность одного цикла пульсирующей анимации.
|
|
||||||
# Определяет, как быстро рамка "пульсирует" между min и max значениями.
|
|
||||||
# Значение в миллисекундах.
|
|
||||||
"pulse_anim_duration": 800,
|
|
||||||
|
|
||||||
# Длительность анимации вращения градиента.
|
|
||||||
# Влияет на скорость, с которой градиентная обводка вращается вокруг карточки.
|
|
||||||
# Значение в миллисекундах.
|
|
||||||
"gradient_anim_duration": 3000,
|
|
||||||
|
|
||||||
# Начальный угол градиента (в градусах).
|
|
||||||
# Определяет начальную точку вращения градиента при старте анимации.
|
|
||||||
"gradient_start_angle": 360,
|
|
||||||
|
|
||||||
# Конечный угол градиента (в градусах).
|
|
||||||
# Определяет конечную точку вращения градиента.
|
|
||||||
# Значение 0 означает полный поворот на 360 градусов.
|
|
||||||
"gradient_end_angle": 0,
|
|
||||||
|
|
||||||
# Тип кривой сглаживания для анимации увеличения обводки (при наведении/фокусе).
|
|
||||||
# Влияет на "чувство" анимации (например, плавное ускорение или замедление).
|
|
||||||
# Возможные значения: строки, соответствующие QEasingCurve.Type (например, "OutBack", "InOutQuad").
|
|
||||||
"thickness_easing_curve": "OutBack",
|
|
||||||
|
|
||||||
# Тип кривой сглаживания для анимации уменьшения обводки (при уходе курсора/потере фокуса).
|
|
||||||
# Влияет на "чувство" возврата к исходной ширине обводки.
|
|
||||||
"thickness_easing_curve_out": "InBack",
|
|
||||||
|
|
||||||
# Цвета градиента для анимированной обводки.
|
|
||||||
# Список словарей, где каждый словарь задает позицию (0.0–1.0) и цвет в формате hex.
|
|
||||||
# Влияет на внешний вид обводки при наведении или фокусе.
|
|
||||||
"gradient_colors": [
|
|
||||||
{"position": 0, "color": "#00fff5"}, # Начальный цвет (циан)
|
|
||||||
{"position": 0.33, "color": "#FF5733"}, # Цвет на 33% (оранжевый)
|
|
||||||
{"position": 0.66, "color": "#9B59B6"}, # Цвет на 66% (пурпурный)
|
|
||||||
{"position": 1, "color": "#00fff5"} # Конечный цвет (возвращение к циану)
|
|
||||||
],
|
|
||||||
|
|
||||||
# Длительность анимации fade при входе на детальную страницу
|
|
||||||
"detail_page_fade_duration": 350,
|
|
||||||
|
|
||||||
# Длительность анимации slide при входе на детальную страницу
|
|
||||||
"detail_page_slide_duration": 500,
|
|
||||||
|
|
||||||
# Длительность анимации zoom при входе на детальную страницу
|
|
||||||
"detail_page_zoom_duration": 400
|
|
||||||
}
|
|
||||||
|
|
||||||
# СТИЛЬ ШАПКИ ГЛАВНОГО ОКНА
|
|
||||||
MAIN_WINDOW_HEADER_STYLE = """
|
|
||||||
QFrame {
|
|
||||||
background: transparent;
|
|
||||||
border: 10px solid rgba(255, 255, 255, 0.10);
|
|
||||||
border-bottom: 0px solid rgba(255, 255, 255, 0.15);
|
|
||||||
border-top-left-radius: 30px;
|
|
||||||
border-top-right-radius: 30px;
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
|
|
||||||
# СТИЛЬ ЗАГОЛОВКА (ЛОГО) В ШАПКЕ
|
|
||||||
TITLE_LABEL_STYLE = """
|
|
||||||
QLabel {
|
|
||||||
font-family: 'RASKHAL';
|
|
||||||
font-size: 38px;
|
|
||||||
margin: 0 0 0 0;
|
|
||||||
color: #007AFF;
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
|
|
||||||
# СТИЛЬ ОБЛАСТИ НАВИГАЦИИ (КНОПКИ ВКЛАДОК)
|
|
||||||
NAV_WIDGET_STYLE = """
|
|
||||||
QWidget {
|
|
||||||
background: #ffffff;
|
|
||||||
border-bottom: 0px solid rgba(0, 0, 0, 0.10);
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
|
|
||||||
# СТИЛЬ КНОПОК ВКЛАДОК НАВИГАЦИИ
|
|
||||||
NAV_BUTTON_STYLE = """
|
|
||||||
NavLabel {
|
|
||||||
background: qlineargradient(x1:0, y1:0, x2:1, y2:0,
|
|
||||||
stop:0 rgba(242, 242, 242, 0.5),
|
|
||||||
stop:1 rgba(232, 232, 232, 0.5));
|
|
||||||
padding: 10px 10px;
|
|
||||||
margin: 10px 0 10px 10px;
|
|
||||||
color: #333333;
|
|
||||||
font-size: 16px;
|
|
||||||
font-family: 'Poppins';
|
|
||||||
text-transform: uppercase;
|
|
||||||
border: 1px solid rgba(179, 179, 179, 0.4);
|
|
||||||
border-radius: 15px;
|
|
||||||
}
|
|
||||||
NavLabel[checked = true] {
|
|
||||||
background: rgba(0,122,255,0.25);
|
|
||||||
color: #002244;
|
|
||||||
font-weight: bold;
|
|
||||||
border-radius: 15px;
|
|
||||||
}
|
|
||||||
NavLabel:hover {
|
|
||||||
background: qlineargradient(x1:0, y1:0, x2:1, y2:0,
|
|
||||||
stop:0 rgba(0,122,255,0.12),
|
|
||||||
stop:1 rgba(0,122,255,0.08));
|
|
||||||
color: #002244;
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
|
|
||||||
# ГЛОБАЛЬНЫЙ СТИЛЬ ДЛЯ ОКНА (ФОН) И QLabel
|
|
||||||
MAIN_WINDOW_STYLE = """
|
|
||||||
QMainWindow {
|
|
||||||
background: none;
|
|
||||||
}
|
|
||||||
QLabel {
|
|
||||||
color: #333333;
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
|
|
||||||
# СТИЛЬ ПОЛЯ ПОИСКА
|
|
||||||
SEARCH_EDIT_STYLE = """
|
|
||||||
QLineEdit {
|
|
||||||
background-color: rgba(30, 30, 30, 0.50);
|
|
||||||
border: 1px solid rgba(255, 255, 255, 0.5);
|
|
||||||
border-radius: 10px;
|
|
||||||
padding: 7px 14px;
|
|
||||||
font-family: 'Poppins';
|
|
||||||
font-size: 16px;
|
|
||||||
color: #ffffff;
|
|
||||||
}
|
|
||||||
QLineEdit:focus {
|
|
||||||
border: 1px solid rgba(0,122,255,0.25);
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
|
|
||||||
# ОТКЛЮЧАЕМ РАМКУ У QScrollArea
|
|
||||||
SCROLL_AREA_STYLE = """
|
|
||||||
QWidget {
|
|
||||||
background: transparent;
|
|
||||||
}
|
|
||||||
QScrollBar:vertical {
|
|
||||||
width: 10px;
|
|
||||||
border: 0px solid;
|
|
||||||
border-radius: 5px;
|
|
||||||
background: rgba(20, 20, 20, 0.30);
|
|
||||||
}
|
|
||||||
QScrollBar::handle:vertical {
|
|
||||||
background: rgba(255, 255, 255, 0.7);
|
|
||||||
border: 0px solid;
|
|
||||||
border-radius: 5px;
|
|
||||||
}
|
|
||||||
QScrollBar::add-line:vertical {
|
|
||||||
border: 0px solid;
|
|
||||||
background: none;
|
|
||||||
}
|
|
||||||
QScrollBar::sub-line:vertical {
|
|
||||||
border: 0px solid;
|
|
||||||
background: none;
|
|
||||||
}
|
|
||||||
QScrollBar::up-arrow:vertical, QScrollBar::down-arrow:vertical {
|
|
||||||
border: 0px solid;
|
|
||||||
width: 3px;
|
|
||||||
height: 3px;
|
|
||||||
background: none;
|
|
||||||
}
|
|
||||||
QScrollBar:horizontal {
|
|
||||||
height: 10px;
|
|
||||||
border: 0px solid;
|
|
||||||
border-radius: 5px;
|
|
||||||
background: rgba(20, 20, 20, 0.30);
|
|
||||||
}
|
|
||||||
QScrollBar::handle:horizontal {
|
|
||||||
background: #bebebe;
|
|
||||||
border: 0px solid;
|
|
||||||
border-radius: 5px;
|
|
||||||
}
|
|
||||||
QScrollBar::add-line:horizontal {
|
|
||||||
border: 0px solid;
|
|
||||||
background: none;
|
|
||||||
}
|
|
||||||
QScrollBar::sub-line:horizontal {
|
|
||||||
border: 0px solid;
|
|
||||||
background: none;
|
|
||||||
}
|
|
||||||
QScrollBar::up-arrow:horizontal, QScrollBar::down-arrow:horizontal {
|
|
||||||
border: 0px solid;
|
|
||||||
width: 3px;
|
|
||||||
height: 3px;
|
|
||||||
background: none;
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
|
|
||||||
# SLIDER_SIZE_STYLE
|
|
||||||
SLIDER_SIZE_STYLE= """
|
|
||||||
QWidget {
|
|
||||||
background: transparent;
|
|
||||||
height: 25px;
|
|
||||||
}
|
|
||||||
QSlider::groove:horizontal {
|
|
||||||
border: 0px solid;
|
|
||||||
border-radius: 3px;
|
|
||||||
height: 6px; /* the groove expands to the size of the slider by default. by giving it a height, it has a fixed size */
|
|
||||||
background: rgba(20, 20, 20, 0.30);
|
|
||||||
margin: 6px 0;
|
|
||||||
}
|
|
||||||
QSlider::handle:horizontal {
|
|
||||||
background: #bebebe;
|
|
||||||
border: 0px solid;
|
|
||||||
width: 18px;
|
|
||||||
height: 18px;
|
|
||||||
margin: -6px 0; /* handle is placed by default on the contents rect of the groove. Expand outside the groove */
|
|
||||||
border-radius: 9px;
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
|
|
||||||
# СТИЛЬ ОБЛАСТИ ДЛЯ КАРТОЧЕК ИГР (QWidget)
|
|
||||||
LIST_WIDGET_STYLE = """
|
|
||||||
QWidget {
|
|
||||||
background: none;
|
|
||||||
border: 0px solid rgba(255, 255, 255, 0.10);
|
|
||||||
border-radius: 25px;
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
|
|
||||||
# ЗАГОЛОВОК "БИБЛИОТЕКА" НА ВКЛАДКЕ
|
|
||||||
INSTALLED_TAB_TITLE_STYLE = "font-family: 'Poppins'; font-size: 24px; color: #232627;"
|
|
||||||
|
|
||||||
# СТИЛЬ КНОПОК "СОХРАНЕНИЯ, ПРИМЕНЕНИЯ И Т.Д."
|
|
||||||
ACTION_BUTTON_STYLE = """
|
|
||||||
QPushButton {
|
|
||||||
background: qlineargradient(x1:0, y1:0, x2:1, y2:0,
|
|
||||||
stop:0 rgba(242, 242, 242, 0.5),
|
|
||||||
stop:1 rgba(232, 232, 232, 0.5));
|
|
||||||
border: 1px solid rgba(179, 179, 179, 0.4);
|
|
||||||
border-radius: 10px;
|
|
||||||
color: #232627;
|
|
||||||
font-size: 16px;
|
|
||||||
font-family: 'Poppins';
|
|
||||||
padding: 8px 16px;
|
|
||||||
}
|
|
||||||
QPushButton:hover {
|
|
||||||
background: rgba(0,122,255,0.25);
|
|
||||||
}
|
|
||||||
QPushButton:pressed {
|
|
||||||
background: rgba(0,122,255,0.25);
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
|
|
||||||
# ТЕКСТОВЫЕ СТИЛИ: ЗАГОЛОВКИ И ОСНОВНОЙ КОНТЕНТ
|
|
||||||
TAB_TITLE_STYLE = "font-family: 'Poppins'; font-size: 24px; color: #232627; background-color: none;"
|
|
||||||
CONTENT_STYLE = """
|
|
||||||
QLabel {
|
|
||||||
font-family: 'Poppins';
|
|
||||||
font-size: 16px;
|
|
||||||
color: #232627;
|
|
||||||
background-color: none;
|
|
||||||
border-bottom: 1px solid rgba(165, 165, 165, 0.7);
|
|
||||||
padding-bottom: 15px;
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
|
|
||||||
# СТИЛЬ ОСНОВНЫХ СТРАНИЦ
|
|
||||||
# LIBRARY_WIDGET_STYLE
|
|
||||||
LIBRARY_WIDGET_STYLE= """
|
|
||||||
QWidget {
|
|
||||||
background: qlineargradient(spread:pad, x1:0.162, y1:0.0313409, x2:1, y2:1, stop:0 rgba(215, 235, 255, 255), stop:1 rgba(253, 252, 255, 255));
|
|
||||||
border-radius: 0px;
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
|
|
||||||
# CONTAINER_STYLE
|
|
||||||
CONTAINER_STYLE= """
|
|
||||||
QWidget {
|
|
||||||
background-color: none;
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
|
|
||||||
# OTHER_PAGES_WIDGET_STYLE
|
|
||||||
OTHER_PAGES_WIDGET_STYLE= """
|
|
||||||
QWidget {
|
|
||||||
background: qlineargradient(spread:pad, x1:0.162, y1:0.0313409, x2:1, y2:1, stop:0 rgba(215, 235, 255, 255), stop:1 rgba(253, 252, 255, 255));
|
|
||||||
border-radius: 0px;
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
|
|
||||||
# CAROUSEL_WIDGET_STYLE
|
|
||||||
CAROUSEL_WIDGET_STYLE= """
|
|
||||||
QWidget {
|
|
||||||
background: qlineargradient(spread:pad, x1:0.099, y1:0.119, x2:0.917, y2:0.936149, stop:0 rgba(215, 235, 255, 255), stop:1 rgba(217, 193, 255, 255));
|
|
||||||
border-radius: 0px;
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
|
|
||||||
# ФОН ДЛЯ ДЕТАЛЬНОЙ СТРАНИЦЫ, ЕСЛИ ОБЛОЖКА НЕ ЗАГРУЖЕНА
|
|
||||||
DETAIL_PAGE_NO_COVER_STYLE = "background: rgba(20,20,20,0.95); border-radius: 15px;"
|
|
||||||
|
|
||||||
# СТИЛЬ КНОПКИ "ДОБАВИТЬ ИГРУ" И "НАЗАД" НА ДЕТАЛЬНОЙ СТРАНИЦЕ И БИБЛИОТЕКИ
|
|
||||||
ADDGAME_BACK_BUTTON_STYLE = """
|
|
||||||
QPushButton {
|
|
||||||
background: rgba(20, 20, 20, 0.40);
|
|
||||||
border: 1px solid rgba(255, 255, 255, 0.5);
|
|
||||||
border-radius: 10px;
|
|
||||||
color: #ffffff;
|
|
||||||
font-size: 16px;
|
|
||||||
font-family: 'Poppins';
|
|
||||||
padding: 4px 16px;
|
|
||||||
}
|
|
||||||
QPushButton:hover {
|
|
||||||
background: rgba(0,122,255,0.25);
|
|
||||||
}
|
|
||||||
QPushButton:pressed {
|
|
||||||
background: rgba(0,122,255,0.25);
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
|
|
||||||
# ОСНОВНОЙ ФРЕЙМ ДЕТАЛЕЙ ИГРЫ
|
|
||||||
DETAIL_CONTENT_FRAME_STYLE = """
|
|
||||||
QFrame {
|
|
||||||
background: qlineargradient(x1:0, y1:0, x2:1, y2:0,
|
|
||||||
stop:0 rgba(20, 20, 20, 0.40),
|
|
||||||
stop:1 rgba(20, 20, 20, 0.35));
|
|
||||||
border: 0px solid rgba(255, 255, 255, 0.10);
|
|
||||||
border-radius: 15px;
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
|
|
||||||
# ФРЕЙМ ПОД ОБЛОЖКОЙ
|
|
||||||
COVER_FRAME_STYLE = """
|
|
||||||
QFrame {
|
|
||||||
background: rgba(30, 30, 30, 0.80);
|
|
||||||
border-radius: 15px;
|
|
||||||
border: 0px solid rgba(255, 255, 255, 0.15);
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
|
|
||||||
# СКРУГЛЕНИЕ LABEL ПОД ОБЛОЖКУ
|
|
||||||
COVER_LABEL_STYLE = "border-radius: 100px;"
|
|
||||||
|
|
||||||
# ВИДЖЕТ ДЕТАЛЕЙ (ТЕКСТ, ОПИСАНИЕ)
|
|
||||||
DETAILS_WIDGET_STYLE = "background: rgba(20,20,20,0.40); border-radius: 15px; padding: 10px;"
|
|
||||||
|
|
||||||
# НАЗВАНИЕ (ЗАГОЛОВОК) НА ДЕТАЛЬНОЙ СТРАНИЦЕ
|
|
||||||
DETAIL_PAGE_TITLE_STYLE = "font-family: 'Orbitron'; font-size: 32px; color: #007AFF;"
|
|
||||||
|
|
||||||
# ЛИНИЯ-РАЗДЕЛИТЕЛЬ
|
|
||||||
DETAIL_PAGE_LINE_STYLE = "color: rgba(255,255,255,0.12); margin: 10px 0;"
|
|
||||||
|
|
||||||
# ТЕКСТ ОПИСАНИЯ
|
|
||||||
DETAIL_PAGE_DESC_STYLE = "font-family: 'Poppins'; font-size: 16px; color: #ffffff; line-height: 1.5;"
|
|
||||||
|
|
||||||
# СТИЛЬ КНОПКИ "ИГРАТЬ"
|
|
||||||
PLAY_BUTTON_STYLE = """
|
|
||||||
QPushButton {
|
|
||||||
background: rgba(20, 20, 20, 0.40);
|
|
||||||
border: 1px solid rgba(255, 255, 255, 0.5);
|
|
||||||
border-radius: 10px;
|
|
||||||
font-size: 18px;
|
|
||||||
color: #ffffff;
|
|
||||||
font-weight: bold;
|
|
||||||
font-family: 'Orbitron';
|
|
||||||
padding: 8px 16px;
|
|
||||||
min-width: 120px;
|
|
||||||
min-height: 40px;
|
|
||||||
}
|
|
||||||
QPushButton:hover {
|
|
||||||
background: rgba(0,122,255,0.25);
|
|
||||||
}
|
|
||||||
QPushButton:pressed {
|
|
||||||
background: rgba(0,122,255,0.25);
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
|
|
||||||
# СТИЛЬ КНОПКИ "ОБЗОР..." В ДИАЛОГЕ "ДОБАВИТЬ ИГРУ"
|
|
||||||
DIALOG_BROWSE_BUTTON_STYLE = """
|
|
||||||
QPushButton {
|
|
||||||
background: rgba(20, 20, 20, 0.40);
|
|
||||||
border: 0px solid rgba(255, 255, 255, 0.20);
|
|
||||||
border-radius: 15px;
|
|
||||||
color: #ffffff;
|
|
||||||
font-size: 16px;
|
|
||||||
padding: 5px 10px;
|
|
||||||
}
|
|
||||||
QPushButton:hover {
|
|
||||||
background: qlineargradient(x1:0, y1:0, x2:1, y2:0,
|
|
||||||
stop:0 rgba(0,122,255,0.20),
|
|
||||||
stop:1 rgba(0,122,255,0.15));
|
|
||||||
}
|
|
||||||
QPushButton:pressed {
|
|
||||||
background: rgba(20, 20, 20, 0.60);
|
|
||||||
border: 0px solid rgba(255, 255, 255, 0.25);
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
|
|
||||||
# СТИЛЬ КАРТОЧКИ ИГРЫ (GAMECARD)
|
|
||||||
GAME_CARD_WINDOW_STYLE = """
|
|
||||||
QFrame {
|
|
||||||
border-radius: 20px;
|
|
||||||
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
|
|
||||||
stop:0 rgba(255, 255, 255, 0.3),
|
|
||||||
stop:1 rgba(249, 249, 249, 0.3));
|
|
||||||
border: 0px solid rgba(255, 255, 255, 0.4);
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
|
|
||||||
# НАЗВАНИЕ В КАРТОЧКЕ (QLabel)
|
|
||||||
GAME_CARD_NAME_LABEL_STYLE = """
|
|
||||||
QLabel {
|
|
||||||
color: #333333;
|
|
||||||
font-family: 'Orbitron';
|
|
||||||
font-size: 16px;
|
|
||||||
font-weight: bold;
|
|
||||||
background-color: qlineargradient(x1:0, y1:0, x2:1, y2:0,
|
|
||||||
stop:0 rgba(242, 242, 242, 0.5),
|
|
||||||
stop:1 rgba(232, 232, 232, 0.5));
|
|
||||||
border-radius: 20px;
|
|
||||||
padding: 7px;
|
|
||||||
qproperty-wordWrap: true;
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
|
|
||||||
# ДОПОЛНИТЕЛЬНЫЕ СТИЛИ ИНФОРМАЦИИ НА СТРАНИЦЕ ИГР
|
|
||||||
LAST_LAUNCH_TITLE_STYLE = "font-family: 'Poppins'; font-size: 11px; color: #bbbbbb; text-transform: uppercase; letter-spacing: 0.75px; margin-bottom: 2px;"
|
|
||||||
LAST_LAUNCH_VALUE_STYLE = "font-family: 'Poppins'; font-size: 13px; color: #ffffff; font-weight: 600; letter-spacing: 0.75px;"
|
|
||||||
PLAY_TIME_TITLE_STYLE = "font-family: 'Poppins'; font-size: 11px; color: #bbbbbb; text-transform: uppercase; letter-spacing: 0.75px; margin-bottom: 2px;"
|
|
||||||
PLAY_TIME_VALUE_STYLE = "font-family: 'Poppins'; font-size: 13px; color: #ffffff; font-weight: 600; letter-spacing: 0.75px;"
|
|
||||||
GAMEPAD_SUPPORT_VALUE_STYLE = """
|
|
||||||
font-family: 'Poppins'; font-size: 12px; color: #00ff00;
|
|
||||||
font-weight: bold; background: rgba(0, 0, 0, 0.3);
|
|
||||||
border-radius: 5px; padding: 4px 8px;
|
|
||||||
"""
|
|
||||||
|
|
||||||
# СТИЛИ ПОЛНОЭКРАНОГО ПРЕВЬЮ СКРИНШОТОВ ТЕМЫ
|
|
||||||
PREV_BUTTON_STYLE="background-color: rgba(0, 0, 0, 0.5); color: white; border: none;"
|
|
||||||
NEXT_BUTTON_STYLE="background-color: rgba(0, 0, 0, 0.5); color: white; border: none;"
|
|
||||||
CAPTION_LABEL_STYLE="color: white; font-size: 16px;"
|
|
||||||
|
|
||||||
# СТИЛИ БЕЙДЖА PROTONDB НА КАРТОЧКЕ
|
|
||||||
def get_protondb_badge_style(tier):
|
|
||||||
tier = tier.lower()
|
|
||||||
tier_colors = {
|
|
||||||
"platinum": {"background": "rgba(255,255,255,0.9)", "color": "black"},
|
|
||||||
"gold": {"background": "rgba(253,185,49,0.7)", "color": "black"},
|
|
||||||
"silver": {"background": "rgba(169,169,169,0.8)", "color": "black"},
|
|
||||||
"bronze": {"background": "rgba(205,133,63,0.7)", "color": "black"},
|
|
||||||
"borked": {"background": "rgba(255,0,0,0.7)", "color": "black"},
|
|
||||||
"pending": {"background": "rgba(160,82,45,0.7)", "color": "black"}
|
|
||||||
}
|
|
||||||
colors = tier_colors.get(tier, {"background": "rgba(0, 0, 0, 0.5)", "color": "white"})
|
|
||||||
return f"""
|
|
||||||
qproperty-alignment: AlignCenter;
|
|
||||||
background-color: {colors["background"]};
|
|
||||||
color: {colors["color"]};
|
|
||||||
border-radius: 5px;
|
|
||||||
font-family: 'Poppins';
|
|
||||||
font-weight: bold;
|
|
||||||
"""
|
|
||||||
|
|
||||||
def get_anticheat_badge_style(status):
|
|
||||||
status = status.lower()
|
|
||||||
status_colors = {
|
|
||||||
"supported": {"background": "rgba(102, 168, 15, 0.7)", "color": "black"},
|
|
||||||
"running": {"background": "rgba(25, 113, 194, 0.7)", "color": "black"},
|
|
||||||
"planned": {"background": "rgba(156, 54, 181, 0.7)", "color": "black"},
|
|
||||||
"broken": {"background": "rgba(232, 89, 12, 0.7)", "color": "black"},
|
|
||||||
"denied": {"background": "rgba(224, 49, 49, 0.7)", "color": "black"}
|
|
||||||
}
|
|
||||||
colors = status_colors.get(status, {"background": "rgba(0, 0, 0, 0.5)", "color": "white"})
|
|
||||||
return f"""
|
|
||||||
qproperty-alignment: AlignCenter;
|
|
||||||
background-color: {colors["background"]};
|
|
||||||
color: {colors["color"]};
|
|
||||||
border-radius: 5px;
|
|
||||||
font-family: 'Poppins';
|
|
||||||
font-weight: bold;
|
|
||||||
"""
|
|
||||||
|
|
||||||
# СТИЛИ БЕЙДЖА STEAM
|
|
||||||
STEAM_BADGE_STYLE= """
|
|
||||||
qproperty-alignment: AlignCenter;
|
|
||||||
background: rgba(0, 0, 0, 0.5);
|
|
||||||
color: white;
|
|
||||||
border-radius: 5px;
|
|
||||||
font-family: 'Poppins';
|
|
||||||
font-weight: bold;
|
|
||||||
"""
|
|
||||||
|
|
||||||
# Favorite Star
|
|
||||||
FAVORITE_LABEL_STYLE = "color: gold; font-size: 32px; background: transparent; border: none;"
|
|
||||||
|
|
||||||
# СТИЛИ ДЛЯ QMessageBox (ОКНА СООБЩЕНИЙ)
|
|
||||||
MESSAGE_BOX_STYLE = """
|
|
||||||
QMessageBox {
|
|
||||||
background: qlineargradient(x1:0, y1:0, x2:1, y2:0,
|
|
||||||
stop:0 rgba(40, 40, 40, 0.95),
|
|
||||||
stop:1 rgba(25, 25, 25, 0.95));
|
|
||||||
border: 1px solid rgba(255, 255, 255, 0.15);
|
|
||||||
border-radius: 12px;
|
|
||||||
}
|
|
||||||
QMessageBox QLabel {
|
|
||||||
color: #ffffff;
|
|
||||||
font-family: 'Poppins';
|
|
||||||
font-size: 16px;
|
|
||||||
}
|
|
||||||
QMessageBox QPushButton {
|
|
||||||
background: rgba(30, 30, 30, 0.6);
|
|
||||||
border: 1px solid rgba(165, 165, 165, 0.7);
|
|
||||||
border-radius: 8px;
|
|
||||||
color: #ffffff;
|
|
||||||
font-family: 'Poppins';
|
|
||||||
padding: 8px 20px;
|
|
||||||
min-width: 80px;
|
|
||||||
}
|
|
||||||
QMessageBox QPushButton:hover {
|
|
||||||
background: #09bec8;
|
|
||||||
border-color: rgba(255, 255, 255, 0.3);
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
|
|
||||||
# СТИЛИ ДЛЯ ВКЛАДКИ НАСТРОЕК PORTPROTON
|
|
||||||
# PARAMS_TITLE_STYLE
|
|
||||||
PARAMS_TITLE_STYLE = "color: #232627; font-family: 'Poppins'; font-size: 16px; padding: 10px; background: transparent;"
|
|
||||||
|
|
||||||
PROXY_INPUT_STYLE = """
|
|
||||||
QLineEdit {
|
|
||||||
background: rgba(20, 20, 20, 0.40);
|
|
||||||
border: 0px solid rgba(165, 165, 165, 0.7);
|
|
||||||
border-radius: 10px;
|
|
||||||
height: 34px;
|
|
||||||
padding-left: 12px;
|
|
||||||
color: #ffffff;
|
|
||||||
font-family: 'Poppins';
|
|
||||||
font-size: 16px;
|
|
||||||
}
|
|
||||||
QLineEdit:focus {
|
|
||||||
border: 1px solid rgba(0,122,255,0.25);
|
|
||||||
}
|
|
||||||
QMenu {
|
|
||||||
border: 1px solid rgba(255, 255, 255, 0.5);
|
|
||||||
padding: 5px 10px;
|
|
||||||
background: #c7c7c7;
|
|
||||||
}
|
|
||||||
QMenu::item {
|
|
||||||
padding: 0px 10px;
|
|
||||||
border: 10px solid transparent; /* reserve space for selection border */
|
|
||||||
}
|
|
||||||
QMenu::item:selected {
|
|
||||||
background: 1px solid rgba(255, 255, 255, 0.5);
|
|
||||||
border-radius: 10px;
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
|
|
||||||
SETTINGS_COMBO_STYLE = f"""
|
|
||||||
QComboBox {{
|
|
||||||
background: rgba(20, 20, 20, 0.40);
|
|
||||||
border: 1px solid rgba(255, 255, 255, 0.5);
|
|
||||||
border-radius: 10px;
|
|
||||||
height: 34px;
|
|
||||||
padding-left: 12px;
|
|
||||||
color: #ffffff;
|
|
||||||
font-family: 'Poppins';
|
|
||||||
font-size: 16px;
|
|
||||||
min-width: 120px;
|
|
||||||
combobox-popup: 0;
|
|
||||||
}}
|
|
||||||
QComboBox:on {{
|
|
||||||
background: rgba(20, 20, 20, 0.40);
|
|
||||||
border: 1px solid rgba(165, 165, 165, 0.7);
|
|
||||||
border-top-left-radius: 10px;
|
|
||||||
border-top-right-radius: 10px;
|
|
||||||
border-bottom-left-radius: 0px;
|
|
||||||
border-bottom-right-radius: 0px;
|
|
||||||
}}
|
|
||||||
QComboBox:hover {{
|
|
||||||
border: 1px solid rgba(165, 165, 165, 0.7);
|
|
||||||
}}
|
|
||||||
QComboBox::drop-down {{
|
|
||||||
subcontrol-origin: padding;
|
|
||||||
subcontrol-position: center right;
|
|
||||||
border-left: 1px solid rgba(255, 255, 255, 0.5);
|
|
||||||
padding: 12px;
|
|
||||||
height: 12px;
|
|
||||||
width: 12px;
|
|
||||||
}}
|
|
||||||
QComboBox::down-arrow {{
|
|
||||||
image: url({theme_manager.get_icon("down", current_theme_name, as_path=True)});
|
|
||||||
padding: 12px;
|
|
||||||
height: 12px;
|
|
||||||
width: 12px;
|
|
||||||
}}
|
|
||||||
QComboBox::down-arrow:on {{
|
|
||||||
image: url({theme_manager.get_icon("up", current_theme_name, as_path=True)});
|
|
||||||
padding: 12px;
|
|
||||||
height: 12px;
|
|
||||||
width: 12px;
|
|
||||||
}}
|
|
||||||
QComboBox QAbstractItemView {{
|
|
||||||
outline: none;
|
|
||||||
border: 1px solid rgba(165, 165, 165, 0.7);
|
|
||||||
border-top-style: none;
|
|
||||||
}}
|
|
||||||
QListView {{
|
|
||||||
background: #ffffff;
|
|
||||||
}}
|
|
||||||
QListView::item {{
|
|
||||||
padding: 7px 7px 7px 12px;
|
|
||||||
border-radius: 0px;
|
|
||||||
color: #232627;
|
|
||||||
}}
|
|
||||||
QListView::item:hover {{
|
|
||||||
background: rgba(0,122,255,0.25);
|
|
||||||
}}
|
|
||||||
QListView::item:selected {{
|
|
||||||
background: rgba(0,122,255,0.25);
|
|
||||||
}}
|
|
||||||
"""
|
|
||||||
|
|
||||||
class FileExplorerStyles:
|
|
||||||
WINDOW_STYLE = """
|
|
||||||
QDialog {
|
|
||||||
background-color: #2d2d2d;
|
|
||||||
color: #ffffff;
|
|
||||||
font-family: "Arial";
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
|
|
||||||
PATH_LABEL_STYLE = """
|
|
||||||
QLabel {
|
|
||||||
color: #3daee9;
|
|
||||||
font-size: 16px;
|
|
||||||
padding: 5px;
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
|
|
||||||
LIST_STYLE = """
|
|
||||||
QListWidget {
|
|
||||||
font-size: 16px;
|
|
||||||
background-color: #353535;
|
|
||||||
color: #eee;
|
|
||||||
border: 1px solid #444;
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
QListWidget::item {
|
|
||||||
padding: 8px;
|
|
||||||
border-bottom: 1px solid #444;
|
|
||||||
}
|
|
||||||
QListWidget::item:selected {
|
|
||||||
background-color: #3daee9;
|
|
||||||
color: white;
|
|
||||||
border-radius: 2px;
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
|
|
||||||
BUTTON_STYLE = """
|
|
||||||
QPushButton {
|
|
||||||
background-color: #3daee9;
|
|
||||||
color: white;
|
|
||||||
border: none;
|
|
||||||
padding: 8px 16px;
|
|
||||||
border-radius: 4px;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
QPushButton:hover {
|
|
||||||
background-color: #2c9fd8;
|
|
||||||
}
|
|
||||||
QPushButton:pressed {
|
|
||||||
background-color: #1a8fc7;
|
|
||||||
}
|
|
||||||
"""
|
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
@@ -27,7 +27,7 @@ color_g = "rgba(0, 0, 0, 0)"
|
|||||||
color_h = "transparent"
|
color_h = "transparent"
|
||||||
|
|
||||||
GAME_CARD_ANIMATION = {
|
GAME_CARD_ANIMATION = {
|
||||||
# Тип анимации fade при входе на детальную страницу
|
# Тип анимации при входе и выходе на детальную страницу
|
||||||
# Возможные значения: "fade", "slide_left", "slide_right", "slide_up", "slide_down", "bounce"
|
# Возможные значения: "fade", "slide_left", "slide_right", "slide_up", "slide_down", "bounce"
|
||||||
"detail_page_animation_type": "fade",
|
"detail_page_animation_type": "fade",
|
||||||
|
|
||||||
@@ -105,8 +105,25 @@ GAME_CARD_ANIMATION = {
|
|||||||
# Длительность анимации slide при входе на детальную страницу
|
# Длительность анимации slide при входе на детальную страницу
|
||||||
"detail_page_slide_duration": 500,
|
"detail_page_slide_duration": 500,
|
||||||
|
|
||||||
# Длительность анимации zoom при входе на детальную страницу
|
# Длительность анимации bounce при входе на детальную страницу
|
||||||
"detail_page_zoom_duration": 400
|
"detail_page_bounce_duration": 400,
|
||||||
|
|
||||||
|
# Длительность анимации fade при выходе из детальной страницы
|
||||||
|
"detail_page_fade_duration_exit": 350,
|
||||||
|
|
||||||
|
# Длительность анимации slide при выходе из детальной страницы
|
||||||
|
"detail_page_slide_duration_exit": 500,
|
||||||
|
|
||||||
|
# Длительность анимации bounce при выходе из детальной страницы
|
||||||
|
"detail_page_bounce_duration_exit": 400,
|
||||||
|
|
||||||
|
# Тип кривой сглаживания для анимации при входе на детальную страницу
|
||||||
|
# Применяется к slide и bounce анимациям
|
||||||
|
"detail_page_easing_curve": "OutCubic",
|
||||||
|
|
||||||
|
# Тип кривой сглаживания для анимации при выходе из детальной страницы
|
||||||
|
# Применяется к slide и bounce анимациям
|
||||||
|
"detail_page_easing_curve_exit": "InCubic"
|
||||||
}
|
}
|
||||||
|
|
||||||
CONTEXT_MENU_STYLE = f"""
|
CONTEXT_MENU_STYLE = f"""
|
||||||
|
@@ -1,49 +0,0 @@
|
|||||||
from PySide6.QtGui import QAction, QIcon
|
|
||||||
from PySide6.QtWidgets import QSystemTrayIcon, QMenu
|
|
||||||
from portprotonqt.theme_manager import ThemeManager
|
|
||||||
from typing import cast
|
|
||||||
import portprotonqt.themes.standart.styles as default_styles
|
|
||||||
from portprotonqt.config_utils import read_theme_from_config
|
|
||||||
|
|
||||||
class SystemTray:
|
|
||||||
def __init__(self, app, theme=None):
|
|
||||||
self.app = app
|
|
||||||
self.theme_manager = ThemeManager()
|
|
||||||
self.theme = theme if theme is not None else default_styles
|
|
||||||
self.current_theme_name = read_theme_from_config()
|
|
||||||
self.tray = QSystemTrayIcon()
|
|
||||||
self.tray.setIcon(cast(QIcon, self.theme_manager.get_icon("ppqt-tray", self.current_theme_name)))
|
|
||||||
self.tray.setToolTip("PortProtonQt")
|
|
||||||
self.tray.setVisible(True)
|
|
||||||
|
|
||||||
# Создаём меню
|
|
||||||
self.menu = QMenu()
|
|
||||||
|
|
||||||
self.hide_action = QAction("Скрыть окно")
|
|
||||||
self.menu.addAction(self.hide_action)
|
|
||||||
|
|
||||||
self.show_action = QAction("Показать окно")
|
|
||||||
self.menu.addAction(self.show_action)
|
|
||||||
|
|
||||||
self.quit_action = QAction("Выход")
|
|
||||||
self.quit_action.triggered.connect(app.quit)
|
|
||||||
self.menu.addAction(self.quit_action)
|
|
||||||
|
|
||||||
self.tray.setContextMenu(self.menu)
|
|
||||||
|
|
||||||
def hide_tray(self):
|
|
||||||
"""Скрыть иконку трея"""
|
|
||||||
if self.tray:
|
|
||||||
self.tray.setVisible(False)
|
|
||||||
if self.menu:
|
|
||||||
self.menu.deleteLater()
|
|
||||||
self.menu = None
|
|
||||||
|
|
||||||
def cleanup(self):
|
|
||||||
"""Очистка ресурсов трея"""
|
|
||||||
if self.tray:
|
|
||||||
self.tray.setVisible(False)
|
|
||||||
self.tray = None
|
|
||||||
if self.menu:
|
|
||||||
self.menu.deleteLater()
|
|
||||||
self.menu = None
|
|
@@ -28,17 +28,18 @@ requires-python = ">=3.10"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"babel>=2.17.0",
|
"babel>=2.17.0",
|
||||||
"beautifulsoup4>=4.13.4",
|
"beautifulsoup4>=4.13.4",
|
||||||
"evdev>=1.9.1",
|
"evdev>=1.9.2",
|
||||||
"icoextract>=0.1.6",
|
"icoextract>=0.2.0",
|
||||||
"numpy>=2.2.4",
|
"numpy>=2.2.4",
|
||||||
"orjson>=3.10.16",
|
"orjson>=3.11.2",
|
||||||
"pillow>=11.2.1",
|
"pillow>=11.3.0",
|
||||||
"psutil>=7.0.0",
|
"psutil>=7.0.0",
|
||||||
"pyside6>=6.9.0",
|
"pyside6>=6.9.1",
|
||||||
"pyudev>=0.24.3",
|
"pyudev>=0.24.3",
|
||||||
"requests>=2.32.3",
|
"requests>=2.32.4",
|
||||||
"tqdm>=4.67.1",
|
"tqdm>=4.67.1",
|
||||||
"vdf>=3.4",
|
"vdf>=3.4",
|
||||||
|
"websocket-client>=1.8.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[project.scripts]
|
[project.scripts]
|
||||||
@@ -102,7 +103,7 @@ ignore = [
|
|||||||
|
|
||||||
[dependency-groups]
|
[dependency-groups]
|
||||||
dev = [
|
dev = [
|
||||||
"pre-commit>=4.2.0",
|
"pre-commit>=4.3.0",
|
||||||
"pyaspeller>=2.0.2",
|
"pyaspeller>=2.0.2",
|
||||||
"pyright>=1.1.400",
|
"pyright>=1.1.403",
|
||||||
]
|
]
|
||||||
|
@@ -15,12 +15,23 @@
|
|||||||
"enabled": false
|
"enabled": false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"matchFileNames": [".gitea/workflows/**.yaml", ".gitea/workflows/**.yml"],
|
"matchFileNames": [".python-version"],
|
||||||
"enabled": false
|
"enabled": false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"matchFileNames": [".python-version"],
|
"matchManagers": ["github-actions", "pre-commit"],
|
||||||
"enabled": false
|
"enabled": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"matchManagers": ["pep621"],
|
||||||
|
"rangeStrategy": "bump",
|
||||||
|
"versioning": "pep440",
|
||||||
|
"groupName": "Python dependencies"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"matchPackageNames": ["numpy", "setuptools"],
|
||||||
|
"enabled": false,
|
||||||
|
"description": "Disabled due to Python 3.10 incompatibility with numpy>=2.3.2 (requires Python>=3.11)"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
337
uv.lock
generated
@@ -304,68 +304,79 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "orjson"
|
name = "orjson"
|
||||||
version = "3.10.18"
|
version = "3.11.2"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/81/0b/fea456a3ffe74e70ba30e01ec183a9b26bec4d497f61dcfce1b601059c60/orjson-3.10.18.tar.gz", hash = "sha256:e8da3947d92123eda795b68228cafe2724815621fe35e8e320a9e9593a4bcd53", size = 5422810 }
|
sdist = { url = "https://files.pythonhosted.org/packages/df/1d/5e0ae38788bdf0721326695e65fdf41405ed535f633eb0df0f06f57552fa/orjson-3.11.2.tar.gz", hash = "sha256:91bdcf5e69a8fd8e8bdb3de32b31ff01d2bd60c1e8d5fe7d5afabdcf19920309", size = 5470739 }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/27/16/2ceb9fb7bc2b11b1e4a3ea27794256e93dee2309ebe297fd131a778cd150/orjson-3.10.18-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:a45e5d68066b408e4bc383b6e4ef05e717c65219a9e1390abc6155a520cac402", size = 248927 },
|
{ url = "https://files.pythonhosted.org/packages/a1/7b/7aebe925c6b1c46c8606a960fe1d6b681fccd4aaf3f37cd647c3309d6582/orjson-3.11.2-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:d6b8a78c33496230a60dc9487118c284c15ebdf6724386057239641e1eb69761", size = 226896 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/3d/e1/d3c0a2bba5b9906badd121da449295062b289236c39c3a7801f92c4682b0/orjson-3.10.18-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be3b9b143e8b9db05368b13b04c84d37544ec85bb97237b3a923f076265ec89c", size = 136995 },
|
{ url = "https://files.pythonhosted.org/packages/7d/39/c952c9b0d51063e808117dd1e53668a2e4325cc63cfe7df453d853ee8680/orjson-3.11.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cc04036eeae11ad4180d1f7b5faddb5dab1dee49ecd147cd431523869514873b", size = 111845 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/d7/51/698dd65e94f153ee5ecb2586c89702c9e9d12f165a63e74eb9ea1299f4e1/orjson-3.10.18-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9b0aa09745e2c9b3bf779b096fa71d1cc2d801a604ef6dd79c8b1bfef52b2f92", size = 132893 },
|
{ url = "https://files.pythonhosted.org/packages/f5/dc/90b7f29be38745eeacc30903b693f29fcc1097db0c2a19a71ffb3e9f2a5f/orjson-3.11.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9c04325839c5754c253ff301cee8aaed7442d974860a44447bb3be785c411c27", size = 116395 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/b3/e5/155ce5a2c43a85e790fcf8b985400138ce5369f24ee6770378ee6b691036/orjson-3.10.18-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:53a245c104d2792e65c8d225158f2b8262749ffe64bc7755b00024757d957a13", size = 137017 },
|
{ url = "https://files.pythonhosted.org/packages/10/c2/fe84ba63164c22932b8d59b8810e2e58590105293a259e6dd1bfaf3422c9/orjson-3.11.2-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:32769e04cd7fdc4a59854376211145a1bbbc0aea5e9d6c9755d3d3c301d7c0df", size = 118768 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/46/bb/6141ec3beac3125c0b07375aee01b5124989907d61c72c7636136e4bd03e/orjson-3.10.18-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f9495ab2611b7f8a0a8a505bcb0f0cbdb5469caafe17b0e404c3c746f9900469", size = 138290 },
|
{ url = "https://files.pythonhosted.org/packages/a9/ce/d9748ec69b1a4c29b8e2bab8233e8c41c583c69f515b373f1fb00247d8c9/orjson-3.11.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0ff285d14917ea1408a821786e3677c5261fa6095277410409c694b8e7720ae0", size = 120887 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/77/36/6961eca0b66b7809d33c4ca58c6bd4c23a1b914fb23aba2fa2883f791434/orjson-3.10.18-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:73be1cbcebadeabdbc468f82b087df435843c809cd079a565fb16f0f3b23238f", size = 142828 },
|
{ url = "https://files.pythonhosted.org/packages/c1/66/b90fac8e4a76e83f981912d7f9524d402b31f6c1b8bff3e498aa321c326c/orjson-3.11.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2662f908114864b63ff75ffe6ffacf996418dd6cc25e02a72ad4bda81b1ec45a", size = 123650 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/8b/2f/0c646d5fd689d3be94f4d83fa9435a6c4322c9b8533edbb3cd4bc8c5f69a/orjson-3.10.18-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fe8936ee2679e38903df158037a2f1c108129dee218975122e37847fb1d4ac68", size = 132806 },
|
{ url = "https://files.pythonhosted.org/packages/33/81/56143898d1689c7f915ac67703efb97e8f2f8d5805ce8c2c3fd0f2bb6e3d/orjson-3.11.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ab463cf5d08ad6623a4dac1badd20e88a5eb4b840050c4812c782e3149fe2334", size = 121287 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/ea/af/65907b40c74ef4c3674ef2bcfa311c695eb934710459841b3c2da212215c/orjson-3.10.18-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:7115fcbc8525c74e4c2b608129bef740198e9a120ae46184dac7683191042056", size = 135005 },
|
{ url = "https://files.pythonhosted.org/packages/80/de/f9c6d00c127be766a3739d0d85b52a7c941e437d8dd4d573e03e98d0f89c/orjson-3.11.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:64414241bde943cbf3c00d45fcb5223dca6d9210148ba984aae6b5d63294502b", size = 119637 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/c7/d1/68bd20ac6a32cd1f1b10d23e7cc58ee1e730e80624e3031d77067d7150fc/orjson-3.10.18-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:771474ad34c66bc4d1c01f645f150048030694ea5b2709b87d3bda273ffe505d", size = 413418 },
|
{ url = "https://files.pythonhosted.org/packages/67/4c/ab70c7627022d395c1b4eb5badf6196b7144e82b46a3a17ed2354f9e592d/orjson-3.11.2-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:7773e71c0ae8c9660192ff144a3d69df89725325e3d0b6a6bb2c50e5ebaf9b84", size = 392478 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/31/31/c701ec0bcc3e80e5cb6e319c628ef7b768aaa24b0f3b4c599df2eaacfa24/orjson-3.10.18-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:7c14047dbbea52886dd87169f21939af5d55143dad22d10db6a7514f058156a8", size = 153288 },
|
{ url = "https://files.pythonhosted.org/packages/77/91/d890b873b69311db4fae2624c5603c437df9c857fb061e97706dac550a77/orjson-3.11.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:652ca14e283b13ece35bf3a86503c25592f294dbcfc5bb91b20a9c9a62a3d4be", size = 134343 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/d9/31/5e1aa99a10893a43cfc58009f9da840990cc8a9ebb75aa452210ba18587e/orjson-3.10.18-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:641481b73baec8db14fdf58f8967e52dc8bda1f2aba3aa5f5c1b07ed6df50b7f", size = 137181 },
|
{ url = "https://files.pythonhosted.org/packages/47/16/1aa248541b4830274a079c4aeb2aa5d1ff17c3f013b1d0d8d16d0848f3de/orjson-3.11.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:26e99e98df8990ecfe3772bbdd7361f602149715c2cbc82e61af89bfad9528a4", size = 123887 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/bf/8c/daba0ac1b8690011d9242a0f37235f7d17df6d0ad941021048523b76674e/orjson-3.10.18-cp310-cp310-win32.whl", hash = "sha256:607eb3ae0909d47280c1fc657c4284c34b785bae371d007595633f4b1a2bbe06", size = 142694 },
|
{ url = "https://files.pythonhosted.org/packages/95/e4/7419833c55ac8b5f385d00c02685a260da1f391e900fc5c3e0b797e0d506/orjson-3.11.2-cp310-cp310-win32.whl", hash = "sha256:5814313b3e75a2be7fe6c7958201c16c4560e21a813dbad25920752cecd6ad66", size = 124560 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/16/62/8b687724143286b63e1d0fab3ad4214d54566d80b0ba9d67c26aaf28a2f8/orjson-3.10.18-cp310-cp310-win_amd64.whl", hash = "sha256:8770432524ce0eca50b7efc2a9a5f486ee0113a5fbb4231526d414e6254eba92", size = 134600 },
|
{ url = "https://files.pythonhosted.org/packages/74/f8/27ca7ef3e194c462af32ce1883187f5ec483650c559166f0de59c4c2c5f0/orjson-3.11.2-cp310-cp310-win_amd64.whl", hash = "sha256:dc471ce2225ab4c42ca672f70600d46a8b8e28e8d4e536088c1ccdb1d22b35ce", size = 119700 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/97/c7/c54a948ce9a4278794f669a353551ce7db4ffb656c69a6e1f2264d563e50/orjson-3.10.18-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:e0a183ac3b8e40471e8d843105da6fbe7c070faab023be3b08188ee3f85719b8", size = 248929 },
|
{ url = "https://files.pythonhosted.org/packages/78/7d/e295df1ac9920cbb19fb4c1afa800e86f175cb657143aa422337270a4782/orjson-3.11.2-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:888b64ef7eaeeff63f773881929434a5834a6a140a63ad45183d59287f07fc6a", size = 226502 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/9e/60/a9c674ef1dd8ab22b5b10f9300e7e70444d4e3cda4b8258d6c2488c32143/orjson-3.10.18-cp311-cp311-macosx_15_0_arm64.whl", hash = "sha256:5ef7c164d9174362f85238d0cd4afdeeb89d9e523e4651add6a5d458d6f7d42d", size = 133364 },
|
{ url = "https://files.pythonhosted.org/packages/65/21/ffb0f10ea04caf418fb4e7ad1fda4b9ab3179df9d7a33b69420f191aadd5/orjson-3.11.2-cp311-cp311-macosx_15_0_arm64.whl", hash = "sha256:83387cc8b26c9fa0ae34d1ea8861a7ae6cff8fb3e346ab53e987d085315a728e", size = 115999 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/c1/4e/f7d1bdd983082216e414e6d7ef897b0c2957f99c545826c06f371d52337e/orjson-3.10.18-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:afd14c5d99cdc7bf93f22b12ec3b294931518aa019e2a147e8aa2f31fd3240f7", size = 136995 },
|
{ url = "https://files.pythonhosted.org/packages/90/d5/8da1e252ac3353d92e6f754ee0c85027c8a2cda90b6899da2be0df3ef83d/orjson-3.11.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7e35f003692c216d7ee901b6b916b5734d6fc4180fcaa44c52081f974c08e17", size = 111563 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/17/89/46b9181ba0ea251c9243b0c8ce29ff7c9796fa943806a9c8b02592fce8ea/orjson-3.10.18-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7b672502323b6cd133c4af6b79e3bea36bad2d16bca6c1f645903fce83909a7a", size = 132894 },
|
{ url = "https://files.pythonhosted.org/packages/4f/81/baabc32e52c570b0e4e1044b1bd2ccbec965e0de3ba2c13082255efa2006/orjson-3.11.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4a0a4c29ae90b11d0c00bcc31533854d89f77bde2649ec602f512a7e16e00640", size = 116222 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/ca/dd/7bce6fcc5b8c21aef59ba3c67f2166f0a1a9b0317dcca4a9d5bd7934ecfd/orjson-3.10.18-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:51f8c63be6e070ec894c629186b1c0fe798662b8687f3d9fdfa5e401c6bd7679", size = 137016 },
|
{ url = "https://files.pythonhosted.org/packages/8d/b7/da2ad55ad80b49b560dce894c961477d0e76811ee6e614b301de9f2f8728/orjson-3.11.2-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:585d712b1880f68370108bc5534a257b561672d1592fae54938738fe7f6f1e33", size = 118594 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/1c/4a/b8aea1c83af805dcd31c1f03c95aabb3e19a016b2a4645dd822c5686e94d/orjson-3.10.18-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3f9478ade5313d724e0495d167083c6f3be0dd2f1c9c8a38db9a9e912cdaf947", size = 138290 },
|
{ url = "https://files.pythonhosted.org/packages/61/be/014f7eab51449f3c894aa9bbda2707b5340c85650cb7d0db4ec9ae280501/orjson-3.11.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d08e342a7143f8a7c11f1c4033efe81acbd3c98c68ba1b26b96080396019701f", size = 120700 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/36/d6/7eb05c85d987b688707f45dcf83c91abc2251e0dd9fb4f7be96514f838b1/orjson-3.10.18-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:187aefa562300a9d382b4b4eb9694806e5848b0cedf52037bb5c228c61bb66d4", size = 142829 },
|
{ url = "https://files.pythonhosted.org/packages/cf/ae/c217903a30c51341868e2d8c318c59a8413baa35af54d7845071c8ccd6fe/orjson-3.11.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:29c0f84fc50398773a702732c87cd622737bf11c0721e6db3041ac7802a686fb", size = 123433 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/d2/78/ddd3ee7873f2b5f90f016bc04062713d567435c53ecc8783aab3a4d34915/orjson-3.10.18-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9da552683bc9da222379c7a01779bddd0ad39dd699dd6300abaf43eadee38334", size = 132805 },
|
{ url = "https://files.pythonhosted.org/packages/57/c2/b3c346f78b1ff2da310dd300cb0f5d32167f872b4d3bb1ad122c889d97b0/orjson-3.11.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:140f84e3c8d4c142575898c91e3981000afebf0333df753a90b3435d349a5fe5", size = 121061 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/8c/09/c8e047f73d2c5d21ead9c180203e111cddeffc0848d5f0f974e346e21c8e/orjson-3.10.18-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e450885f7b47a0231979d9c49b567ed1c4e9f69240804621be87c40bc9d3cf17", size = 135008 },
|
{ url = "https://files.pythonhosted.org/packages/00/c8/c97798f6010327ffc75ad21dd6bca11ea2067d1910777e798c2849f1c68f/orjson-3.11.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:96304a2b7235e0f3f2d9363ddccdbfb027d27338722fe469fe656832a017602e", size = 119410 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/0c/4b/dccbf5055ef8fb6eda542ab271955fc1f9bf0b941a058490293f8811122b/orjson-3.10.18-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:5e3c9cc2ba324187cd06287ca24f65528f16dfc80add48dc99fa6c836bb3137e", size = 413419 },
|
{ url = "https://files.pythonhosted.org/packages/37/fd/df720f7c0e35694617b7f95598b11a2cb0374661d8389703bea17217da53/orjson-3.11.2-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:3d7612bb227d5d9582f1f50a60bd55c64618fc22c4a32825d233a4f2771a428a", size = 392294 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/8a/f3/1eac0c5e2d6d6790bd2025ebfbefcbd37f0d097103d76f9b3f9302af5a17/orjson-3.10.18-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:50ce016233ac4bfd843ac5471e232b865271d7d9d44cf9d33773bcd883ce442b", size = 153292 },
|
{ url = "https://files.pythonhosted.org/packages/ba/52/0120d18f60ab0fe47531d520372b528a45c9a25dcab500f450374421881c/orjson-3.11.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:a134587d18fe493befc2defffef2a8d27cfcada5696cb7234de54a21903ae89a", size = 134134 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/1f/b4/ef0abf64c8f1fabf98791819ab502c2c8c1dc48b786646533a93637d8999/orjson-3.10.18-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b3ceff74a8f7ffde0b2785ca749fc4e80e4315c0fd887561144059fb1c138aa7", size = 137182 },
|
{ url = "https://files.pythonhosted.org/packages/ec/10/1f967671966598366de42f07e92b0fc694ffc66eafa4b74131aeca84915f/orjson-3.11.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0b84455e60c4bc12c1e4cbaa5cfc1acdc7775a9da9cec040e17232f4b05458bd", size = 123745 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/a9/a3/6ea878e7b4a0dc5c888d0370d7752dcb23f402747d10e2257478d69b5e63/orjson-3.10.18-cp311-cp311-win32.whl", hash = "sha256:fdba703c722bd868c04702cac4cb8c6b8ff137af2623bc0ddb3b3e6a2c8996c1", size = 142695 },
|
{ url = "https://files.pythonhosted.org/packages/43/eb/76081238671461cfd0f47e0c24f408ffa66184237d56ef18c33e86abb612/orjson-3.11.2-cp311-cp311-win32.whl", hash = "sha256:f0660efeac223f0731a70884e6914a5f04d613b5ae500744c43f7bf7b78f00f9", size = 124393 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/79/2a/4048700a3233d562f0e90d5572a849baa18ae4e5ce4c3ba6247e4ece57b0/orjson-3.10.18-cp311-cp311-win_amd64.whl", hash = "sha256:c28082933c71ff4bc6ccc82a454a2bffcef6e1d7379756ca567c772e4fb3278a", size = 134603 },
|
{ url = "https://files.pythonhosted.org/packages/26/76/cc598c1811ba9ba935171267b02e377fc9177489efce525d478a2999d9cc/orjson-3.11.2-cp311-cp311-win_amd64.whl", hash = "sha256:955811c8405251d9e09cbe8606ad8fdef49a451bcf5520095a5ed38c669223d8", size = 119561 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/03/45/10d934535a4993d27e1c84f1810e79ccf8b1b7418cef12151a22fe9bb1e1/orjson-3.10.18-cp311-cp311-win_arm64.whl", hash = "sha256:a6c7c391beaedd3fa63206e5c2b7b554196f14debf1ec9deb54b5d279b1b46f5", size = 131400 },
|
{ url = "https://files.pythonhosted.org/packages/d8/17/c48011750f0489006f7617b0a3cebc8230f36d11a34e7e9aca2085f07792/orjson-3.11.2-cp311-cp311-win_arm64.whl", hash = "sha256:2e4d423a6f838552e3a6d9ec734b729f61f88b1124fd697eab82805ea1a2a97d", size = 114186 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/21/1a/67236da0916c1a192d5f4ccbe10ec495367a726996ceb7614eaa687112f2/orjson-3.10.18-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:50c15557afb7f6d63bc6d6348e0337a880a04eaa9cd7c9d569bcb4e760a24753", size = 249184 },
|
{ url = "https://files.pythonhosted.org/packages/40/02/46054ebe7996a8adee9640dcad7d39d76c2000dc0377efa38e55dc5cbf78/orjson-3.11.2-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:901d80d349d8452162b3aa1afb82cec5bee79a10550660bc21311cc61a4c5486", size = 226528 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/b3/bc/c7f1db3b1d094dc0c6c83ed16b161a16c214aaa77f311118a93f647b32dc/orjson-3.10.18-cp312-cp312-macosx_15_0_arm64.whl", hash = "sha256:356b076f1662c9813d5fa56db7d63ccceef4c271b1fb3dd522aca291375fcf17", size = 133279 },
|
{ url = "https://files.pythonhosted.org/packages/e2/c6/6b6f0b4d8aea1137436546b990f71be2cd8bd870aa2f5aa14dba0fcc95dc/orjson-3.11.2-cp312-cp312-macosx_15_0_arm64.whl", hash = "sha256:cf3bd3967a360e87ee14ed82cb258b7f18c710dacf3822fb0042a14313a673a1", size = 115931 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/af/84/664657cd14cc11f0d81e80e64766c7ba5c9b7fc1ec304117878cc1b4659c/orjson-3.10.18-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:559eb40a70a7494cd5beab2d73657262a74a2c59aff2068fdba8f0424ec5b39d", size = 136799 },
|
{ url = "https://files.pythonhosted.org/packages/ae/05/4205cc97c30e82a293dd0d149b1a89b138ebe76afeca66fc129fa2aa4e6a/orjson-3.11.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:26693dde66910078229a943e80eeb99fdce6cd2c26277dc80ead9f3ab97d2131", size = 111382 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/9a/bb/f50039c5bb05a7ab024ed43ba25d0319e8722a0ac3babb0807e543349978/orjson-3.10.18-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f3c29eb9a81e2fbc6fd7ddcfba3e101ba92eaff455b8d602bf7511088bbc0eae", size = 132791 },
|
{ url = "https://files.pythonhosted.org/packages/50/c7/b8a951a93caa821f9272a7c917115d825ae2e4e8768f5ddf37968ec9de01/orjson-3.11.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4ad4c8acb50a28211c33fc7ef85ddf5cb18d4636a5205fd3fa2dce0411a0e30c", size = 116271 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/93/8c/ee74709fc072c3ee219784173ddfe46f699598a1723d9d49cbc78d66df65/orjson-3.10.18-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6612787e5b0756a171c7d81ba245ef63a3533a637c335aa7fcb8e665f4a0966f", size = 137059 },
|
{ url = "https://files.pythonhosted.org/packages/17/03/1006c7f8782d5327439e26d9b0ec66500ea7b679d4bbb6b891d2834ab3ee/orjson-3.11.2-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:994181e7f1725bb5f2d481d7d228738e0743b16bf319ca85c29369c65913df14", size = 119086 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/6a/37/e6d3109ee004296c80426b5a62b47bcadd96a3deab7443e56507823588c5/orjson-3.10.18-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7ac6bd7be0dcab5b702c9d43d25e70eb456dfd2e119d512447468f6405b4a69c", size = 138359 },
|
{ url = "https://files.pythonhosted.org/packages/44/61/57d22bc31f36a93878a6f772aea76b2184102c6993dea897656a66d18c74/orjson-3.11.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dbb79a0476393c07656b69c8e763c3cc925fa8e1d9e9b7d1f626901bb5025448", size = 120724 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/4f/5d/387dafae0e4691857c62bd02839a3bf3fa648eebd26185adfac58d09f207/orjson-3.10.18-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9f72f100cee8dde70100406d5c1abba515a7df926d4ed81e20a9730c062fe9ad", size = 142853 },
|
{ url = "https://files.pythonhosted.org/packages/78/a9/4550e96b4c490c83aea697d5347b8f7eb188152cd7b5a38001055ca5b379/orjson-3.11.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:191ed27a1dddb305083d8716af413d7219f40ec1d4c9b0e977453b4db0d6fb6c", size = 123577 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/27/6f/875e8e282105350b9a5341c0222a13419758545ae32ad6e0fcf5f64d76aa/orjson-3.10.18-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9dca85398d6d093dd41dc0983cbf54ab8e6afd1c547b6b8a311643917fbf4e0c", size = 133131 },
|
{ url = "https://files.pythonhosted.org/packages/3a/86/09b8cb3ebd513d708ef0c92d36ac3eebda814c65c72137b0a82d6d688fc4/orjson-3.11.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0afb89f16f07220183fd00f5f297328ed0a68d8722ad1b0c8dcd95b12bc82804", size = 121195 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/48/b2/73a1f0b4790dcb1e5a45f058f4f5dcadc8a85d90137b50d6bbc6afd0ae50/orjson-3.10.18-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:22748de2a07fcc8781a70edb887abf801bb6142e6236123ff93d12d92db3d406", size = 134834 },
|
{ url = "https://files.pythonhosted.org/packages/37/68/7b40b39ac2c1c644d4644e706d0de6c9999764341cd85f2a9393cb387661/orjson-3.11.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6ab6e6b4e93b1573a026b6ec16fca9541354dd58e514b62c558b58554ae04307", size = 119234 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/56/f5/7ed133a5525add9c14dbdf17d011dd82206ca6840811d32ac52a35935d19/orjson-3.10.18-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:3a83c9954a4107b9acd10291b7f12a6b29e35e8d43a414799906ea10e75438e6", size = 413368 },
|
{ url = "https://files.pythonhosted.org/packages/40/7c/bb6e7267cd80c19023d44d8cbc4ea4ed5429fcd4a7eb9950f50305697a28/orjson-3.11.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:9cb23527efb61fb75527df55d20ee47989c4ee34e01a9c98ee9ede232abf6219", size = 392250 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/11/7c/439654221ed9c3324bbac7bdf94cf06a971206b7b62327f11a52544e4982/orjson-3.10.18-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:303565c67a6c7b1f194c94632a4a39918e067bd6176a48bec697393865ce4f06", size = 153359 },
|
{ url = "https://files.pythonhosted.org/packages/64/f2/6730ace05583dbca7c1b406d59f4266e48cd0d360566e71482420fb849fc/orjson-3.11.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a4dd1268e4035af21b8a09e4adf2e61f87ee7bf63b86d7bb0a237ac03fad5b45", size = 134572 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/48/e7/d58074fa0cc9dd29a8fa2a6c8d5deebdfd82c6cfef72b0e4277c4017563a/orjson-3.10.18-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:86314fdb5053a2f5a5d881f03fca0219bfdf832912aa88d18676a5175c6916b5", size = 137466 },
|
{ url = "https://files.pythonhosted.org/packages/96/0f/7d3e03a30d5aac0432882b539a65b8c02cb6dd4221ddb893babf09c424cc/orjson-3.11.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ff8b155b145eaf5a9d94d2c476fbe18d6021de93cf36c2ae2c8c5b775763f14e", size = 123869 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/57/4d/fe17581cf81fb70dfcef44e966aa4003360e4194d15a3f38cbffe873333a/orjson-3.10.18-cp312-cp312-win32.whl", hash = "sha256:187ec33bbec58c76dbd4066340067d9ece6e10067bb0cc074a21ae3300caa84e", size = 142683 },
|
{ url = "https://files.pythonhosted.org/packages/45/80/1513265eba6d4a960f078f4b1d2bff94a571ab2d28c6f9835e03dfc65cc6/orjson-3.11.2-cp312-cp312-win32.whl", hash = "sha256:ae3bb10279d57872f9aba68c9931aa71ed3b295fa880f25e68da79e79453f46e", size = 124430 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/e6/22/469f62d25ab5f0f3aee256ea732e72dc3aab6d73bac777bd6277955bceef/orjson-3.10.18-cp312-cp312-win_amd64.whl", hash = "sha256:f9f94cf6d3f9cd720d641f8399e390e7411487e493962213390d1ae45c7814fc", size = 134754 },
|
{ url = "https://files.pythonhosted.org/packages/fb/61/eadf057b68a332351eeb3d89a4cc538d14f31cd8b5ec1b31a280426ccca2/orjson-3.11.2-cp312-cp312-win_amd64.whl", hash = "sha256:d026e1967239ec11a2559b4146a61d13914504b396f74510a1c4d6b19dfd8732", size = 119598 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/10/b0/1040c447fac5b91bc1e9c004b69ee50abb0c1ffd0d24406e1350c58a7fcb/orjson-3.10.18-cp312-cp312-win_arm64.whl", hash = "sha256:3d600be83fe4514944500fa8c2a0a77099025ec6482e8087d7659e891f23058a", size = 131218 },
|
{ url = "https://files.pythonhosted.org/packages/6b/3f/7f4b783402143d965ab7e9a2fc116fdb887fe53bdce7d3523271cd106098/orjson-3.11.2-cp312-cp312-win_arm64.whl", hash = "sha256:59f8d5ad08602711af9589375be98477d70e1d102645430b5a7985fdbf613b36", size = 114052 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/04/f0/8aedb6574b68096f3be8f74c0b56d36fd94bcf47e6c7ed47a7bd1474aaa8/orjson-3.10.18-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:69c34b9441b863175cc6a01f2935de994025e773f814412030f269da4f7be147", size = 249087 },
|
{ url = "https://files.pythonhosted.org/packages/c2/f3/0dd6b4750eb556ae4e2c6a9cb3e219ec642e9c6d95f8ebe5dc9020c67204/orjson-3.11.2-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:a079fdba7062ab396380eeedb589afb81dc6683f07f528a03b6f7aae420a0219", size = 226419 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/bc/f7/7118f965541aeac6844fcb18d6988e111ac0d349c9b80cda53583e758908/orjson-3.10.18-cp313-cp313-macosx_15_0_arm64.whl", hash = "sha256:1ebeda919725f9dbdb269f59bc94f861afbe2a27dce5608cdba2d92772364d1c", size = 133273 },
|
{ url = "https://files.pythonhosted.org/packages/44/d5/e67f36277f78f2af8a4690e0c54da6b34169812f807fd1b4bfc4dbcf9558/orjson-3.11.2-cp313-cp313-macosx_15_0_arm64.whl", hash = "sha256:6a5f62ebbc530bb8bb4b1ead103647b395ba523559149b91a6c545f7cd4110ad", size = 115803 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/fb/d9/839637cc06eaf528dd8127b36004247bf56e064501f68df9ee6fd56a88ee/orjson-3.10.18-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5adf5f4eed520a4959d29ea80192fa626ab9a20b2ea13f8f6dc58644f6927103", size = 136779 },
|
{ url = "https://files.pythonhosted.org/packages/24/37/ff8bc86e0dacc48f07c2b6e20852f230bf4435611bab65e3feae2b61f0ae/orjson-3.11.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7df6c7b8b0931feb3420b72838c3e2ba98c228f7aa60d461bc050cf4ca5f7b2", size = 111337 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/2b/6d/f226ecfef31a1f0e7d6bf9a31a0bbaf384c7cbe3fce49cc9c2acc51f902a/orjson-3.10.18-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7592bb48a214e18cd670974f289520f12b7aed1fa0b2e2616b8ed9e069e08595", size = 132811 },
|
{ url = "https://files.pythonhosted.org/packages/b9/25/37d4d3e8079ea9784ea1625029988e7f4594ce50d4738b0c1e2bf4a9e201/orjson-3.11.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6f59dfea7da1fced6e782bb3699718088b1036cb361f36c6e4dd843c5111aefe", size = 116222 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/73/2d/371513d04143c85b681cf8f3bce743656eb5b640cb1f461dad750ac4b4d4/orjson-3.10.18-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f872bef9f042734110642b7a11937440797ace8c87527de25e0c53558b579ccc", size = 137018 },
|
{ url = "https://files.pythonhosted.org/packages/b7/32/a63fd9c07fce3b4193dcc1afced5dd4b0f3a24e27556604e9482b32189c9/orjson-3.11.2-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:edf49146520fef308c31aa4c45b9925fd9c7584645caca7c0c4217d7900214ae", size = 119020 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/69/cb/a4d37a30507b7a59bdc484e4a3253c8141bf756d4e13fcc1da760a0b00cb/orjson-3.10.18-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0315317601149c244cb3ecef246ef5861a64824ccbcb8018d32c66a60a84ffbc", size = 138368 },
|
{ url = "https://files.pythonhosted.org/packages/b4/b6/400792b8adc3079a6b5d649264a3224d6342436d9fac9a0ed4abc9dc4596/orjson-3.11.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:50995bbeb5d41a32ad15e023305807f561ac5dcd9bd41a12c8d8d1d2c83e44e6", size = 120721 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/1e/ae/cd10883c48d912d216d541eb3db8b2433415fde67f620afe6f311f5cd2ca/orjson-3.10.18-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e0da26957e77e9e55a6c2ce2e7182a36a6f6b180ab7189315cb0995ec362e049", size = 142840 },
|
{ url = "https://files.pythonhosted.org/packages/40/f3/31ab8f8c699eb9e65af8907889a0b7fef74c1d2b23832719a35da7bb0c58/orjson-3.11.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2cc42960515076eb639b705f105712b658c525863d89a1704d984b929b0577d1", size = 123574 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/6d/4c/2bda09855c6b5f2c055034c9eda1529967b042ff8d81a05005115c4e6772/orjson-3.10.18-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb70d489bc79b7519e5803e2cc4c72343c9dc1154258adf2f8925d0b60da7c58", size = 133135 },
|
{ url = "https://files.pythonhosted.org/packages/bd/a6/ce4287c412dff81878f38d06d2c80845709c60012ca8daf861cb064b4574/orjson-3.11.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c56777cab2a7b2a8ea687fedafb84b3d7fdafae382165c31a2adf88634c432fa", size = 121225 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/13/4a/35971fd809a8896731930a80dfff0b8ff48eeb5d8b57bb4d0d525160017f/orjson-3.10.18-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e9e86a6af31b92299b00736c89caf63816f70a4001e750bda179e15564d7a034", size = 134810 },
|
{ url = "https://files.pythonhosted.org/packages/69/b0/7a881b2aef4fed0287d2a4fbb029d01ed84fa52b4a68da82bdee5e50598e/orjson-3.11.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:07349e88025b9b5c783077bf7a9f401ffbfb07fd20e86ec6fc5b7432c28c2c5e", size = 119201 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/99/70/0fa9e6310cda98365629182486ff37a1c6578e34c33992df271a476ea1cd/orjson-3.10.18-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:c382a5c0b5931a5fc5405053d36c1ce3fd561694738626c77ae0b1dfc0242ca1", size = 413491 },
|
{ url = "https://files.pythonhosted.org/packages/cf/98/a325726b37f7512ed6338e5e65035c3c6505f4e628b09a5daf0419f054ea/orjson-3.11.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:45841fbb79c96441a8c58aa29ffef570c5df9af91f0f7a9572e5505e12412f15", size = 392193 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/32/cb/990a0e88498babddb74fb97855ae4fbd22a82960e9b06eab5775cac435da/orjson-3.10.18-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:8e4b2ae732431127171b875cb2668f883e1234711d3c147ffd69fe5be51a8012", size = 153277 },
|
{ url = "https://files.pythonhosted.org/packages/cb/4f/a7194f98b0ce1d28190e0c4caa6d091a3fc8d0107ad2209f75c8ba398984/orjson-3.11.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:13d8d8db6cd8d89d4d4e0f4161acbbb373a4d2a4929e862d1d2119de4aa324ac", size = 134548 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/92/44/473248c3305bf782a384ed50dd8bc2d3cde1543d107138fd99b707480ca1/orjson-3.10.18-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:2d808e34ddb24fc29a4d4041dcfafbae13e129c93509b847b14432717d94b44f", size = 137367 },
|
{ url = "https://files.pythonhosted.org/packages/e8/5e/b84caa2986c3f472dc56343ddb0167797a708a8d5c3be043e1e2677b55df/orjson-3.11.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:51da1ee2178ed09c00d09c1b953e45846bbc16b6420965eb7a913ba209f606d8", size = 123798 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/ad/fd/7f1d3edd4ffcd944a6a40e9f88af2197b619c931ac4d3cfba4798d4d3815/orjson-3.10.18-cp313-cp313-win32.whl", hash = "sha256:ad8eacbb5d904d5591f27dee4031e2c1db43d559edb8f91778efd642d70e6bea", size = 142687 },
|
{ url = "https://files.pythonhosted.org/packages/9c/5b/e398449080ce6b4c8fcadad57e51fa16f65768e1b142ba90b23ac5d10801/orjson-3.11.2-cp313-cp313-win32.whl", hash = "sha256:51dc033df2e4a4c91c0ba4f43247de99b3cbf42ee7a42ee2b2b2f76c8b2f2cb5", size = 124402 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/4b/03/c75c6ad46be41c16f4cfe0352a2d1450546f3c09ad2c9d341110cd87b025/orjson-3.10.18-cp313-cp313-win_amd64.whl", hash = "sha256:aed411bcb68bf62e85588f2a7e03a6082cc42e5a2796e06e72a962d7c6310b52", size = 134794 },
|
{ url = "https://files.pythonhosted.org/packages/b3/66/429e4608e124debfc4790bfc37131f6958e59510ba3b542d5fc163be8e5f/orjson-3.11.2-cp313-cp313-win_amd64.whl", hash = "sha256:29d91d74942b7436f29b5d1ed9bcfc3f6ef2d4f7c4997616509004679936650d", size = 119498 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/c2/28/f53038a5a72cc4fd0b56c1eafb4ef64aec9685460d5ac34de98ca78b6e29/orjson-3.10.18-cp313-cp313-win_arm64.whl", hash = "sha256:f54c1385a0e6aba2f15a40d703b858bedad36ded0491e55d35d905b2c34a4cc3", size = 131186 },
|
{ url = "https://files.pythonhosted.org/packages/7b/04/f8b5f317cce7ad3580a9ad12d7e2df0714dfa8a83328ecddd367af802f5b/orjson-3.11.2-cp313-cp313-win_arm64.whl", hash = "sha256:4ca4fb5ac21cd1e48028d4f708b1bb13e39c42d45614befd2ead004a8bba8535", size = 114051 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/74/83/2c363022b26c3c25b3708051a19d12f3374739bb81323f05b284392080c0/orjson-3.11.2-cp314-cp314-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:3dcba7101ea6a8d4ef060746c0f2e7aa8e2453a1012083e1ecce9726d7554cb7", size = 226406 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b0/a7/aa3c973de0b33fc93b4bd71691665ffdfeae589ea9d0625584ab10a7d0f5/orjson-3.11.2-cp314-cp314-macosx_15_0_arm64.whl", hash = "sha256:15d17bdb76a142e1f55d91913e012e6e6769659daa6bfef3ef93f11083137e81", size = 115788 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ef/f2/e45f233dfd09fdbb052ec46352363dca3906618e1a2b264959c18f809d0b/orjson-3.11.2-cp314-cp314-manylinux_2_34_aarch64.whl", hash = "sha256:53c9e81768c69d4b66b8876ec3c8e431c6e13477186d0db1089d82622bccd19f", size = 111318 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3e/23/cf5a73c4da6987204cbbf93167f353ff0c5013f7c5e5ef845d4663a366da/orjson-3.11.2-cp314-cp314-manylinux_2_34_x86_64.whl", hash = "sha256:d4f13af59a7b84c1ca6b8a7ab70d608f61f7c44f9740cd42409e6ae7b6c8d8b7", size = 121231 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/40/1d/47468a398ae68a60cc21e599144e786e035bb12829cb587299ecebc088f1/orjson-3.11.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:bde64aa469b5ee46cc960ed241fae3721d6a8801dacb2ca3466547a2535951e4", size = 119204 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/4d/d9/f99433d89b288b5bc8836bffb32a643f805e673cf840ef8bab6e73ced0d1/orjson-3.11.2-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:b5ca86300aeb383c8fa759566aca065878d3d98c3389d769b43f0a2e84d52c5f", size = 392237 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d4/dc/1b9d80d40cebef603325623405136a29fb7d08c877a728c0943dd066c29a/orjson-3.11.2-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:24e32a558ebed73a6a71c8f1cbc163a7dd5132da5270ff3d8eeb727f4b6d1bc7", size = 134578 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/45/b3/72e7a4c5b6485ef4e83ef6aba7f1dd041002bad3eb5d1d106ca5b0fc02c6/orjson-3.11.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:e36319a5d15b97e4344110517450396845cc6789aed712b1fbf83c1bd95792f6", size = 123799 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c8/3e/a3d76b392e7acf9b34dc277171aad85efd6accc75089bb35b4c614990ea9/orjson-3.11.2-cp314-cp314-win32.whl", hash = "sha256:40193ada63fab25e35703454d65b6afc71dbc65f20041cb46c6d91709141ef7f", size = 124461 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/fb/e3/75c6a596ff8df9e4a5894813ff56695f0a218e6ea99420b4a645c4f7795d/orjson-3.11.2-cp314-cp314-win_amd64.whl", hash = "sha256:7c8ac5f6b682d3494217085cf04dadae66efee45349ad4ee2a1da3c97e2305a8", size = 119494 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/5b/3d/9e74742fc261c5ca473c96bb3344d03995869e1dc6402772c60afb97736a/orjson-3.11.2-cp314-cp314-win_arm64.whl", hash = "sha256:21cf261e8e79284242e4cb1e5924df16ae28255184aafeff19be1405f6d33f67", size = 114046 },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -379,79 +390,104 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pillow"
|
name = "pillow"
|
||||||
version = "11.2.1"
|
version = "11.3.0"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/af/cb/bb5c01fcd2a69335b86c22142b2bccfc3464087efb7fd382eee5ffc7fdf7/pillow-11.2.1.tar.gz", hash = "sha256:a64dd61998416367b7ef979b73d3a85853ba9bec4c2925f74e588879a58716b6", size = 47026707 }
|
sdist = { url = "https://files.pythonhosted.org/packages/f3/0d/d0d6dea55cd152ce3d6767bb38a8fc10e33796ba4ba210cbab9354b6d238/pillow-11.3.0.tar.gz", hash = "sha256:3828ee7586cd0b2091b6209e5ad53e20d0649bbe87164a459d0676e035e8f523", size = 47113069 }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/0d/8b/b158ad57ed44d3cc54db8d68ad7c0a58b8fc0e4c7a3f995f9d62d5b464a1/pillow-11.2.1-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:d57a75d53922fc20c165016a20d9c44f73305e67c351bbc60d1adaf662e74047", size = 3198442 },
|
{ url = "https://files.pythonhosted.org/packages/4c/5d/45a3553a253ac8763f3561371432a90bdbe6000fbdcf1397ffe502aa206c/pillow-11.3.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:1b9c17fd4ace828b3003dfd1e30bff24863e0eb59b535e8f80194d9cc7ecf860", size = 5316554 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/b1/f8/bb5d956142f86c2d6cc36704943fa761f2d2e4c48b7436fd0a85c20f1713/pillow-11.2.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:127bf6ac4a5b58b3d32fc8289656f77f80567d65660bc46f72c0d77e6600cc95", size = 3030553 },
|
{ url = "https://files.pythonhosted.org/packages/7c/c8/67c12ab069ef586a25a4a79ced553586748fad100c77c0ce59bb4983ac98/pillow-11.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:65dc69160114cdd0ca0f35cb434633c75e8e7fad4cf855177a05bf38678f73ad", size = 4686548 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/22/7f/0e413bb3e2aa797b9ca2c5c38cb2e2e45d88654e5b12da91ad446964cfae/pillow-11.2.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b4ba4be812c7a40280629e55ae0b14a0aafa150dd6451297562e1764808bbe61", size = 4405503 },
|
{ url = "https://files.pythonhosted.org/packages/2f/bd/6741ebd56263390b382ae4c5de02979af7f8bd9807346d068700dd6d5cf9/pillow-11.3.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7107195ddc914f656c7fc8e4a5e1c25f32e9236ea3ea860f257b0436011fddd0", size = 5859742 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/f3/b4/cc647f4d13f3eb837d3065824aa58b9bcf10821f029dc79955ee43f793bd/pillow-11.2.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c8bd62331e5032bc396a93609982a9ab6b411c05078a52f5fe3cc59234a3abd1", size = 4490648 },
|
{ url = "https://files.pythonhosted.org/packages/ca/0b/c412a9e27e1e6a829e6ab6c2dca52dd563efbedf4c9c6aa453d9a9b77359/pillow-11.3.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:cc3e831b563b3114baac7ec2ee86819eb03caa1a2cef0b481a5675b59c4fe23b", size = 7633087 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/c2/6f/240b772a3b35cdd7384166461567aa6713799b4e78d180c555bd284844ea/pillow-11.2.1-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:562d11134c97a62fe3af29581f083033179f7ff435f78392565a1ad2d1c2c45c", size = 4508937 },
|
{ url = "https://files.pythonhosted.org/packages/59/9d/9b7076aaf30f5dd17e5e5589b2d2f5a5d7e30ff67a171eb686e4eecc2adf/pillow-11.3.0-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f1f182ebd2303acf8c380a54f615ec883322593320a9b00438eb842c1f37ae50", size = 5963350 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/f3/5e/7ca9c815ade5fdca18853db86d812f2f188212792780208bdb37a0a6aef4/pillow-11.2.1-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:c97209e85b5be259994eb5b69ff50c5d20cca0f458ef9abd835e262d9d88b39d", size = 4599802 },
|
{ url = "https://files.pythonhosted.org/packages/f0/16/1a6bf01fb622fb9cf5c91683823f073f053005c849b1f52ed613afcf8dae/pillow-11.3.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4445fa62e15936a028672fd48c4c11a66d641d2c05726c7ec1f8ba6a572036ae", size = 6631840 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/02/81/c3d9d38ce0c4878a77245d4cf2c46d45a4ad0f93000227910a46caff52f3/pillow-11.2.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0c3e6d0f59171dfa2e25d7116217543310908dfa2770aa64b8f87605f8cacc97", size = 4576717 },
|
{ url = "https://files.pythonhosted.org/packages/7b/e6/6ff7077077eb47fde78739e7d570bdcd7c10495666b6afcd23ab56b19a43/pillow-11.3.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:71f511f6b3b91dd543282477be45a033e4845a40278fa8dcdbfdb07109bf18f9", size = 6074005 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/42/49/52b719b89ac7da3185b8d29c94d0e6aec8140059e3d8adcaa46da3751180/pillow-11.2.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cc1c3bc53befb6096b84165956e886b1729634a799e9d6329a0c512ab651e579", size = 4654874 },
|
{ url = "https://files.pythonhosted.org/packages/c3/3a/b13f36832ea6d279a697231658199e0a03cd87ef12048016bdcc84131601/pillow-11.3.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:040a5b691b0713e1f6cbe222e0f4f74cd233421e105850ae3b3c0ceda520f42e", size = 6708372 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/5b/0b/ede75063ba6023798267023dc0d0401f13695d228194d2242d5a7ba2f964/pillow-11.2.1-cp310-cp310-win32.whl", hash = "sha256:312c77b7f07ab2139924d2639860e084ec2a13e72af54d4f08ac843a5fc9c79d", size = 2331717 },
|
{ url = "https://files.pythonhosted.org/packages/6c/e4/61b2e1a7528740efbc70b3d581f33937e38e98ef3d50b05007267a55bcb2/pillow-11.3.0-cp310-cp310-win32.whl", hash = "sha256:89bd777bc6624fe4115e9fac3352c79ed60f3bb18651420635f26e643e3dd1f6", size = 6277090 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/ed/3c/9831da3edea527c2ed9a09f31a2c04e77cd705847f13b69ca60269eec370/pillow-11.2.1-cp310-cp310-win_amd64.whl", hash = "sha256:9bc7ae48b8057a611e5fe9f853baa88093b9a76303937449397899385da06fad", size = 2676204 },
|
{ url = "https://files.pythonhosted.org/packages/a9/d3/60c781c83a785d6afbd6a326ed4d759d141de43aa7365725cbcd65ce5e54/pillow-11.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:19d2ff547c75b8e3ff46f4d9ef969a06c30ab2d4263a9e287733aa8b2429ce8f", size = 6985988 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/01/97/1f66ff8a1503d8cbfc5bae4dc99d54c6ec1e22ad2b946241365320caabc2/pillow-11.2.1-cp310-cp310-win_arm64.whl", hash = "sha256:2728567e249cdd939f6cc3d1f049595c66e4187f3c34078cbc0a7d21c47482d2", size = 2414767 },
|
{ url = "https://files.pythonhosted.org/packages/9f/28/4f4a0203165eefb3763939c6789ba31013a2e90adffb456610f30f613850/pillow-11.3.0-cp310-cp310-win_arm64.whl", hash = "sha256:819931d25e57b513242859ce1876c58c59dc31587847bf74cfe06b2e0cb22d2f", size = 2422899 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/68/08/3fbf4b98924c73037a8e8b4c2c774784805e0fb4ebca6c5bb60795c40125/pillow-11.2.1-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:35ca289f712ccfc699508c4658a1d14652e8033e9b69839edf83cbdd0ba39e70", size = 3198450 },
|
{ url = "https://files.pythonhosted.org/packages/db/26/77f8ed17ca4ffd60e1dcd220a6ec6d71210ba398cfa33a13a1cd614c5613/pillow-11.3.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:1cd110edf822773368b396281a2293aeb91c90a2db00d78ea43e7e861631b722", size = 5316531 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/84/92/6505b1af3d2849d5e714fc75ba9e69b7255c05ee42383a35a4d58f576b16/pillow-11.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e0409af9f829f87a2dfb7e259f78f317a5351f2045158be321fd135973fff7bf", size = 3030550 },
|
{ url = "https://files.pythonhosted.org/packages/cb/39/ee475903197ce709322a17a866892efb560f57900d9af2e55f86db51b0a5/pillow-11.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9c412fddd1b77a75aa904615ebaa6001f169b26fd467b4be93aded278266b288", size = 4686560 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/3c/8c/ac2f99d2a70ff966bc7eb13dacacfaab57c0549b2ffb351b6537c7840b12/pillow-11.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4e5c5edee874dce4f653dbe59db7c73a600119fbea8d31f53423586ee2aafd7", size = 4415018 },
|
{ url = "https://files.pythonhosted.org/packages/d5/90/442068a160fd179938ba55ec8c97050a612426fae5ec0a764e345839f76d/pillow-11.3.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7d1aa4de119a0ecac0a34a9c8bde33f34022e2e8f99104e47a3ca392fd60e37d", size = 5870978 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/1f/e3/0a58b5d838687f40891fff9cbaf8669f90c96b64dc8f91f87894413856c6/pillow-11.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b93a07e76d13bff9444f1a029e0af2964e654bfc2e2c2d46bfd080df5ad5f3d8", size = 4498006 },
|
{ url = "https://files.pythonhosted.org/packages/13/92/dcdd147ab02daf405387f0218dcf792dc6dd5b14d2573d40b4caeef01059/pillow-11.3.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:91da1d88226663594e3f6b4b8c3c8d85bd504117d043740a8e0ec449087cc494", size = 7641168 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/21/f5/6ba14718135f08fbfa33308efe027dd02b781d3f1d5c471444a395933aac/pillow-11.2.1-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:e6def7eed9e7fa90fde255afaf08060dc4b343bbe524a8f69bdd2a2f0018f600", size = 4517773 },
|
{ url = "https://files.pythonhosted.org/packages/6e/db/839d6ba7fd38b51af641aa904e2960e7a5644d60ec754c046b7d2aee00e5/pillow-11.3.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:643f189248837533073c405ec2f0bb250ba54598cf80e8c1e043381a60632f58", size = 5973053 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/20/f2/805ad600fc59ebe4f1ba6129cd3a75fb0da126975c8579b8f57abeb61e80/pillow-11.2.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:8f4f3724c068be008c08257207210c138d5f3731af6c155a81c2b09a9eb3a788", size = 4607069 },
|
{ url = "https://files.pythonhosted.org/packages/f2/2f/d7675ecae6c43e9f12aa8d58b6012683b20b6edfbdac7abcb4e6af7a3784/pillow-11.3.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:106064daa23a745510dabce1d84f29137a37224831d88eb4ce94bb187b1d7e5f", size = 6640273 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/71/6b/4ef8a288b4bb2e0180cba13ca0a519fa27aa982875882392b65131401099/pillow-11.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a0a6709b47019dff32e678bc12c63008311b82b9327613f534e496dacaefb71e", size = 4583460 },
|
{ url = "https://files.pythonhosted.org/packages/45/ad/931694675ede172e15b2ff03c8144a0ddaea1d87adb72bb07655eaffb654/pillow-11.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:cd8ff254faf15591e724dc7c4ddb6bf4793efcbe13802a4ae3e863cd300b493e", size = 6082043 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/62/ae/f29c705a09cbc9e2a456590816e5c234382ae5d32584f451c3eb41a62062/pillow-11.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f6b0c664ccb879109ee3ca702a9272d877f4fcd21e5eb63c26422fd6e415365e", size = 4661304 },
|
{ url = "https://files.pythonhosted.org/packages/3a/04/ba8f2b11fc80d2dd462d7abec16351b45ec99cbbaea4387648a44190351a/pillow-11.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:932c754c2d51ad2b2271fd01c3d121daaa35e27efae2a616f77bf164bc0b3e94", size = 6715516 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/6e/1a/c8217b6f2f73794a5e219fbad087701f412337ae6dbb956db37d69a9bc43/pillow-11.2.1-cp311-cp311-win32.whl", hash = "sha256:cc5d875d56e49f112b6def6813c4e3d3036d269c008bf8aef72cd08d20ca6df6", size = 2331809 },
|
{ url = "https://files.pythonhosted.org/packages/48/59/8cd06d7f3944cc7d892e8533c56b0acb68399f640786313275faec1e3b6f/pillow-11.3.0-cp311-cp311-win32.whl", hash = "sha256:b4b8f3efc8d530a1544e5962bd6b403d5f7fe8b9e08227c6b255f98ad82b4ba0", size = 6274768 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/e2/72/25a8f40170dc262e86e90f37cb72cb3de5e307f75bf4b02535a61afcd519/pillow-11.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:0f5c7eda47bf8e3c8a283762cab94e496ba977a420868cb819159980b6709193", size = 2676338 },
|
{ url = "https://files.pythonhosted.org/packages/f1/cc/29c0f5d64ab8eae20f3232da8f8571660aa0ab4b8f1331da5c2f5f9a938e/pillow-11.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:1a992e86b0dd7aeb1f053cd506508c0999d710a8f07b4c791c63843fc6a807ac", size = 6986055 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/06/9e/76825e39efee61efea258b479391ca77d64dbd9e5804e4ad0fa453b4ba55/pillow-11.2.1-cp311-cp311-win_arm64.whl", hash = "sha256:4d375eb838755f2528ac8cbc926c3e31cc49ca4ad0cf79cff48b20e30634a4a7", size = 2414918 },
|
{ url = "https://files.pythonhosted.org/packages/c6/df/90bd886fabd544c25addd63e5ca6932c86f2b701d5da6c7839387a076b4a/pillow-11.3.0-cp311-cp311-win_arm64.whl", hash = "sha256:30807c931ff7c095620fe04448e2c2fc673fcbb1ffe2a7da3fb39613489b1ddd", size = 2423079 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/c7/40/052610b15a1b8961f52537cc8326ca6a881408bc2bdad0d852edeb6ed33b/pillow-11.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:78afba22027b4accef10dbd5eed84425930ba41b3ea0a86fa8d20baaf19d807f", size = 3190185 },
|
{ url = "https://files.pythonhosted.org/packages/40/fe/1bc9b3ee13f68487a99ac9529968035cca2f0a51ec36892060edcc51d06a/pillow-11.3.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fdae223722da47b024b867c1ea0be64e0df702c5e0a60e27daad39bf960dd1e4", size = 5278800 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/e5/7e/b86dbd35a5f938632093dc40d1682874c33dcfe832558fc80ca56bfcb774/pillow-11.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:78092232a4ab376a35d68c4e6d5e00dfd73454bd12b230420025fbe178ee3b0b", size = 3030306 },
|
{ url = "https://files.pythonhosted.org/packages/2c/32/7e2ac19b5713657384cec55f89065fb306b06af008cfd87e572035b27119/pillow-11.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:921bd305b10e82b4d1f5e802b6850677f965d8394203d182f078873851dada69", size = 4686296 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/a4/5c/467a161f9ed53e5eab51a42923c33051bf8d1a2af4626ac04f5166e58e0c/pillow-11.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25a5f306095c6780c52e6bbb6109624b95c5b18e40aab1c3041da3e9e0cd3e2d", size = 4416121 },
|
{ url = "https://files.pythonhosted.org/packages/8e/1e/b9e12bbe6e4c2220effebc09ea0923a07a6da1e1f1bfbc8d7d29a01ce32b/pillow-11.3.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:eb76541cba2f958032d79d143b98a3a6b3ea87f0959bbe256c0b5e416599fd5d", size = 5871726 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/62/73/972b7742e38ae0e2ac76ab137ca6005dcf877480da0d9d61d93b613065b4/pillow-11.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c7b29dbd4281923a2bfe562acb734cee96bbb129e96e6972d315ed9f232bef4", size = 4501707 },
|
{ url = "https://files.pythonhosted.org/packages/8d/33/e9200d2bd7ba00dc3ddb78df1198a6e80d7669cce6c2bdbeb2530a74ec58/pillow-11.3.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:67172f2944ebba3d4a7b54f2e95c786a3a50c21b88456329314caaa28cda70f6", size = 7644652 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/e4/3a/427e4cb0b9e177efbc1a84798ed20498c4f233abde003c06d2650a6d60cb/pillow-11.2.1-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:3e645b020f3209a0181a418bffe7b4a93171eef6c4ef6cc20980b30bebf17b7d", size = 4522921 },
|
{ url = "https://files.pythonhosted.org/packages/41/f1/6f2427a26fc683e00d985bc391bdd76d8dd4e92fac33d841127eb8fb2313/pillow-11.3.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:97f07ed9f56a3b9b5f49d3661dc9607484e85c67e27f3e8be2c7d28ca032fec7", size = 5977787 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/fe/7c/d8b1330458e4d2f3f45d9508796d7caf0c0d3764c00c823d10f6f1a3b76d/pillow-11.2.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:b2dbea1012ccb784a65349f57bbc93730b96e85b42e9bf7b01ef40443db720b4", size = 4612523 },
|
{ url = "https://files.pythonhosted.org/packages/e4/c9/06dd4a38974e24f932ff5f98ea3c546ce3f8c995d3f0985f8e5ba48bba19/pillow-11.3.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:676b2815362456b5b3216b4fd5bd89d362100dc6f4945154ff172e206a22c024", size = 6645236 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/b3/2f/65738384e0b1acf451de5a573d8153fe84103772d139e1e0bdf1596be2ea/pillow-11.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:da3104c57bbd72948d75f6a9389e6727d2ab6333c3617f0a89d72d4940aa0443", size = 4587836 },
|
{ url = "https://files.pythonhosted.org/packages/40/e7/848f69fb79843b3d91241bad658e9c14f39a32f71a301bcd1d139416d1be/pillow-11.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3e184b2f26ff146363dd07bde8b711833d7b0202e27d13540bfe2e35a323a809", size = 6086950 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/6a/c5/e795c9f2ddf3debb2dedd0df889f2fe4b053308bb59a3cc02a0cd144d641/pillow-11.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:598174aef4589af795f66f9caab87ba4ff860ce08cd5bb447c6fc553ffee603c", size = 4669390 },
|
{ url = "https://files.pythonhosted.org/packages/0b/1a/7cff92e695a2a29ac1958c2a0fe4c0b2393b60aac13b04a4fe2735cad52d/pillow-11.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6be31e3fc9a621e071bc17bb7de63b85cbe0bfae91bb0363c893cbe67247780d", size = 6723358 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/96/ae/ca0099a3995976a9fce2f423166f7bff9b12244afdc7520f6ed38911539a/pillow-11.2.1-cp312-cp312-win32.whl", hash = "sha256:1d535df14716e7f8776b9e7fee118576d65572b4aad3ed639be9e4fa88a1cad3", size = 2332309 },
|
{ url = "https://files.pythonhosted.org/packages/26/7d/73699ad77895f69edff76b0f332acc3d497f22f5d75e5360f78cbcaff248/pillow-11.3.0-cp312-cp312-win32.whl", hash = "sha256:7b161756381f0918e05e7cb8a371fff367e807770f8fe92ecb20d905d0e1c149", size = 6275079 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/7c/18/24bff2ad716257fc03da964c5e8f05d9790a779a8895d6566e493ccf0189/pillow-11.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:14e33b28bf17c7a38eede290f77db7c664e4eb01f7869e37fa98a5aa95978941", size = 2676768 },
|
{ url = "https://files.pythonhosted.org/packages/8c/ce/e7dfc873bdd9828f3b6e5c2bbb74e47a98ec23cc5c74fc4e54462f0d9204/pillow-11.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:a6444696fce635783440b7f7a9fc24b3ad10a9ea3f0ab66c5905be1c19ccf17d", size = 6986324 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/da/bb/e8d656c9543276517ee40184aaa39dcb41e683bca121022f9323ae11b39d/pillow-11.2.1-cp312-cp312-win_arm64.whl", hash = "sha256:21e1470ac9e5739ff880c211fc3af01e3ae505859392bf65458c224d0bf283eb", size = 2415087 },
|
{ url = "https://files.pythonhosted.org/packages/16/8f/b13447d1bf0b1f7467ce7d86f6e6edf66c0ad7cf44cf5c87a37f9bed9936/pillow-11.3.0-cp312-cp312-win_arm64.whl", hash = "sha256:2aceea54f957dd4448264f9bf40875da0415c83eb85f55069d89c0ed436e3542", size = 2423067 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/36/9c/447528ee3776e7ab8897fe33697a7ff3f0475bb490c5ac1456a03dc57956/pillow-11.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:fdec757fea0b793056419bca3e9932eb2b0ceec90ef4813ea4c1e072c389eb28", size = 3190098 },
|
{ url = "https://files.pythonhosted.org/packages/1e/93/0952f2ed8db3a5a4c7a11f91965d6184ebc8cd7cbb7941a260d5f018cd2d/pillow-11.3.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:1c627742b539bba4309df89171356fcb3cc5a9178355b2727d1b74a6cf155fbd", size = 2128328 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/b5/09/29d5cd052f7566a63e5b506fac9c60526e9ecc553825551333e1e18a4858/pillow-11.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:b0e130705d568e2f43a17bcbe74d90958e8a16263868a12c3e0d9c8162690830", size = 3030166 },
|
{ url = "https://files.pythonhosted.org/packages/4b/e8/100c3d114b1a0bf4042f27e0f87d2f25e857e838034e98ca98fe7b8c0a9c/pillow-11.3.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:30b7c02f3899d10f13d7a48163c8969e4e653f8b43416d23d13d1bbfdc93b9f8", size = 2170652 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/71/5d/446ee132ad35e7600652133f9c2840b4799bbd8e4adba881284860da0a36/pillow-11.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7bdb5e09068332578214cadd9c05e3d64d99e0e87591be22a324bdbc18925be0", size = 4408674 },
|
{ url = "https://files.pythonhosted.org/packages/aa/86/3f758a28a6e381758545f7cdb4942e1cb79abd271bea932998fc0db93cb6/pillow-11.3.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:7859a4cc7c9295f5838015d8cc0a9c215b77e43d07a25e460f35cf516df8626f", size = 2227443 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/69/5f/cbe509c0ddf91cc3a03bbacf40e5c2339c4912d16458fcb797bb47bcb269/pillow-11.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d189ba1bebfbc0c0e529159631ec72bb9e9bc041f01ec6d3233d6d82eb823bc1", size = 4496005 },
|
{ url = "https://files.pythonhosted.org/packages/01/f4/91d5b3ffa718df2f53b0dc109877993e511f4fd055d7e9508682e8aba092/pillow-11.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ec1ee50470b0d050984394423d96325b744d55c701a439d2bd66089bff963d3c", size = 5278474 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/f9/b3/dd4338d8fb8a5f312021f2977fb8198a1184893f9b00b02b75d565c33b51/pillow-11.2.1-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:191955c55d8a712fab8934a42bfefbf99dd0b5875078240943f913bb66d46d9f", size = 4518707 },
|
{ url = "https://files.pythonhosted.org/packages/f9/0e/37d7d3eca6c879fbd9dba21268427dffda1ab00d4eb05b32923d4fbe3b12/pillow-11.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7db51d222548ccfd274e4572fdbf3e810a5e66b00608862f947b163e613b67dd", size = 4686038 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/13/eb/2552ecebc0b887f539111c2cd241f538b8ff5891b8903dfe672e997529be/pillow-11.2.1-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:ad275964d52e2243430472fc5d2c2334b4fc3ff9c16cb0a19254e25efa03a155", size = 4610008 },
|
{ url = "https://files.pythonhosted.org/packages/ff/b0/3426e5c7f6565e752d81221af9d3676fdbb4f352317ceafd42899aaf5d8a/pillow-11.3.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:2d6fcc902a24ac74495df63faad1884282239265c6839a0a6416d33faedfae7e", size = 5864407 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/72/d1/924ce51bea494cb6e7959522d69d7b1c7e74f6821d84c63c3dc430cbbf3b/pillow-11.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:750f96efe0597382660d8b53e90dd1dd44568a8edb51cb7f9d5d918b80d4de14", size = 4585420 },
|
{ url = "https://files.pythonhosted.org/packages/fc/c1/c6c423134229f2a221ee53f838d4be9d82bab86f7e2f8e75e47b6bf6cd77/pillow-11.3.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f0f5d8f4a08090c6d6d578351a2b91acf519a54986c055af27e7a93feae6d3f1", size = 7639094 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/43/ab/8f81312d255d713b99ca37479a4cb4b0f48195e530cdc1611990eb8fd04b/pillow-11.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fe15238d3798788d00716637b3d4e7bb6bde18b26e5d08335a96e88564a36b6b", size = 4667655 },
|
{ url = "https://files.pythonhosted.org/packages/ba/c9/09e6746630fe6372c67c648ff9deae52a2bc20897d51fa293571977ceb5d/pillow-11.3.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c37d8ba9411d6003bba9e518db0db0c58a680ab9fe5179f040b0463644bc9805", size = 5973503 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/94/86/8f2e9d2dc3d308dfd137a07fe1cc478df0a23d42a6c4093b087e738e4827/pillow-11.2.1-cp313-cp313-win32.whl", hash = "sha256:3fe735ced9a607fee4f481423a9c36701a39719252a9bb251679635f99d0f7d2", size = 2332329 },
|
{ url = "https://files.pythonhosted.org/packages/d5/1c/a2a29649c0b1983d3ef57ee87a66487fdeb45132df66ab30dd37f7dbe162/pillow-11.3.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:13f87d581e71d9189ab21fe0efb5a23e9f28552d5be6979e84001d3b8505abe8", size = 6642574 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/6d/ec/1179083b8d6067a613e4d595359b5fdea65d0a3b7ad623fee906e1b3c4d2/pillow-11.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:74ee3d7ecb3f3c05459ba95eed5efa28d6092d751ce9bf20e3e253a4e497e691", size = 2676388 },
|
{ url = "https://files.pythonhosted.org/packages/36/de/d5cc31cc4b055b6c6fd990e3e7f0f8aaf36229a2698501bcb0cdf67c7146/pillow-11.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:023f6d2d11784a465f09fd09a34b150ea4672e85fb3d05931d89f373ab14abb2", size = 6084060 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/23/f1/2fc1e1e294de897df39fa8622d829b8828ddad938b0eaea256d65b84dd72/pillow-11.2.1-cp313-cp313-win_arm64.whl", hash = "sha256:5119225c622403afb4b44bad4c1ca6c1f98eed79db8d3bc6e4e160fc6339d66c", size = 2414950 },
|
{ url = "https://files.pythonhosted.org/packages/d5/ea/502d938cbaeec836ac28a9b730193716f0114c41325db428e6b280513f09/pillow-11.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:45dfc51ac5975b938e9809451c51734124e73b04d0f0ac621649821a63852e7b", size = 6721407 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/c4/3e/c328c48b3f0ead7bab765a84b4977acb29f101d10e4ef57a5e3400447c03/pillow-11.2.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:8ce2e8411c7aaef53e6bb29fe98f28cd4fbd9a1d9be2eeea434331aac0536b22", size = 3192759 },
|
{ url = "https://files.pythonhosted.org/packages/45/9c/9c5e2a73f125f6cbc59cc7087c8f2d649a7ae453f83bd0362ff7c9e2aee2/pillow-11.3.0-cp313-cp313-win32.whl", hash = "sha256:a4d336baed65d50d37b88ca5b60c0fa9d81e3a87d4a7930d3880d1624d5b31f3", size = 6273841 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/18/0e/1c68532d833fc8b9f404d3a642991441d9058eccd5606eab31617f29b6d4/pillow-11.2.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:9ee66787e095127116d91dea2143db65c7bb1e232f617aa5957c0d9d2a3f23a7", size = 3033284 },
|
{ url = "https://files.pythonhosted.org/packages/23/85/397c73524e0cd212067e0c969aa245b01d50183439550d24d9f55781b776/pillow-11.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:0bce5c4fd0921f99d2e858dc4d4d64193407e1b99478bc5cacecba2311abde51", size = 6978450 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/b7/cb/6faf3fb1e7705fd2db74e070f3bf6f88693601b0ed8e81049a8266de4754/pillow-11.2.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9622e3b6c1d8b551b6e6f21873bdcc55762b4b2126633014cea1803368a9aa16", size = 4445826 },
|
{ url = "https://files.pythonhosted.org/packages/17/d2/622f4547f69cd173955194b78e4d19ca4935a1b0f03a302d655c9f6aae65/pillow-11.3.0-cp313-cp313-win_arm64.whl", hash = "sha256:1904e1264881f682f02b7f8167935cce37bc97db457f8e7849dc3a6a52b99580", size = 2423055 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/07/94/8be03d50b70ca47fb434a358919d6a8d6580f282bbb7af7e4aa40103461d/pillow-11.2.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:63b5dff3a68f371ea06025a1a6966c9a1e1ee452fc8020c2cd0ea41b83e9037b", size = 4527329 },
|
{ url = "https://files.pythonhosted.org/packages/dd/80/a8a2ac21dda2e82480852978416cfacd439a4b490a501a288ecf4fe2532d/pillow-11.3.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:4c834a3921375c48ee6b9624061076bc0a32a60b5532b322cc0ea64e639dd50e", size = 5281110 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/fd/a4/bfe78777076dc405e3bd2080bc32da5ab3945b5a25dc5d8acaa9de64a162/pillow-11.2.1-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:31df6e2d3d8fc99f993fd253e97fae451a8db2e7207acf97859732273e108406", size = 4549049 },
|
{ url = "https://files.pythonhosted.org/packages/44/d6/b79754ca790f315918732e18f82a8146d33bcd7f4494380457ea89eb883d/pillow-11.3.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5e05688ccef30ea69b9317a9ead994b93975104a677a36a8ed8106be9260aa6d", size = 4689547 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/65/4d/eaf9068dc687c24979e977ce5677e253624bd8b616b286f543f0c1b91662/pillow-11.2.1-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:062b7a42d672c45a70fa1f8b43d1d38ff76b63421cbbe7f88146b39e8a558d91", size = 4635408 },
|
{ url = "https://files.pythonhosted.org/packages/49/20/716b8717d331150cb00f7fdd78169c01e8e0c219732a78b0e59b6bdb2fd6/pillow-11.3.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:1019b04af07fc0163e2810167918cb5add8d74674b6267616021ab558dc98ced", size = 5901554 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/1d/26/0fd443365d9c63bc79feb219f97d935cd4b93af28353cba78d8e77b61719/pillow-11.2.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4eb92eca2711ef8be42fd3f67533765d9fd043b8c80db204f16c8ea62ee1a751", size = 4614863 },
|
{ url = "https://files.pythonhosted.org/packages/74/cf/a9f3a2514a65bb071075063a96f0a5cf949c2f2fce683c15ccc83b1c1cab/pillow-11.3.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f944255db153ebb2b19c51fe85dd99ef0ce494123f21b9db4877ffdfc5590c7c", size = 7669132 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/49/65/dca4d2506be482c2c6641cacdba5c602bc76d8ceb618fd37de855653a419/pillow-11.2.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:f91ebf30830a48c825590aede79376cb40f110b387c17ee9bd59932c961044f9", size = 4692938 },
|
{ url = "https://files.pythonhosted.org/packages/98/3c/da78805cbdbee9cb43efe8261dd7cc0b4b93f2ac79b676c03159e9db2187/pillow-11.3.0-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1f85acb69adf2aaee8b7da124efebbdb959a104db34d3a2cb0f3793dbae422a8", size = 6005001 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/b3/92/1ca0c3f09233bd7decf8f7105a1c4e3162fb9142128c74adad0fb361b7eb/pillow-11.2.1-cp313-cp313t-win32.whl", hash = "sha256:e0b55f27f584ed623221cfe995c912c61606be8513bfa0e07d2c674b4516d9dd", size = 2335774 },
|
{ url = "https://files.pythonhosted.org/packages/6c/fa/ce044b91faecf30e635321351bba32bab5a7e034c60187fe9698191aef4f/pillow-11.3.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:05f6ecbeff5005399bb48d198f098a9b4b6bdf27b8487c7f38ca16eeb070cd59", size = 6668814 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/a5/ac/77525347cb43b83ae905ffe257bbe2cc6fd23acb9796639a1f56aa59d191/pillow-11.2.1-cp313-cp313t-win_amd64.whl", hash = "sha256:36d6b82164c39ce5482f649b437382c0fb2395eabc1e2b1702a6deb8ad647d6e", size = 2681895 },
|
{ url = "https://files.pythonhosted.org/packages/7b/51/90f9291406d09bf93686434f9183aba27b831c10c87746ff49f127ee80cb/pillow-11.3.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:a7bc6e6fd0395bc052f16b1a8670859964dbd7003bd0af2ff08342eb6e442cfe", size = 6113124 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/67/32/32dc030cfa91ca0fc52baebbba2e009bb001122a1daa8b6a79ad830b38d3/pillow-11.2.1-cp313-cp313t-win_arm64.whl", hash = "sha256:225c832a13326e34f212d2072982bb1adb210e0cc0b153e688743018c94a2681", size = 2417234 },
|
{ url = "https://files.pythonhosted.org/packages/cd/5a/6fec59b1dfb619234f7636d4157d11fb4e196caeee220232a8d2ec48488d/pillow-11.3.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:83e1b0161c9d148125083a35c1c5a89db5b7054834fd4387499e06552035236c", size = 6747186 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/33/49/c8c21e4255b4f4a2c0c68ac18125d7f5460b109acc6dfdef1a24f9b960ef/pillow-11.2.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:9b7b0d4fd2635f54ad82785d56bc0d94f147096493a79985d0ab57aedd563156", size = 3181727 },
|
{ url = "https://files.pythonhosted.org/packages/49/6b/00187a044f98255225f172de653941e61da37104a9ea60e4f6887717e2b5/pillow-11.3.0-cp313-cp313t-win32.whl", hash = "sha256:2a3117c06b8fb646639dce83694f2f9eac405472713fcb1ae887469c0d4f6788", size = 6277546 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/6d/f1/f7255c0838f8c1ef6d55b625cfb286835c17e8136ce4351c5577d02c443b/pillow-11.2.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:aa442755e31c64037aa7c1cb186e0b369f8416c567381852c63444dd666fb772", size = 2999833 },
|
{ url = "https://files.pythonhosted.org/packages/e8/5c/6caaba7e261c0d75bab23be79f1d06b5ad2a2ae49f028ccec801b0e853d6/pillow-11.3.0-cp313-cp313t-win_amd64.whl", hash = "sha256:857844335c95bea93fb39e0fa2726b4d9d758850b34075a7e3ff4f4fa3aa3b31", size = 6985102 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/e2/57/9968114457bd131063da98d87790d080366218f64fa2943b65ac6739abb3/pillow-11.2.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f0d3348c95b766f54b76116d53d4cb171b52992a1027e7ca50c81b43b9d9e363", size = 3437472 },
|
{ url = "https://files.pythonhosted.org/packages/f3/7e/b623008460c09a0cb38263c93b828c666493caee2eb34ff67f778b87e58c/pillow-11.3.0-cp313-cp313t-win_arm64.whl", hash = "sha256:8797edc41f3e8536ae4b10897ee2f637235c94f27404cac7297f7b607dd0716e", size = 2424803 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/b2/1b/e35d8a158e21372ecc48aac9c453518cfe23907bb82f950d6e1c72811eb0/pillow-11.2.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85d27ea4c889342f7e35f6d56e7e1cb345632ad592e8c51b693d7b7556043ce0", size = 3459976 },
|
{ url = "https://files.pythonhosted.org/packages/73/f4/04905af42837292ed86cb1b1dabe03dce1edc008ef14c473c5c7e1443c5d/pillow-11.3.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:d9da3df5f9ea2a89b81bb6087177fb1f4d1c7146d583a3fe5c672c0d94e55e12", size = 5278520 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/26/da/2c11d03b765efff0ccc473f1c4186dc2770110464f2177efaed9cf6fae01/pillow-11.2.1-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:bf2c33d6791c598142f00c9c4c7d47f6476731c31081331664eb26d6ab583e01", size = 3527133 },
|
{ url = "https://files.pythonhosted.org/packages/41/b0/33d79e377a336247df6348a54e6d2a2b85d644ca202555e3faa0cf811ecc/pillow-11.3.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:0b275ff9b04df7b640c59ec5a3cb113eefd3795a8df80bac69646ef699c6981a", size = 4686116 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/79/1a/4e85bd7cadf78412c2a3069249a09c32ef3323650fd3005c97cca7aa21df/pillow-11.2.1-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:e616e7154c37669fc1dfc14584f11e284e05d1c650e1c0f972f281c4ccc53193", size = 3571555 },
|
{ url = "https://files.pythonhosted.org/packages/49/2d/ed8bc0ab219ae8768f529597d9509d184fe8a6c4741a6864fea334d25f3f/pillow-11.3.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0743841cabd3dba6a83f38a92672cccbd69af56e3e91777b0ee7f4dba4385632", size = 5864597 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/69/03/239939915216de1e95e0ce2334bf17a7870ae185eb390fab6d706aadbfc0/pillow-11.2.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:39ad2e0f424394e3aebc40168845fee52df1394a4673a6ee512d840d14ab3013", size = 2674713 },
|
{ url = "https://files.pythonhosted.org/packages/b5/3d/b932bb4225c80b58dfadaca9d42d08d0b7064d2d1791b6a237f87f661834/pillow-11.3.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2465a69cf967b8b49ee1b96d76718cd98c4e925414ead59fdf75cf0fd07df673", size = 7638246 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/a4/ad/2613c04633c7257d9481ab21d6b5364b59fc5d75faafd7cb8693523945a3/pillow-11.2.1-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:80f1df8dbe9572b4b7abdfa17eb5d78dd620b1d55d9e25f834efdbee872d3aed", size = 3181734 },
|
{ url = "https://files.pythonhosted.org/packages/09/b5/0487044b7c096f1b48f0d7ad416472c02e0e4bf6919541b111efd3cae690/pillow-11.3.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:41742638139424703b4d01665b807c6468e23e699e8e90cffefe291c5832b027", size = 5973336 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/a4/fd/dcdda4471ed667de57bb5405bb42d751e6cfdd4011a12c248b455c778e03/pillow-11.2.1-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:ea926cfbc3957090becbcbbb65ad177161a2ff2ad578b5a6ec9bb1e1cd78753c", size = 2999841 },
|
{ url = "https://files.pythonhosted.org/packages/a8/2d/524f9318f6cbfcc79fbc004801ea6b607ec3f843977652fdee4857a7568b/pillow-11.3.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:93efb0b4de7e340d99057415c749175e24c8864302369e05914682ba642e5d77", size = 6642699 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/ac/89/8a2536e95e77432833f0db6fd72a8d310c8e4272a04461fb833eb021bf94/pillow-11.2.1-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:738db0e0941ca0376804d4de6a782c005245264edaa253ffce24e5a15cbdc7bd", size = 3437470 },
|
{ url = "https://files.pythonhosted.org/packages/6f/d2/a9a4f280c6aefedce1e8f615baaa5474e0701d86dd6f1dede66726462bbd/pillow-11.3.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7966e38dcd0fa11ca390aed7c6f20454443581d758242023cf36fcb319b1a874", size = 6083789 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/9d/8f/abd47b73c60712f88e9eda32baced7bfc3e9bd6a7619bb64b93acff28c3e/pillow-11.2.1-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9db98ab6565c69082ec9b0d4e40dd9f6181dab0dd236d26f7a50b8b9bfbd5076", size = 3460013 },
|
{ url = "https://files.pythonhosted.org/packages/fe/54/86b0cd9dbb683a9d5e960b66c7379e821a19be4ac5810e2e5a715c09a0c0/pillow-11.3.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:98a9afa7b9007c67ed84c57c9e0ad86a6000da96eaa638e4f8abe5b65ff83f0a", size = 6720386 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/f6/20/5c0a0aa83b213b7a07ec01e71a3d6ea2cf4ad1d2c686cc0168173b6089e7/pillow-11.2.1-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:036e53f4170e270ddb8797d4c590e6dd14d28e15c7da375c18978045f7e6c37b", size = 3527165 },
|
{ url = "https://files.pythonhosted.org/packages/e7/95/88efcaf384c3588e24259c4203b909cbe3e3c2d887af9e938c2022c9dd48/pillow-11.3.0-cp314-cp314-win32.whl", hash = "sha256:02a723e6bf909e7cea0dac1b0e0310be9d7650cd66222a5f1c571455c0a45214", size = 6370911 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/58/0e/2abab98a72202d91146abc839e10c14f7cf36166f12838ea0c4db3ca6ecb/pillow-11.2.1-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:14f73f7c291279bd65fda51ee87affd7c1e097709f7fdd0188957a16c264601f", size = 3571586 },
|
{ url = "https://files.pythonhosted.org/packages/2e/cc/934e5820850ec5eb107e7b1a72dd278140731c669f396110ebc326f2a503/pillow-11.3.0-cp314-cp314-win_amd64.whl", hash = "sha256:a418486160228f64dd9e9efcd132679b7a02a5f22c982c78b6fc7dab3fefb635", size = 7117383 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/21/2c/5e05f58658cf49b6667762cca03d6e7d85cededde2caf2ab37b81f80e574/pillow-11.2.1-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:208653868d5c9ecc2b327f9b9ef34e0e42a4cdd172c2988fd81d62d2bc9bc044", size = 2674751 },
|
{ url = "https://files.pythonhosted.org/packages/d6/e9/9c0a616a71da2a5d163aa37405e8aced9a906d574b4a214bede134e731bc/pillow-11.3.0-cp314-cp314-win_arm64.whl", hash = "sha256:155658efb5e044669c08896c0c44231c5e9abcaadbc5cd3648df2f7c0b96b9a6", size = 2511385 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/1a/33/c88376898aff369658b225262cd4f2659b13e8178e7534df9e6e1fa289f6/pillow-11.3.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:59a03cdf019efbfeeed910bf79c7c93255c3d54bc45898ac2a4140071b02b4ae", size = 5281129 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/1f/70/d376247fb36f1844b42910911c83a02d5544ebd2a8bad9efcc0f707ea774/pillow-11.3.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:f8a5827f84d973d8636e9dc5764af4f0cf2318d26744b3d902931701b0d46653", size = 4689580 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/eb/1c/537e930496149fbac69efd2fc4329035bbe2e5475b4165439e3be9cb183b/pillow-11.3.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ee92f2fd10f4adc4b43d07ec5e779932b4eb3dbfbc34790ada5a6669bc095aa6", size = 5902860 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/bd/57/80f53264954dcefeebcf9dae6e3eb1daea1b488f0be8b8fef12f79a3eb10/pillow-11.3.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c96d333dcf42d01f47b37e0979b6bd73ec91eae18614864622d9b87bbd5bbf36", size = 7670694 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/70/ff/4727d3b71a8578b4587d9c276e90efad2d6fe0335fd76742a6da08132e8c/pillow-11.3.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4c96f993ab8c98460cd0c001447bff6194403e8b1d7e149ade5f00594918128b", size = 6005888 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/05/ae/716592277934f85d3be51d7256f3636672d7b1abfafdc42cf3f8cbd4b4c8/pillow-11.3.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:41342b64afeba938edb034d122b2dda5db2139b9a4af999729ba8818e0056477", size = 6670330 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e7/bb/7fe6cddcc8827b01b1a9766f5fdeb7418680744f9082035bdbabecf1d57f/pillow-11.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:068d9c39a2d1b358eb9f245ce7ab1b5c3246c7c8c7d9ba58cfa5b43146c06e50", size = 6114089 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/8b/f5/06bfaa444c8e80f1a8e4bff98da9c83b37b5be3b1deaa43d27a0db37ef84/pillow-11.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:a1bc6ba083b145187f648b667e05a2534ecc4b9f2784c2cbe3089e44868f2b9b", size = 6748206 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f0/77/bc6f92a3e8e6e46c0ca78abfffec0037845800ea38c73483760362804c41/pillow-11.3.0-cp314-cp314t-win32.whl", hash = "sha256:118ca10c0d60b06d006be10a501fd6bbdfef559251ed31b794668ed569c87e12", size = 6377370 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/4a/82/3a721f7d69dca802befb8af08b7c79ebcab461007ce1c18bd91a5d5896f9/pillow-11.3.0-cp314-cp314t-win_amd64.whl", hash = "sha256:8924748b688aa210d79883357d102cd64690e56b923a186f35a82cbc10f997db", size = 7121500 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/89/c7/5572fa4a3f45740eaab6ae86fcdf7195b55beac1371ac8c619d880cfe948/pillow-11.3.0-cp314-cp314t-win_arm64.whl", hash = "sha256:79ea0d14d3ebad43ec77ad5272e6ff9bba5b679ef73375ea760261207fa8e0aa", size = 2512835 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/6f/8b/209bd6b62ce8367f47e68a218bffac88888fdf2c9fcf1ecadc6c3ec1ebc7/pillow-11.3.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:3cee80663f29e3843b68199b9d6f4f54bd1d4a6b59bdd91bceefc51238bcb967", size = 5270556 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2e/e6/231a0b76070c2cfd9e260a7a5b504fb72da0a95279410fa7afd99d9751d6/pillow-11.3.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:b5f56c3f344f2ccaf0dd875d3e180f631dc60a51b314295a3e681fe8cf851fbe", size = 4654625 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/13/f4/10cf94fda33cb12765f2397fc285fa6d8eb9c29de7f3185165b702fc7386/pillow-11.3.0-pp310-pypy310_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:e67d793d180c9df62f1f40aee3accca4829d3794c95098887edc18af4b8b780c", size = 4874207 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/72/c9/583821097dc691880c92892e8e2d41fe0a5a3d6021f4963371d2f6d57250/pillow-11.3.0-pp310-pypy310_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d000f46e2917c705e9fb93a3606ee4a819d1e3aa7a9b442f6444f07e77cf5e25", size = 6583939 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3b/8e/5c9d410f9217b12320efc7c413e72693f48468979a013ad17fd690397b9a/pillow-11.3.0-pp310-pypy310_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:527b37216b6ac3a12d7838dc3bd75208ec57c1c6d11ef01902266a5a0c14fc27", size = 4957166 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/62/bb/78347dbe13219991877ffb3a91bf09da8317fbfcd4b5f9140aeae020ad71/pillow-11.3.0-pp310-pypy310_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:be5463ac478b623b9dd3937afd7fb7ab3d79dd290a28e2b6df292dc75063eb8a", size = 5581482 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d9/28/1000353d5e61498aaeaaf7f1e4b49ddb05f2c6575f9d4f9f914a3538b6e1/pillow-11.3.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:8dc70ca24c110503e16918a658b869019126ecfe03109b754c402daff12b3d9f", size = 6984596 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/9e/e3/6fa84033758276fb31da12e5fb66ad747ae83b93c67af17f8c6ff4cc8f34/pillow-11.3.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7c8ec7a017ad1bd562f93dbd8505763e688d388cde6e4a010ae1486916e713e6", size = 5270566 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/5b/ee/e8d2e1ab4892970b561e1ba96cbd59c0d28cf66737fc44abb2aec3795a4e/pillow-11.3.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:9ab6ae226de48019caa8074894544af5b53a117ccb9d3b3dcb2871464c829438", size = 4654618 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f2/6d/17f80f4e1f0761f02160fc433abd4109fa1548dcfdca46cfdadaf9efa565/pillow-11.3.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:fe27fb049cdcca11f11a7bfda64043c37b30e6b91f10cb5bab275806c32f6ab3", size = 4874248 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/de/5f/c22340acd61cef960130585bbe2120e2fd8434c214802f07e8c03596b17e/pillow-11.3.0-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:465b9e8844e3c3519a983d58b80be3f668e2a7a5db97f2784e7079fbc9f9822c", size = 6583963 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/31/5e/03966aedfbfcbb4d5f8aa042452d3361f325b963ebbadddac05b122e47dd/pillow-11.3.0-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5418b53c0d59b3824d05e029669efa023bbef0f3e92e75ec8428f3799487f361", size = 4957170 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/cc/2d/e082982aacc927fc2cab48e1e731bdb1643a1406acace8bed0900a61464e/pillow-11.3.0-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:504b6f59505f08ae014f724b6207ff6222662aab5cc9542577fb084ed0676ac7", size = 5581505 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/34/e7/ae39f538fd6844e982063c3a5e4598b8ced43b9633baa3a85ef33af8c05c/pillow-11.3.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:c84d689db21a1c397d001aa08241044aa2069e7587b398c8cc63020390b1c1b8", size = 6984598 },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -482,6 +518,7 @@ dependencies = [
|
|||||||
{ name = "requests" },
|
{ name = "requests" },
|
||||||
{ name = "tqdm" },
|
{ name = "tqdm" },
|
||||||
{ name = "vdf" },
|
{ name = "vdf" },
|
||||||
|
{ name = "websocket-client" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dev-dependencies]
|
[package.dev-dependencies]
|
||||||
@@ -495,29 +532,30 @@ dev = [
|
|||||||
requires-dist = [
|
requires-dist = [
|
||||||
{ name = "babel", specifier = ">=2.17.0" },
|
{ name = "babel", specifier = ">=2.17.0" },
|
||||||
{ name = "beautifulsoup4", specifier = ">=4.13.4" },
|
{ name = "beautifulsoup4", specifier = ">=4.13.4" },
|
||||||
{ name = "evdev", specifier = ">=1.9.1" },
|
{ name = "evdev", specifier = ">=1.9.2" },
|
||||||
{ name = "icoextract", specifier = ">=0.1.6" },
|
{ name = "icoextract", specifier = ">=0.2.0" },
|
||||||
{ name = "numpy", specifier = ">=2.2.4" },
|
{ name = "numpy", specifier = ">=2.2.4" },
|
||||||
{ name = "orjson", specifier = ">=3.10.16" },
|
{ name = "orjson", specifier = ">=3.11.2" },
|
||||||
{ name = "pillow", specifier = ">=11.2.1" },
|
{ name = "pillow", specifier = ">=11.3.0" },
|
||||||
{ name = "psutil", specifier = ">=7.0.0" },
|
{ name = "psutil", specifier = ">=7.0.0" },
|
||||||
{ name = "pyside6", specifier = ">=6.9.0" },
|
{ name = "pyside6", specifier = ">=6.9.1" },
|
||||||
{ name = "pyudev", specifier = ">=0.24.3" },
|
{ name = "pyudev", specifier = ">=0.24.3" },
|
||||||
{ name = "requests", specifier = ">=2.32.3" },
|
{ name = "requests", specifier = ">=2.32.4" },
|
||||||
{ name = "tqdm", specifier = ">=4.67.1" },
|
{ name = "tqdm", specifier = ">=4.67.1" },
|
||||||
{ name = "vdf", specifier = ">=3.4" },
|
{ name = "vdf", specifier = ">=3.4" },
|
||||||
|
{ name = "websocket-client", specifier = ">=1.8.0" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.metadata.requires-dev]
|
[package.metadata.requires-dev]
|
||||||
dev = [
|
dev = [
|
||||||
{ name = "pre-commit", specifier = ">=4.2.0" },
|
{ name = "pre-commit", specifier = ">=4.3.0" },
|
||||||
{ name = "pyaspeller", specifier = ">=2.0.2" },
|
{ name = "pyaspeller", specifier = ">=2.0.2" },
|
||||||
{ name = "pyright", specifier = ">=1.1.400" },
|
{ name = "pyright", specifier = ">=1.1.403" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pre-commit"
|
name = "pre-commit"
|
||||||
version = "4.2.0"
|
version = "4.3.0"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "cfgv" },
|
{ name = "cfgv" },
|
||||||
@@ -526,9 +564,9 @@ dependencies = [
|
|||||||
{ name = "pyyaml" },
|
{ name = "pyyaml" },
|
||||||
{ name = "virtualenv" },
|
{ name = "virtualenv" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/08/39/679ca9b26c7bb2999ff122d50faa301e49af82ca9c066ec061cfbc0c6784/pre_commit-4.2.0.tar.gz", hash = "sha256:601283b9757afd87d40c4c4a9b2b5de9637a8ea02eaff7adc2d0fb4e04841146", size = 193424 }
|
sdist = { url = "https://files.pythonhosted.org/packages/ff/29/7cf5bbc236333876e4b41f56e06857a87937ce4bf91e117a6991a2dbb02a/pre_commit-4.3.0.tar.gz", hash = "sha256:499fe450cc9d42e9d58e606262795ecb64dd05438943c62b66f6a8673da30b16", size = 193792 }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/88/74/a88bf1b1efeae488a0c0b7bdf71429c313722d1fc0f377537fbe554e6180/pre_commit-4.2.0-py2.py3-none-any.whl", hash = "sha256:a009ca7205f1eb497d10b845e52c838a98b6cdd2102a6c8e4540e94ee75c58bd", size = 220707 },
|
{ url = "https://files.pythonhosted.org/packages/5b/a5/987a405322d78a73b66e39e4a90e4ef156fd7141bf71df987e50717c321b/pre_commit-4.3.0-py2.py3-none-any.whl", hash = "sha256:2b0747ad7e6e967169136edffee14c16e148a778a54e4f967921aa1ebf2308d8", size = 220965 },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -560,15 +598,15 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pyright"
|
name = "pyright"
|
||||||
version = "1.1.402"
|
version = "1.1.403"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "nodeenv" },
|
{ name = "nodeenv" },
|
||||||
{ name = "typing-extensions" },
|
{ name = "typing-extensions" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/aa/04/ce0c132d00e20f2d2fb3b3e7c125264ca8b909e693841210534b1ea1752f/pyright-1.1.402.tar.gz", hash = "sha256:85a33c2d40cd4439c66aa946fd4ce71ab2f3f5b8c22ce36a623f59ac22937683", size = 3888207 }
|
sdist = { url = "https://files.pythonhosted.org/packages/fe/f6/35f885264ff08c960b23d1542038d8da86971c5d8c955cfab195a4f672d7/pyright-1.1.403.tar.gz", hash = "sha256:3ab69b9f41c67fb5bbb4d7a36243256f0d549ed3608678d381d5f51863921104", size = 3913526 }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/fe/37/1a1c62d955e82adae588be8e374c7f77b165b6cb4203f7d581269959abbc/pyright-1.1.402-py3-none-any.whl", hash = "sha256:2c721f11869baac1884e846232800fe021c33f1b4acb3929cff321f7ea4e2982", size = 5624004 },
|
{ url = "https://files.pythonhosted.org/packages/49/b6/b04e5c2f41a5ccad74a1a4759da41adb20b4bc9d59a5e08d29ba60084d07/pyright-1.1.403-py3-none-any.whl", hash = "sha256:c0eeca5aa76cbef3fcc271259bbd785753c7ad7bcac99a9162b4c4c7daed23b3", size = 5684504 },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -760,3 +798,12 @@ sdist = { url = "https://files.pythonhosted.org/packages/56/2c/444f465fb2c65f40c
|
|||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/f3/40/b1c265d4b2b62b58576588510fc4d1fe60a86319c8de99fd8e9fec617d2c/virtualenv-20.31.2-py3-none-any.whl", hash = "sha256:36efd0d9650ee985f0cad72065001e66d49a6f24eb44d98980f630686243cf11", size = 6057982 },
|
{ url = "https://files.pythonhosted.org/packages/f3/40/b1c265d4b2b62b58576588510fc4d1fe60a86319c8de99fd8e9fec617d2c/virtualenv-20.31.2-py3-none-any.whl", hash = "sha256:36efd0d9650ee985f0cad72065001e66d49a6f24eb44d98980f630686243cf11", size = 6057982 },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "websocket-client"
|
||||||
|
version = "1.8.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/e6/30/fba0d96b4b5fbf5948ed3f4681f7da2f9f64512e1d303f94b4cc174c24a5/websocket_client-1.8.0.tar.gz", hash = "sha256:3239df9f44da632f96012472805d40a23281a991027ce11d2f45a6f24ac4c3da", size = 54648 }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/5a/84/44687a29792a70e111c5c477230a72c4b957d88d16141199bf9acb7537a3/websocket_client-1.8.0-py3-none-any.whl", hash = "sha256:17b44cc997f5c498e809b22cdf2d9c7a9e71c02c8cc2b6c56e7c2d1239bfa526", size = 58826 },
|
||||||
|
]
|
||||||
|