Compare commits

..

11 Commits

Author SHA1 Message Date
Wiktor Zykubek
45b5643cc7
Update screenshot_linux.png 2023-06-19 01:13:55 +02:00
Wiktor Zykubek
eeadc0a8c2
Create separate pause and stop button 2023-06-18 22:27:55 +02:00
Wiktor Zykubek
5358deab51
Change pagination for eposiodes list 2023-06-18 18:01:06 +02:00
Wiktor Zykubek
f664548d71
Allow to play podcasts 2023-06-18 17:57:27 +02:00
Wiktor Zykubek
c26d8833b3
Clear stationsListWidget each time listWidget is changed 2023-06-18 17:46:16 +02:00
Wiktor Zykubek
32ed78e7bc
Increase MainWindow width 2023-06-18 17:42:55 +02:00
Wiktor Zykubek
edc498c510
Print podcasts and episodes 2023-06-18 17:37:10 +02:00
Wiktor Zykubek
d02f7302a2
Add printPodcastGroups method 2023-06-18 16:37:12 +02:00
Wiktor Zykubek
e01edba7f3
Rename methods 2023-06-18 16:34:19 +02:00
Wiktor Zykubek
0b63621532
Adjust and rename getStationsData method to handle other URLs 2023-06-18 16:32:57 +02:00
Wiktor Zykubek
89cedd4f7c
Add tabWidget and podcasts category to UI 2023-06-18 16:14:26 +02:00
18 changed files with 319 additions and 573 deletions

View File

@ -1,23 +0,0 @@
---
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

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

View File

@ -1,7 +0,0 @@
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.

51
Open-FM.spec Normal file
View File

