Compare commits

..

36 Commits

Author SHA1 Message Date
Wiktor Zykubek
522ba01275
Increment patch version 2023-07-16 16:29:40 +02:00
Wiktor Zykubek
338c18ae92
Move icons to subclass (object) __icons 2023-07-16 16:20:48 +02:00
Wiktor Zykubek
1fc5660c31
Convert method names to snake_case
PEP8 rules
2023-07-16 15:50:43 +02:00
Wiktor Zykubek
79b270794e
Remove parent argument from MainWindow's constructor 2023-07-16 15:48:30 +02:00
Wiktor Zykubek
2df7bdc5dc
Fix displaying icons 2023-07-16 15:46:55 +02:00
Wiktor Zykubek
7c3830b8ab
Convert PySide names to snake_case with __feature__
https://doc.qt.io/qtforpython-6/developer/feature-motivation.html#the-snake-case-feature
2023-07-16 15:44:47 +02:00
Wiktor Zykubek
9d679ae20e
Display station name in window title 2023-07-11 18:38:44 +02:00
Wiktor Zykubek
8e1cdb76f0
Display error message when network is down 2023-07-11 18:27:45 +02:00
Wiktor Zykubek
85be796276
Remember previous volume after muting
#2
2023-07-11 17:53:51 +02:00
Wiktor Zykubek
1a95171bb0
Set volumeHorizontalSlider position on init 2023-07-11 16:24:53 +02:00
Wiktor Zykubek
6a08d45677
Format .py files with isort 2023-07-11 16:06:05 +02:00
Wiktor Zykubek
1e149f9993
Add isort as dev dependency 2023-07-11 15:29:17 +02:00
Wiktor Zykubek
d72d8c751d
Update .gitignore and format __main__.py 2023-07-11 15:16:40 +02:00
Wiktor Zykubek
866f57569a
Fix building on Windows 2023-07-10 20:18:25 +02:00
Wiktor Zykubek
92cfe6fa51
Format code with yapf 2023-07-10 17:04:47 +02:00
Wiktor Zykubek
27bb48b97c
Add yapf as dev dependency 2023-07-10 17:04:32 +02:00
Wiktor Zykubek
fcc610e2d0
Update pyproject.toml 2023-07-10 14:54:42 +02:00
Wiktor Zykubek
14ece7390a
Increment patch version 2023-07-10 02:16:53 +02:00
Wiktor Zykubek
4a1242c92e
Update README.md 2023-07-10 02:15:42 +02:00
Wiktor Zykubek
fe0cc065aa
Move ui/ to assets/ui 2023-07-10 02:10:52 +02:00
Wiktor Zykubek
16c35d1010
Move icons to assets/icons 2023-07-10 02:08:31 +02:00
Wiktor Zykubek
6f7bca792d
Rename .ui files 2023-07-10 02:01:43 +02:00
Wiktor Zykubek
5b20136717
Untrack .pyproject 2023-07-10 01:38:16 +02:00
Wiktor Zykubek
1f805f638a
Add poetry.lock
https://python-poetry.org/docs/basic-usage/#committing-your-poetrylock-file-to-version-control
2023-07-10 01:33:22 +02:00
Wiktor Zykubek
e4ff91e9ec
Specify Python version range 2023-07-10 01:30:06 +02:00
Wiktor Zykubek
3f477fb62b
Update prebuild.py 2023-07-10 01:29:19 +02:00
Wiktor Zykubek
72cf937826
Create directory for .ui files 2023-07-10 01:29:02 +02:00
Wiktor Zykubek
80c04fa73b
Update issue templates 2023-07-09 02:41:18 +02:00
Wiktor Zykubek
dd94992bda
Update README.md 2023-07-09 01:51:35 +02:00
Wiktor Zykubek
ba7d6bf57d
Update .gitignore 2023-07-09 00:30:20 +02:00
Wiktor Zykubek
826b2fea2b
Add LICENSE 2023-07-09 00:30:20 +02:00
Wiktor Zykubek
d6f5a84f0d
Add png version of icon 2023-07-09 00:30:20 +02:00
Wiktor Zykubek
1b1a66dbd0
Update version 2023-07-08 21:24:43 +02:00
Wiktor Zykubek
003233ba8d
Update README.md 2023-07-08 20:27:36 +02:00
Wiktor Zykubek
1eb60a64ed
Update pyproject.toml and abort using pyinstaller 2023-07-08 20:24:53 +02:00
Wiktor Zykubek
eb86628f6e
Improve building methods 2023-07-08 20:20:56 +02:00
18 changed files with 576 additions and 322 deletions

23
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@ -0,0 +1,23 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: bug
assignees: ''
---
## Description
...
## Additional information
...
## Steps to reproduce
1. ...
2. ...
...
## Setup information
+ Version: ...
+ Installation method: ...

View File

@ -0,0 +1,14 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: enhancement
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.

10
.gitignore vendored
View File