@ -0,0 +1,51 @@
# -*- 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,41 +2,19 @@
Qt client for Polish internet radio Open FM.
## GNU/Linux packages
### Arch Linux
Official package is available in AUR as [openfm-qt](https://aur.archlinux.org/packages/openfm-qt).
Install it using `yay` or other AUR helper.
```bash
$ yay -S openfm-qt
```
## 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.
## 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 .
## Build binary (Linux/Windows)
```shell
$ python3 build.py
```
Alternatively use `pipx` to install app in virtual environment.
```bash
$ pipx install .
```
Executable will be available in `dist/Open-FM` directory.
> **_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
## Run (Linux/Windows)
```shell
$ python3 main.py
```
## Screenshots

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

7
build.py Normal file
View File

@ -0,0 +1,7 @@
# 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

@ -6,19 +6,19 @@
<rect>
<x>0</x>
<y>0</y>
<width>350</width>
<width>650</width>
<height>500</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>350</width>
<width>650</width>
<height>500</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>350</width>
<width>650</width>
<height>500</height>
</size>
</property>
@ -33,7 +33,7 @@
</property>
<property name="windowIcon">
<iconset>
<normaloff>../assets/icons/icon.png</normaloff>../assets/icons/icon.png</iconset>
<normaloff>icon.ico</normaloff>icon.ico</iconset>
</property>
<property name="locale">
<locale language="Polish" country="Poland"/>
@ -44,7 +44,7 @@
<rect>
<x>9</x>
<y>9</y>
<width>332</width>
<width>631</width>
<height>461</height>
</rect>
</property>
@ -52,19 +52,85 @@
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QListWidget" name="groupsListWidget">
<widget class="QTabWidget" name="tabWidget">
<property name="minimumSize">
<size>
<width>130</width>
<width>200</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>130</width>
<width>200</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>
@ -81,6 +147,13 @@
</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">
@ -99,6 +172,18 @@
<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>
@ -124,8 +209,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>350</width>
<height>20</height>
<width>650</width>
<height>22</height>
</rect>
</property>
</widget>

View File

Before

Width:  |  Height:  |  Size: 252 KiB

After

Width:  |  Height:  |  Size: 252 KiB

View File

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

3
openfm-qt.pyproject Normal file
View File

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

View File

@ -1,135 +1,198 @@
# coding=utf-8
# This Python file uses the following encoding: utf-8
import json
import requests
from PySide6.QtCore import QUrl
from PySide6.QtMultimedia import QAudioOutput, QMediaPlayer
from PySide6.QtWidgets import QMainWindow, QMessageBox, QStyle
from PySide6.QtMultimedia import QMediaPlayer, QAudioOutput
from . import API_URL, DEFAULT_VOLUME, Ui_MainWindow
from __feature__ import snake_case, true_property # isort: skip
# 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
class MainWindow(QMainWindow):
"""MainWindow Class."""
def __init__(self):
def __init__(self, parent=None):
"""Initialize UI, audio player and handlers."""
super().__init__()
super().__init__(parent)
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)
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.__stations = self.getData(
"https://open.fm/radio/api/v2/ofm/stations_slug.json"
)
self.__podcasts_groups = self.getData(
"https://open.fm/api/podcasts/categories"
)
self.__player = QMediaPlayer()
self.__audio = QAudioOutput()
self.__player.audio_output = self.__audio
self.print_groups()
self.__player.setAudioOutput(self.__audio)
self.setVolume(DEFAULT_VOLUME)
self.printRadioGroups()
self.printPodcastGroups()
self.set_volume(DEFAULT_VOLUME)
self.ui.volumeHorizontalSlider.value = DEFAULT_VOLUME
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.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:
def getData(self, url) -> dict:
"""Get JSON data from API and convert it to dict."""
try:
resp = requests.get(API_URL)
resp = requests.get(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",
"Brak połączenia z serwerem.",
f"Błąd połączenia o kodzie: {resp.status_code}",
QMessageBox.Cancel,
)
error_box.exec()
else:
return json.loads(resp.text)
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 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_stations(self) -> None:
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:
"""Print stations (channels) in stationsListWidget."""
group = self.ui.groupsListWidget.selected_items()[0].text()
group = self.ui.radioGroupsListWidget.selectedItems()[0].text()
group_id = None
for e in self.__stations_data["groups"]:
for e in self.__stations["groups"]:
if e["name"] == group:
group_id = e["id"]
self.ui.stationsListWidget.clear()
self.ui.stationsListWidget.add_items([
e["name"] for e in self.__stations_data["channels"]
self.ui.stationsListWidget.addItems(
[
e["name"]
for e in self.__stations["channels"]
if e["group_id"] == group_id
])
]
)
def set_volume(self, volume: int = None) -> None:
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:
"""Set playback volume to given number or slider value."""
if not volume:
volume = self.ui.volumeHorizontalSlider.value
self.__audio.volume = volume / 100
volume = self.ui.volumeHorizontalSlider.value()
self.__audio.setVolume(volume / 100)
def toggle_mute(self) -> None:
def toggleMute(self) -> None:
"""Toggle playback volume between 0 and 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)
if self.ui.volumeHorizontalSlider.value() == 0:
self.ui.volumeHorizontalSlider.setValue(DEFAULT_VOLUME)
icon = self.style().standardIcon(QStyle.SP_MediaVolume)
self.setVolume(DEFAULT_VOLUME)
else:
self.previous_volume = self.__audio.volume * 100
self.ui.volumeHorizontalSlider.value = 0
icon = self.__icons.muted
self.set_volume(0)
self.ui.volumeHorizontalSlider.setValue(0)
icon = self.style().standardIcon(QStyle.SP_MediaVolumeMuted)
self.setVolume(0)
self.ui.volumeToolButton.icon = icon
self.ui.volumeToolButton.setIcon(icon)
def play_radio(self) -> None:
def playRadio(self) -> None:
"""Play station selected by user."""
station = self.ui.stationsListWidget.selected_items()[0].text()
selection = self.ui.stationsListWidget.selectedItems()[0].text()
stream_url = None
for e in self.__stations_data["channels"]:
if e["name"] == station:
for e in self.__stations["channels"]:
if e["name"] == selection:
stream_url = f"http://stream.open.fm/{e['id']}"
self.__player.source = QUrl(stream_url)
self.window_title = f"Open FM - {station}"
if not stream_url:
for e in self.__podcast_episodes["content"]:
if e["title"] == selection:
stream_url = e["file"].replace("https", "http")
# 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.
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.
# If you won't, application would crash.
for _ in range(3):
self.toggle_player()
def toggle_player(self) -> None:
"""Toggle playback (play/stop)."""
pb_state = QMediaPlayer.PlaybackState
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.__icons.stop
self.__player.stop()
self.__player.play()
icon = self.style().standardIcon(QStyle.SP_MediaPause)
self.ui.playbackToolButton.setIcon(icon)
def togglePlayer(self) -> None:
"""Toggle playback (play/pause)."""
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
]:
self.__player.play()
icon = self.style().standardIcon(QStyle.SP_MediaPause)
else:
pass
self.ui.playbackToolButton.icon = icon
self.ui.playbackToolButton.setIcon(icon)
def stopPlayer(self) -> None:
self.__player.stop()
icon = self.style().standardIcon(QStyle.SP_MediaPlay)
self.ui.playbackToolButton.setIcon(icon)

315
poetry.lock generated
View File

@ -1,315 +0,0 @@
# 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"

View File

@ -1,40 +0,0 @@
# 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,42 +1,19 @@
[tool.poetry]
name = "openfm-qt"
version = "0.1.3"
version = "0.2.0"
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]
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"
pyinstaller = "^5.12.0"
[build-system]
requires = ["poetry-core"]

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 53 KiB