@ -35,6 +35,9 @@ Thumbs.db
/.qmake.cache
/.qmake.stash
ui_form.py
*.pyproject*
# qtcreator generated files
*.pro.user*
CMakeLists.txt.user*
@ -64,8 +67,13 @@ CMakeLists.txt.user*
*.Debug
*.Release
# Python byte code
# Python
__pycache__/
*.pyc
dist/*
build/*
ui_*.py
.ropeproject/
# Binaries
# --------

7
LICENSE Normal file
View File

@ -0,0 +1,7 @@
ISC License
Copyright 2023 Wiktor Zykubek
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

View File

@ -1,51 +0,0 @@
# -*- mode: python ; coding: utf-8 -*-
block_cipher = None
a = Analysis(
['main.py'],
pathex=[],
binaries=[('icon.ico', '.')],
datas=[],
hiddenimports=[],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False,
)
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
exe = EXE(
pyz,
a.scripts,
[],
exclude_binaries=True,
name='Open-FM',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
console=False,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
icon=['icon.ico'],
)
coll = COLLECT(
exe,
a.binaries,
a.zipfiles,
a.datas,
strip=False,
upx=True,
upx_exclude=[],
name='Open-FM',
)

View File

@ -2,19 +2,41 @@
Qt client for Polish internet radio Open FM.
## Releases
To download latest version go to [releases](https://github.com/wzykubek/openfm-qt/releases).
## GNU/Linux packages
### Arch Linux
Official package is available in AUR as [openfm-qt](https://aur.archlinux.org/packages/openfm-qt).
## Build binary (Linux/Windows)
```shell
$ python3 build.py
Install it using `yay` or other AUR helper.
```bash
$ yay -S openfm-qt
```
Executable will be available in `dist/Open-FM` directory.
## Releases
To download latest version go to [releases](https://github.com/wzykubek/openfm-qt/releases).
> **_NOTE:_** Releases are currently suspended. You can download working one portable version for Windows or any Linux distro, but not the latest. Currently my main goal is to maintain AUR package and soon `.deb` and `.rpm` packages.
## Run (Linux/Windows)
```shell
$ python3 main.py
## Python package
You can manually install app as Python package using `pip`. Go to root project directory and use following command.
```bash
$ python -m pip install .
```
Alternatively use `pipx` to install app in virtual environment.
```bash
$ pipx install .
```
> **_NOTE:_** This option won't create desktop entry.
## Development
Use `poetry` tool to manage project dependencies and virtual environments.
```bash
$ poetry install # in root project directory
```
Run application.
```bash
$ poetry run openfm-qt
```
## Screenshots

View File

Before

Width:  |  Height:  |  Size: 252 KiB

After

Width:  |  Height:  |  Size: 252 KiB

BIN
assets/icons/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

@ -6,19 +6,19 @@
<rect>
<x>0</x>
<y>0</y>
<width>650</width>
<width>350</width>
<height>500</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>650</width>
<width>350</width>
<height>500</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>650</width>
<width>350</width>
<height>500</height>
</size>
</property>
@ -33,7 +33,7 @@
</property>
<property name="windowIcon">
<iconset>
<normaloff>icon.ico</normaloff>icon.ico</iconset>
<normaloff>../assets/icons/icon.png</normaloff>../assets/icons/icon.png</iconset>
</property>
<property name="locale">
<locale language="Polish" country="Poland"/>
@ -44,7 +44,7 @@
<rect>
<x>9</x>
<y>9</y>
<width>631</width>
<width>332</width>
<height>461</height>
</rect>
</property>
@ -52,85 +52,19 @@
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QTabWidget" name="tabWidget">
<widget class="QListWidget" name="groupsListWidget">
<property name="minimumSize">
<size>
<width>200</width>
<width>130</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>200</width>
<width>130</width>
<height>16777215</height>
</size>
</property>
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="radioTab">
<attribute name="title">
<string>Radio</string>
</attribute>
<widget class="QListWidget" name="radioGroupsListWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>200</width>
<height>400</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>200</width>
<height>400</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>200</width>
<height>400</height>
</size>
</property>
</widget>
</widget>
<widget class="QWidget" name="podcastTab">
<attribute name="title">
<string>Podcasty</string>
</attribute>
<widget class="QWidget" name="verticalLayoutWidget_2">
<property name="geometry">
<rect>
<x>-1</x>
<y>-1</y>
<width>201</width>
<height>401</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QListWidget" name="podcastGroupsListWidget"/>
</item>
<item>
<widget class="QListWidget" name="podcastListWidget">
<property name="minimumSize">
<size>
<width>0</width>
<height>195</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>195</height>
</size>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
</widget>
</item>
<item>
@ -147,13 +81,6 @@
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="stopToolButton">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
<item>
<widget class="Line" name="line">
<property name="lineWidth">
@ -172,18 +99,6 @@
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>120</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>120</width>
<height>16777215</height>
</size>
</property>
<property name="value">
<number>70</number>
</property>
@ -209,8 +124,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>650</width>
<height>22</height>
<width>350</width>
<height>20</height>
</rect>
</property>
</widget>

View File

@ -1,7 +0,0 @@
# This Python file uses the following encoding: utf-8
import PyInstaller.__main__
import os
os.system("pyside6-uic form.ui -o ui_form.py")
PyInstaller.__main__.run(['Open-FM.spec'])

View File

@ -1,3 +0,0 @@
{
"files": ["build.py","openfm_qt/__init__.py","form.ui","main.py","Open-FM.spec","pyproject.toml","openfm_qt/mainwindow.py","icon.ico","README.md","screenshot_linux.png"]
}

View File

@ -1,5 +1,9 @@
# This Python file uses the following encoding: utf-8
# coding=utf-8
API_URL = "https://open.fm/radio/api/v2/ofm/stations_slug.json"
DEFAULT_VOLUME = 70
from .mainwindow import MainWindow
from .ui_main_window import Ui_MainWindow # nopep8: E402 isort: skip
from .mainwindow import MainWindow # nopep8: E402 isort: skip
__all__ = [Ui_MainWindow, MainWindow]

View File

@ -1,11 +1,18 @@
# This Python file uses the following encoding: utf-8
# coding=utf-8
from PySide6.QtWidgets import QApplication
from openfm_qt import MainWindow
import sys
if __name__ == "__main__":
from PySide6.QtWidgets import QApplication
from . import MainWindow
def main():
app = QApplication(sys.argv)
widget = MainWindow()
widget.show()
sys.exit(app.exec())
if __name__ == "__main__":
main()

View File

@ -1,198 +1,135 @@
# This Python file uses the following encoding: utf-8
# coding=utf-8
from PySide6.QtCore import QUrl
from PySide6.QtWidgets import QMainWindow, QMessageBox, QStyle
from PySide6.QtMultimedia import QMediaPlayer, QAudioOutput
# Important:
# You need to run the following command to generate the ui_form.py file
# pyside6-uic form.ui -o ui_form.py, or
# pyside2-uic form.ui -o ui_form.py
from ui_form import Ui_MainWindow
import json
import requests
from . import DEFAULT_VOLUME
from PySide6.QtCore import QUrl
from PySide6.QtMultimedia import QAudioOutput, QMediaPlayer
from PySide6.QtWidgets import QMainWindow, QMessageBox, QStyle
from . import API_URL, DEFAULT_VOLUME, Ui_MainWindow
from __feature__ import snake_case, true_property # isort: skip
class MainWindow(QMainWindow):
"""MainWindow Class."""
def __init__(self, parent=None):
def __init__(self):
"""Initialize UI, audio player and handlers."""
super().__init__(parent)
super().__init__()
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
volume_icon = self.style().standardIcon(QStyle.SP_MediaVolume)
playback_icon = self.style().standardIcon(QStyle.SP_MediaPlay)
stop_icon = self.style().standardIcon(QStyle.SP_MediaStop)
self.ui.volumeToolButton.setIcon(volume_icon)
self.ui.playbackToolButton.setIcon(playback_icon)
self.ui.stopToolButton.setIcon(stop_icon)
self.__stations = self.getData(
"https://open.fm/radio/api/v2/ofm/stations_slug.json"
)
self.__podcasts_groups = self.getData(
"https://open.fm/api/podcasts/categories"
)
class __icons(object):
volume = self.style().standard_icon(QStyle.SP_MediaVolume)
muted = self.style().standard_icon(QStyle.SP_MediaVolumeMuted)
play = self.style().standard_icon(QStyle.SP_MediaPlay)
stop = self.style().standard_icon(QStyle.SP_MediaStop)
self.__icons = __icons
self.ui.volumeToolButton.icon = self.__icons.volume
self.ui.playbackToolButton.icon = self.__icons.play
self.__stations_data = self.get_stations_data()
self.__player = QMediaPlayer()
self.__audio = QAudioOutput()
self.__player.setAudioOutput(self.__audio)
self.setVolume(DEFAULT_VOLUME)
self.printRadioGroups()
self.printPodcastGroups()
self.__player.audio_output = self.__audio
self.print_groups()
self.ui.radioGroupsListWidget.itemClicked.connect(self.printRadioStations)
self.ui.podcastGroupsListWidget.itemClicked.connect(self.printPodcasts)
self.ui.podcastListWidget.itemClicked.connect(self.printPodcastEpisodes)
self.ui.stationsListWidget.itemClicked.connect(self.playRadio)
self.ui.playbackToolButton.clicked.connect(self.togglePlayer)
self.ui.stopToolButton.clicked.connect(self.stopPlayer)
self.ui.volumeHorizontalSlider.valueChanged.connect(self.setVolume)
self.ui.volumeToolButton.clicked.connect(self.toggleMute)
self.set_volume(DEFAULT_VOLUME)
self.ui.volumeHorizontalSlider.value = DEFAULT_VOLUME
def getData(self, url) -> dict:
self.ui.groupsListWidget.itemClicked.connect(self.print_stations)
self.ui.stationsListWidget.itemClicked.connect(self.play_radio)
self.ui.playbackToolButton.clicked.connect(self.toggle_player)
self.ui.volumeHorizontalSlider.valueChanged.connect(self.set_volume)
self.ui.volumeToolButton.clicked.connect(self.toggle_mute)
def get_stations_data(self) -> dict:
"""Get JSON data from API and convert it to dict."""
resp = requests.get(url)
if resp.status_code not in range(200, 299 + 1):
try:
resp = requests.get(API_URL)
if resp.status_code not in range(200, 299 + 1):
raise requests.exceptions.ConnectionError()
else:
return json.loads(resp.text)
except requests.exceptions.ConnectionError:
error_box = QMessageBox.critical(
self,
"Błąd",
f"Błąd połączenia o kodzie: {resp.status_code}",
"Brak połączenia z serwerem.",
QMessageBox.Cancel,
)
error_box.exec()
else:
return json.loads(resp.text)
def printRadioGroups(self) -> None:
"""Print groups (categories) in radioGroupsListWidget."""
self.ui.stationsListWidget.clear()
self.ui.radioGroupsListWidget.addItems(
[e["name"] for e in self.__stations["groups"]]
)
def print_groups(self) -> None:
"""Print groups (categories) in groupsListWidget."""
self.ui.groupsListWidget.add_items(
[e["name"] for e in self.__stations_data["groups"]])
def printPodcastGroups(self) -> None:
"""Print groups (categories) in podcastGroupsListWidget."""
self.ui.stationsListWidget.clear()
self.ui.podcastGroupsListWidget.addItems(
[e["name"] for e in self.__podcasts_groups]
)
def printRadioStations(self) -> None:
def print_stations(self) -> None:
"""Print stations (channels) in stationsListWidget."""
group = self.ui.radioGroupsListWidget.selectedItems()[0].text()
group = self.ui.groupsListWidget.selected_items()[0].text()
group_id = None
for e in self.__stations["groups"]:
for e in self.__stations_data["groups"]:
if e["name"] == group:
group_id = e["id"]
self.ui.stationsListWidget.clear()
self.ui.stationsListWidget.addItems(
[
e["name"]
for e in self.__stations["channels"]
if e["group_id"] == group_id
]
)
self.ui.stationsListWidget.add_items([
e["name"] for e in self.__stations_data["channels"]
if e["group_id"] == group_id
])
def printPodcasts(self) -> None:
"""Print podcasts in podcastListWidget."""
self.ui.stationsListWidget.clear()
group = self.ui.podcastGroupsListWidget.selectedItems()[0].text()
group_name = None
for e in self.__podcasts_groups:
if e["name"] == group:
group_name = e["slug"]
self.__podcasts = self.getData(
f"https://open.fm/api/podcasts/category/{group_name}"
)["podcasts"]["content"]
self.ui.podcastListWidget.clear()
self.ui.podcastListWidget.addItems(
[e["title"] for e in self.__podcasts]
)
def printPodcastEpisodes(self) -> None:
"""Print podcast episodes in stationsListWidget."""
podcast_name = self.ui.podcastListWidget.selectedItems()[0].text()
podcast_id = None
for e in self.__podcasts:
if e["title"] == podcast_name:
podcast_id = e["id"]
self.__podcast_episodes = self.getData(
f"https://open.fm/api/podcast/{podcast_id}/episodes?size=999"
)
self.ui.stationsListWidget.clear()
self.ui.stationsListWidget.addItems(
[e["title"] for e in self.__podcast_episodes["content"]]
)
def setVolume(self, volume: int = None) -> None:
def set_volume(self, volume: int = None) -> None:
"""Set playback volume to given number or slider value."""
if not volume:
volume = self.ui.volumeHorizontalSlider.value()
self.__audio.setVolume(volume / 100)
volume = self.ui.volumeHorizontalSlider.value
self.__audio.volume = volume / 100
def toggleMute(self) -> None:
def toggle_mute(self) -> None:
"""Toggle playback volume between 0 and DEFAULT_VOLUME."""
if self.ui.volumeHorizontalSlider.value() == 0:
self.ui.volumeHorizontalSlider.setValue(DEFAULT_VOLUME)
icon = self.style().standardIcon(QStyle.SP_MediaVolume)
self.setVolume(DEFAULT_VOLUME)
if self.ui.volumeHorizontalSlider.value == 0:
self.ui.volumeHorizontalSlider.value = self.previous_volume
icon = self.__icons.volume
self.set_volume(self.previous_volume)
else:
self.ui.volumeHorizontalSlider.setValue(0)
icon = self.style().standardIcon(QStyle.SP_MediaVolumeMuted)
self.setVolume(0)
self.previous_volume = self.__audio.volume * 100
self.ui.volumeHorizontalSlider.value = 0
icon = self.__icons.muted
self.set_volume(0)
self.ui.volumeToolButton.setIcon(icon)
self.ui.volumeToolButton.icon = icon
def playRadio(self) -> None:
def play_radio(self) -> None:
"""Play station selected by user."""
selection = self.ui.stationsListWidget.selectedItems()[0].text()
station = self.ui.stationsListWidget.selected_items()[0].text()
stream_url = None
for e in self.__stations["channels"]:
if e["name"] == selection:
for e in self.__stations_data["channels"]:
if e["name"] == station:
stream_url = f"http://stream.open.fm/{e['id']}"
if not stream_url:
for e in self.__podcast_episodes["content"]:
if e["title"] == selection:
stream_url = e["file"].replace("https", "http")
self.__player.source = QUrl(stream_url)
self.window_title = f"Open FM - {station}"
self.__player.setSource(QUrl(stream_url))
self.__fix_playback()
def __fix_playback(self) -> None:
"""Fix playack."""
# For some reason if you want to change the station for the first time,
# you need to stop and resume playback.
# Required to avoid crashing. For some reason if you want to change
# the station for the first time, you need to stop and resume playback.
# If you won't, application would crash.
self.__player.play()
self.__player.stop()
self.__player.play()
icon = self.style().standardIcon(QStyle.SP_MediaPause)
self.ui.playbackToolButton.setIcon(icon)
for _ in range(3):
self.toggle_player()
def togglePlayer(self) -> None:
"""Toggle playback (play/pause)."""
def toggle_player(self) -> None:
"""Toggle playback (play/stop)."""
pb_state = QMediaPlayer.PlaybackState
if self.__player.playbackState() == pb_state.PlayingState:
self.__player.pause()
icon = self.style().standardIcon(QStyle.SP_MediaPlay)
elif self.__player.playbackState() in [
pb_state.PausedState,
pb_state.StoppedState
]:
if self.__player.playback_state == pb_state.PlayingState:
self.__player.stop()
icon = self.__icons.play
elif self.__player.playback_state == pb_state.StoppedState:
self.__player.play()
icon = self.style().standardIcon(QStyle.SP_MediaPause)
icon = self.__icons.stop
else:
pass
self.ui.playbackToolButton.setIcon(icon)
def stopPlayer(self) -> None:
self.__player.stop()
icon = self.style().standardIcon(QStyle.SP_MediaPlay)
self.ui.playbackToolButton.setIcon(icon)
self.ui.playbackToolButton.icon = icon

315
poetry.lock generated Normal file
View File

@ -0,0 +1,315 @@
# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand.
[[package]]
name = "certifi"
version = "2023.5.7"
description = "Python package for providing Mozilla's CA Bundle."
optional = false
python-versions = ">=3.6"
files = [
{file = "certifi-2023.5.7-py3-none-any.whl", hash = "sha256:c6c2e98f5c7869efca1f8916fed228dd91539f9f1b444c314c06eef02980c716"},
{file = "certifi-2023.5.7.tar.gz", hash = "sha256:0f0d56dc5a6ad56fd4ba36484d6cc34451e1c6548c61daad8c320169f91eddc7"},
]
[[package]]
name = "charset-normalizer"
version = "3.2.0"
description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
optional = false
python-versions = ">=3.7.0"
files = [
{file = "charset-normalizer-3.2.0.tar.gz", hash = "sha256:3bb3d25a8e6c0aedd251753a79ae98a093c7e7b471faa3aa9a93a81431987ace"},
{file = "charset_normalizer-3.2.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0b87549028f680ca955556e3bd57013ab47474c3124dc069faa0b6545b6c9710"},
{file = "charset_normalizer-3.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7c70087bfee18a42b4040bb9ec1ca15a08242cf5867c58726530bdf3945672ed"},
{file = "charset_normalizer-3.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a103b3a7069b62f5d4890ae1b8f0597618f628b286b03d4bc9195230b154bfa9"},
{file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:94aea8eff76ee6d1cdacb07dd2123a68283cb5569e0250feab1240058f53b623"},
{file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:db901e2ac34c931d73054d9797383d0f8009991e723dab15109740a63e7f902a"},
{file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b0dac0ff919ba34d4df1b6131f59ce95b08b9065233446be7e459f95554c0dc8"},
{file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:193cbc708ea3aca45e7221ae58f0fd63f933753a9bfb498a3b474878f12caaad"},
{file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:09393e1b2a9461950b1c9a45d5fd251dc7c6f228acab64da1c9c0165d9c7765c"},
{file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:baacc6aee0b2ef6f3d308e197b5d7a81c0e70b06beae1f1fcacffdbd124fe0e3"},
{file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:bf420121d4c8dce6b889f0e8e4ec0ca34b7f40186203f06a946fa0276ba54029"},
{file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:c04a46716adde8d927adb9457bbe39cf473e1e2c2f5d0a16ceb837e5d841ad4f"},
{file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:aaf63899c94de41fe3cf934601b0f7ccb6b428c6e4eeb80da72c58eab077b19a"},
{file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d62e51710986674142526ab9f78663ca2b0726066ae26b78b22e0f5e571238dd"},
{file = "charset_normalizer-3.2.0-cp310-cp310-win32.whl", hash = "sha256:04e57ab9fbf9607b77f7d057974694b4f6b142da9ed4a199859d9d4d5c63fe96"},
{file = "charset_normalizer-3.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:48021783bdf96e3d6de03a6e39a1171ed5bd7e8bb93fc84cc649d11490f87cea"},
{file = "charset_normalizer-3.2.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:4957669ef390f0e6719db3613ab3a7631e68424604a7b448f079bee145da6e09"},
{file = "charset_normalizer-3.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:46fb8c61d794b78ec7134a715a3e564aafc8f6b5e338417cb19fe9f57a5a9bf2"},
{file = "charset_normalizer-3.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f779d3ad205f108d14e99bb3859aa7dd8e9c68874617c72354d7ecaec2a054ac"},
{file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f25c229a6ba38a35ae6e25ca1264621cc25d4d38dca2942a7fce0b67a4efe918"},
{file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2efb1bd13885392adfda4614c33d3b68dee4921fd0ac1d3988f8cbb7d589e72a"},
{file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f30b48dd7fa1474554b0b0f3fdfdd4c13b5c737a3c6284d3cdc424ec0ffff3a"},
{file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:246de67b99b6851627d945db38147d1b209a899311b1305dd84916f2b88526c6"},
{file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9bd9b3b31adcb054116447ea22caa61a285d92e94d710aa5ec97992ff5eb7cf3"},
{file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:8c2f5e83493748286002f9369f3e6607c565a6a90425a3a1fef5ae32a36d749d"},
{file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:3170c9399da12c9dc66366e9d14da8bf7147e1e9d9ea566067bbce7bb74bd9c2"},
{file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:7a4826ad2bd6b07ca615c74ab91f32f6c96d08f6fcc3902ceeedaec8cdc3bcd6"},
{file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:3b1613dd5aee995ec6d4c69f00378bbd07614702a315a2cf6c1d21461fe17c23"},
{file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9e608aafdb55eb9f255034709e20d5a83b6d60c054df0802fa9c9883d0a937aa"},
{file = "charset_normalizer-3.2.0-cp311-cp311-win32.whl", hash = "sha256:f2a1d0fd4242bd8643ce6f98927cf9c04540af6efa92323e9d3124f57727bfc1"},
{file = "charset_normalizer-3.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:681eb3d7e02e3c3655d1b16059fbfb605ac464c834a0c629048a30fad2b27489"},
{file = "charset_normalizer-3.2.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c57921cda3a80d0f2b8aec7e25c8aa14479ea92b5b51b6876d975d925a2ea346"},
{file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41b25eaa7d15909cf3ac4c96088c1f266a9a93ec44f87f1d13d4a0e86c81b982"},
{file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f058f6963fd82eb143c692cecdc89e075fa0828db2e5b291070485390b2f1c9c"},
{file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a7647ebdfb9682b7bb97e2a5e7cb6ae735b1c25008a70b906aecca294ee96cf4"},
{file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eef9df1eefada2c09a5e7a40991b9fc6ac6ef20b1372abd48d2794a316dc0449"},
{file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e03b8895a6990c9ab2cdcd0f2fe44088ca1c65ae592b8f795c3294af00a461c3"},
{file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:ee4006268ed33370957f55bf2e6f4d263eaf4dc3cfc473d1d90baff6ed36ce4a"},
{file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c4983bf937209c57240cff65906b18bb35e64ae872da6a0db937d7b4af845dd7"},
{file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:3bb7fda7260735efe66d5107fb7e6af6a7c04c7fce9b2514e04b7a74b06bf5dd"},
{file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:72814c01533f51d68702802d74f77ea026b5ec52793c791e2da806a3844a46c3"},
{file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:70c610f6cbe4b9fce272c407dd9d07e33e6bf7b4aa1b7ffb6f6ded8e634e3592"},
{file = "charset_normalizer-3.2.0-cp37-cp37m-win32.whl", hash = "sha256:a401b4598e5d3f4a9a811f3daf42ee2291790c7f9d74b18d75d6e21dda98a1a1"},
{file = "charset_normalizer-3.2.0-cp37-cp37m-win_amd64.whl", hash = "sha256:c0b21078a4b56965e2b12f247467b234734491897e99c1d51cee628da9786959"},
{file = "charset_normalizer-3.2.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:95eb302ff792e12aba9a8b8f8474ab229a83c103d74a750ec0bd1c1eea32e669"},
{file = "charset_normalizer-3.2.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1a100c6d595a7f316f1b6f01d20815d916e75ff98c27a01ae817439ea7726329"},
{file = "charset_normalizer-3.2.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:6339d047dab2780cc6220f46306628e04d9750f02f983ddb37439ca47ced7149"},
{file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e4b749b9cc6ee664a3300bb3a273c1ca8068c46be705b6c31cf5d276f8628a94"},
{file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a38856a971c602f98472050165cea2cdc97709240373041b69030be15047691f"},
{file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f87f746ee241d30d6ed93969de31e5ffd09a2961a051e60ae6bddde9ec3583aa"},
{file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89f1b185a01fe560bc8ae5f619e924407efca2191b56ce749ec84982fc59a32a"},
{file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e1c8a2f4c69e08e89632defbfabec2feb8a8d99edc9f89ce33c4b9e36ab63037"},
{file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2f4ac36d8e2b4cc1aa71df3dd84ff8efbe3bfb97ac41242fbcfc053c67434f46"},
{file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a386ebe437176aab38c041de1260cd3ea459c6ce5263594399880bbc398225b2"},
{file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:ccd16eb18a849fd8dcb23e23380e2f0a354e8daa0c984b8a732d9cfaba3a776d"},
{file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:e6a5bf2cba5ae1bb80b154ed68a3cfa2fa00fde979a7f50d6598d3e17d9ac20c"},
{file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:45de3f87179c1823e6d9e32156fb14c1927fcc9aba21433f088fdfb555b77c10"},
{file = "charset_normalizer-3.2.0-cp38-cp38-win32.whl", hash = "sha256:1000fba1057b92a65daec275aec30586c3de2401ccdcd41f8a5c1e2c87078706"},
{file = "charset_normalizer-3.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:8b2c760cfc7042b27ebdb4a43a4453bd829a5742503599144d54a032c5dc7e9e"},
{file = "charset_normalizer-3.2.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:855eafa5d5a2034b4621c74925d89c5efef61418570e5ef9b37717d9c796419c"},
{file = "charset_normalizer-3.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:203f0c8871d5a7987be20c72442488a0b8cfd0f43b7973771640fc593f56321f"},
{file = "charset_normalizer-3.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e857a2232ba53ae940d3456f7533ce6ca98b81917d47adc3c7fd55dad8fab858"},
{file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5e86d77b090dbddbe78867a0275cb4df08ea195e660f1f7f13435a4649e954e5"},
{file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c4fb39a81950ec280984b3a44f5bd12819953dc5fa3a7e6fa7a80db5ee853952"},
{file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2dee8e57f052ef5353cf608e0b4c871aee320dd1b87d351c28764fc0ca55f9f4"},
{file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8700f06d0ce6f128de3ccdbc1acaea1ee264d2caa9ca05daaf492fde7c2a7200"},
{file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1920d4ff15ce893210c1f0c0e9d19bfbecb7983c76b33f046c13a8ffbd570252"},
{file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:c1c76a1743432b4b60ab3358c937a3fe1341c828ae6194108a94c69028247f22"},
{file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f7560358a6811e52e9c4d142d497f1a6e10103d3a6881f18d04dbce3729c0e2c"},
{file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:c8063cf17b19661471ecbdb3df1c84f24ad2e389e326ccaf89e3fb2484d8dd7e"},
{file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:cd6dbe0238f7743d0efe563ab46294f54f9bc8f4b9bcf57c3c666cc5bc9d1299"},
{file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:1249cbbf3d3b04902ff081ffbb33ce3377fa6e4c7356f759f3cd076cc138d020"},
{file = "charset_normalizer-3.2.0-cp39-cp39-win32.whl", hash = "sha256:6c409c0deba34f147f77efaa67b8e4bb83d2f11c8806405f76397ae5b8c0d1c9"},
{file = "charset_normalizer-3.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:7095f6fbfaa55defb6b733cfeb14efaae7a29f0b59d8cf213be4e7ca0b857b80"},
{file = "charset_normalizer-3.2.0-py3-none-any.whl", hash = "sha256:8e098148dd37b4ce3baca71fb394c81dc5d9c7728c95df695d2dca218edf40e6"},
]
[[package]]
name = "idna"
version = "3.4"
description = "Internationalized Domain Names in Applications (IDNA)"
optional = false
python-versions = ">=3.5"
files = [
{file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"},
{file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"},
]
[[package]]
name = "importlib-metadata"
version = "6.8.0"
description = "Read metadata from Python packages"
optional = false
python-versions = ">=3.8"
files = [
{file = "importlib_metadata-6.8.0-py3-none-any.whl", hash = "sha256:3ebb78df84a805d7698245025b975d9d67053cd94c79245ba4b3eb694abe68bb"},
{file = "importlib_metadata-6.8.0.tar.gz", hash = "sha256:dbace7892d8c0c4ac1ad096662232f831d4e64f4c4545bd53016a3e9d4654743"},
]
[package.dependencies]
zipp = ">=0.5"
[package.extras]
docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"]
perf = ["ipython"]
testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)", "pytest-ruff"]
[[package]]
name = "isort"
version = "5.12.0"
description = "A Python utility / library to sort Python imports."
optional = false
python-versions = ">=3.8.0"
files = [
{file = "isort-5.12.0-py3-none-any.whl", hash = "sha256:f84c2818376e66cf843d497486ea8fed8700b340f308f076c6fb1229dff318b6"},
{file = "isort-5.12.0.tar.gz", hash = "sha256:8bef7dde241278824a6d83f44a544709b065191b95b6e50894bdc722fcba0504"},
]
[package.extras]
colors = ["colorama (>=0.4.3)"]
pipfile-deprecated-finder = ["pip-shims (>=0.5.2)", "pipreqs", "requirementslib"]
plugins = ["setuptools"]
requirements-deprecated-finder = ["pip-api", "pipreqs"]
[[package]]
name = "platformdirs"
version = "3.8.1"
description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
optional = false
python-versions = ">=3.7"
files = [
{file = "platformdirs-3.8.1-py3-none-any.whl", hash = "sha256:cec7b889196b9144d088e4c57d9ceef7374f6c39694ad1577a0aab50d27ea28c"},
{file = "platformdirs-3.8.1.tar.gz", hash = "sha256:f87ca4fcff7d2b0f81c6a748a77973d7af0f4d526f98f308477c3c436c74d528"},
]
[package.extras]
docs = ["furo (>=2023.5.20)", "proselint (>=0.13)", "sphinx (>=7.0.1)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"]
test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.3.1)", "pytest-cov (>=4.1)", "pytest-mock (>=3.10)"]
[[package]]
name = "pyside6"
version = "6.5.1.1"
description = "Python bindings for the Qt cross-platform application and UI framework"
optional = false
python-versions = "<3.12,>=3.7"
files = [
{file = "PySide6-6.5.1.1-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:dc2d249ea2486526d1bb74e6cf96e2b49f2089cf069ab289a168aa48b5c251d5"},
{file = "PySide6-6.5.1.1-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:b7b6588527eb1ca45afb8918f109d827f7d248beaec14e7acdaea18883680aee"},
{file = "PySide6-6.5.1.1-cp37-abi3-win_amd64.whl", hash = "sha256:1517dd56f7235a98f3e1fcc983d3c8cf3d539b33164815c6e06442a297d2ab0d"},
{file = "PySide6-6.5.1.1-pp39-pypy39_pp73-macosx_10_9_universal2.whl", hash = "sha256:a55403254ff7421bea5b8e2196fded24e4a0357d3b1f10d5f01ffc3ae937c71a"},
{file = "PySide6-6.5.1.1-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:25c83843de0aa562631620721e4599eed55bc96747ed869caa631ecf92070951"},
{file = "PySide6-6.5.1.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:645c1a99c37a0ce045b23fb35faacf54d98442cc16f621fe1dad2a1d2880e5e3"},
]
[package.dependencies]
PySide6-Addons = "6.5.1.1"
PySide6-Essentials = "6.5.1.1"
shiboken6 = "6.5.1.1"
[[package]]
name = "pyside6-addons"
version = "6.5.1.1"
description = "Python bindings for the Qt cross-platform application and UI framework (Addons)"
optional = false
python-versions = "<3.12,>=3.7"
files = [
{file = "PySide6_Addons-6.5.1.1-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:aadda3376a81dbead867380f7ae81d2fe0fb1ffd482bfc10212be8b0d06c2c4c"},
{file = "PySide6_Addons-6.5.1.1-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:cf18c88274d6c9c29cccbecb11c72b1f0b0bb077dc044f9b40354f13d0c1c52e"},
{file = "PySide6_Addons-6.5.1.1-cp37-abi3-win_amd64.whl", hash = "sha256:d6370dfd03329cdcc91288d64bd1e26a5fc1908958b8a81fea5010a5849db441"},
{file = "PySide6_Addons-6.5.1.1-pp39-pypy39_pp73-macosx_10_9_universal2.whl", hash = "sha256:e3ab22776e620d9467ffb2d76be06d5a3b8b3859d77e2e73f65f2b29018645e7"},
{file = "PySide6_Addons-6.5.1.1-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:4e1bc141a7aa9488dc77c9b29ad412e417e601cc8e23050517f7c6c8634feb46"},
{file = "PySide6_Addons-6.5.1.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:441f8797d6b01c9dd9b848d0e156b2b5042d71d9266d0a6ded48c9b1cd337821"},
]
[package.dependencies]
PySide6-Essentials = "6.5.1.1"
shiboken6 = "6.5.1.1"
[[package]]
name = "pyside6-essentials"
version = "6.5.1.1"
description = "Python bindings for the Qt cross-platform application and UI framework (Essentials)"
optional = false
python-versions = "<3.12,>=3.7"
files = [
{file = "PySide6_Essentials-6.5.1.1-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:c0cc3b1e7ca0e6b7a0cb8190a8538242972df43c1f9014cc0cd066d4ed7fc83a"},
{file = "PySide6_Essentials-6.5.1.1-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:bfd8900b1bf6a595b7d63539817bc825941f737486a093d519514c5b67af789f"},
{file = "PySide6_Essentials-6.5.1.1-cp37-abi3-win_amd64.whl", hash = "sha256:1346e6a4e97d97f54e6c0805150c6dead4cc0e7914d77167f836eb36b83acb5c"},
{file = "PySide6_Essentials-6.5.1.1-pp39-pypy39_pp73-macosx_10_9_universal2.whl", hash = "sha256:0111386918064fa84a498ed7a6e93ec4155fe96e8d4f9c9e3ac54a5b65ddfadf"},
{file = "PySide6_Essentials-6.5.1.1-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:6264b00099a9bed0020460033e2a4369513e0e69f7abe3f436c3c6390164bcea"},
{file = "PySide6_Essentials-6.5.1.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:620cefb6c954d59f941f06acecfe5cdf42bf470f2f3e6b9d023f49f93d740080"},
]
[package.dependencies]
shiboken6 = "6.5.1.1"
[[package]]
name = "requests"
version = "2.31.0"
description = "Python HTTP for Humans."
optional = false
python-versions = ">=3.7"
files = [
{file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"},
{file = "requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"},
]
[package.dependencies]
certifi = ">=2017.4.17"
charset-normalizer = ">=2,<4"
idna = ">=2.5,<4"
urllib3 = ">=1.21.1,<3"
[package.extras]
socks = ["PySocks (>=1.5.6,!=1.5.7)"]
use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"]
[[package]]
name = "shiboken6"
version = "6.5.1.1"
description = "Python/C++ bindings helper module"
optional = false
python-versions = "<3.12,>=3.7"
files = [
{file = "shiboken6-6.5.1.1-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:59fc1797df38c9e8c89cc43d5996a4c0331d0258087fa9d6466b03822aba6ff2"},
{file = "shiboken6-6.5.1.1-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:4338a8eb00e8d6f5b27edf85ab689ada905a4490c73ed3f23ff3b3c5f72a563e"},
{file = "shiboken6-6.5.1.1-cp37-abi3-win_amd64.whl", hash = "sha256:aa6289cdbaa12f364f1c45d60d9d483c3842ee9cf6e9acdc3efd21cd460c2eb5"},
{file = "shiboken6-6.5.1.1-pp39-pypy39_pp73-macosx_10_9_universal2.whl", hash = "sha256:db029b9d895052c1f42b1f929af3a5f6e688a88c5862aed24d5094086b034ab2"},
{file = "shiboken6-6.5.1.1-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:1c7ba82093d66ace5c7a07ed9c7b4ea57a311ddbfecbe44aff7ed023efc8a380"},
{file = "shiboken6-6.5.1.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:34cacba2954bff632476fbead190868c6f068a6dd9e5c8fd7d2ed4f8f5cfade4"},
]
[[package]]
name = "tomli"
version = "2.0.1"
description = "A lil' TOML parser"
optional = false
python-versions = ">=3.7"
files = [
{file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"},
{file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"},
]
[[package]]
name = "urllib3"
version = "2.0.3"
description = "HTTP library with thread-safe connection pooling, file post, and more."
optional = false
python-versions = ">=3.7"
files = [
{file = "urllib3-2.0.3-py3-none-any.whl", hash = "sha256:48e7fafa40319d358848e1bc6809b208340fafe2096f1725d05d67443d0483d1"},
{file = "urllib3-2.0.3.tar.gz", hash = "sha256:bee28b5e56addb8226c96f7f13ac28cb4c301dd5ea8a6ca179c0b9835e032825"},
]
[package.extras]
brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"]
secure = ["certifi", "cryptography (>=1.9)", "idna (>=2.0.0)", "pyopenssl (>=17.1.0)", "urllib3-secure-extra"]
socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"]
zstd = ["zstandard (>=0.18.0)"]
[[package]]
name = "yapf"
version = "0.40.1"
description = "A formatter for Python code."
optional = false
python-versions = ">=3.7"
files = [
{file = "yapf-0.40.1-py3-none-any.whl", hash = "sha256:b8bfc1f280949153e795181768ca14ef43d7312629a06c43e7abd279323af313"},
{file = "yapf-0.40.1.tar.gz", hash = "sha256:958587eb5c8ec6c860119a9c25d02addf30a44f75aa152a4220d30e56a98037c"},
]
[package.dependencies]
importlib-metadata = ">=6.6.0"
platformdirs = ">=3.5.1"
tomli = ">=2.0.1"
[[package]]
name = "zipp"
version = "3.16.0"
description = "Backport of pathlib-compatible object wrapper for zip files"
optional = false
python-versions = ">=3.8"
files = [
{file = "zipp-3.16.0-py3-none-any.whl", hash = "sha256:5dadc3ad0a1f825fe42ce1bce0f2fc5a13af2e6b2d386af5b0ff295bc0a287d3"},
{file = "zipp-3.16.0.tar.gz", hash = "sha256:1876cb065531855bbe83b6c489dcf69ecc28f1068d8e95959fe8bbc77774c941"},
]
[package.extras]
docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"]
testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-ruff"]
[metadata]
lock-version = "2.0"
python-versions = "~3.11"
content-hash = "8a46b91bea175b77beffbe87a22e0fe9c21ea080cd3c8b0952d44233a24c3324"

40
prebuild.py Normal file
View File

@ -0,0 +1,40 @@
# coding=utf-8
import logging
import os
import sys
from shutil import which
UI_DIR = "assets/ui"
logging.basicConfig(level=logging.INFO)
class UICNotFound(Exception):
pass
if sys.platform == "linux":
exe = "pyside6-uic"
exe_alt = "/usr/lib/qt6/uic"
elif sys.platform == "win32":
exe = "pyside6-uic.exe"
exe_alt = None
UI_DIR = UI_DIR.replace("/", "\\")
if not which(exe) and not which(exe_alt):
raise UICNotFound("User Interface Compiler binary not found.")
elif not which(exe) and which(exe_alt):
exe = exe_alt
logging.info("Building UI files...")
for f in os.listdir(UI_DIR):
if exe == "/usr/lib/qt6/uic":
__flags = "--generator python"
else:
__flags = ""
cmd = f"{exe} {UI_DIR}/{f} -o openfm_qt/ui_{f[:-3]}.py {__flags}"
if sys.platform == "win32":
cmd = cmd.replace("/", "\\")
os.system(cmd)
logging.info(f"Successfully builded {f} as ui_{f[:-3]}.py")

View File

@ -1,19 +1,42 @@
[tool.poetry]
name = "openfm-qt"
version = "0.2.0"
version = "0.1.3"
description = "Qt client for Polish internet radio Open FM."
authors = ["Wiktor Zykubek <wz-git@mailbox.org>"]
license = "ISC"
readme = "README.md"
repository = "https://github.com/wzykubek/openfm-qt"
keywords = ["music", "player", "radio", "desktop", "gui", "qt6"]
classifiers = [
"Environment :: X11 Applications :: Qt",
"Intended Audience :: End Users/Desktop",
"License :: OSI Approved :: ISC License (ISCL)",
"Natural Language :: Polish",
"Operating System :: Unix",
"Operating System :: Microsoft :: Windows",
"Programming Language :: Python :: 3.11",
"Topic :: Multimedia :: Sound/Audio :: Players"
]
packages = [{include = "openfm_qt"}]
include = [{path = "openfm_qt/ui_*.py"}]
[tool.poetry.dependencies]
python = "^3.11"
python = "~3.11"
requests = "^2.31.0"
PySide6 = "^6.5.1.1"
[tool.poetry.group.dev.dependencies]
pyinstaller = "^5.12.0"
yapf = "^0.40.1"
isort = "^5.12.0"
[tool.yapf]
based_on_style = "pep8"
[tool.poetry.scripts]
openfm-qt = "openfm_qt.__main__:main"
[tool.poetry.build]
script = "prebuild.py"
[build-system]
requires = ["poetry-core"]

Binary file not shown.

Before

Width:  |  Height:  |  Size: 53 KiB

After

Width:  |  Height:  |  Size: 42 KiB