Compare commits

..

3 Commits

Author SHA1 Message Date
Keith Edmunds
4eb3a98c95 Added volume fade graph. 2023-06-18 09:20:55 +01:00
Keith Edmunds
af0d715423 Suppress pygame message at startup 2023-06-14 07:20:36 +01:00
Keith Edmunds
6ae6d8e94e WIP volume graphs using matlibplot 2023-06-13 07:55:24 +01:00
9 changed files with 18662 additions and 18668 deletions

1
.envrc
View File

@ -4,6 +4,7 @@ export MAIL_PORT=587
export MAIL_SERVER="smtp.fastmail.com" export MAIL_SERVER="smtp.fastmail.com"
export MAIL_USERNAME="kae@midnighthax.com" export MAIL_USERNAME="kae@midnighthax.com"
export MAIL_USE_TLS=True export MAIL_USE_TLS=True
export PYGAME_HIDE_SUPPORT_PROMPT=1
branch=$(git branch --show-current) branch=$(git branch --show-current)
# Always treat running from /home/kae/mm as production # Always treat running from /home/kae/mm as production
if [ $(pwd) == /home/kae/mm ]; then if [ $(pwd) == /home/kae/mm ]; then

View File

@ -48,6 +48,9 @@ class Config(object):
DISPLAY_SQL = False DISPLAY_SQL = False
ERRORS_FROM = ['noreply@midnighthax.com'] ERRORS_FROM = ['noreply@midnighthax.com']
ERRORS_TO = ['kae@midnighthax.com'] ERRORS_TO = ['kae@midnighthax.com']
FADE_CURVE_BACKGROUND = "lightyellow"
FADE_CURVE_FOREGROUND = "blue"
FADE_CURVE_MS_BEFORE_FADE = 5000
FADE_STEPS = 20 FADE_STEPS = 20
FADE_TIME = 3000 FADE_TIME = 3000
HIDE_AFTER_PLAYING_OFFSET = 5000 HIDE_AFTER_PLAYING_OFFSET = 5000
@ -77,7 +80,7 @@ class Config(object):
SCROLL_TOP_MARGIN = 3 SCROLL_TOP_MARGIN = 3
TEXT_NO_TRACK_NO_NOTE = "[Section header]" TEXT_NO_TRACK_NO_NOTE = "[Section header]"
TOD_TIME_FORMAT = "%H:%M:%S" TOD_TIME_FORMAT = "%H:%M:%S"
TIMER_MS = 500 TIMER_MS = 100
TRACK_TIME_FORMAT = "%H:%M:%S" TRACK_TIME_FORMAT = "%H:%M:%S"
VOLUME_VLC_DEFAULT = 75 VOLUME_VLC_DEFAULT = 75
VOLUME_VLC_DROP3db = 65 VOLUME_VLC_DROP3db = 65

View File

@ -1,3 +1,4 @@
import numpy as np
import os import os
import psutil import psutil
import shutil import shutil

View File

@ -4,11 +4,14 @@ from log import log
from os.path import basename from os.path import basename
import argparse import argparse
import os import os
import numpy as np
import pyqtgraph as pg # type: ignore
import stackprinter # type: ignore import stackprinter # type: ignore
import subprocess import subprocess
import sys import sys
import threading import threading
import icons_rc
from datetime import datetime, timedelta from datetime import datetime, timedelta
from pygame import mixer from pygame import mixer
from time import sleep from time import sleep
@ -140,78 +143,63 @@ class CartButton(QPushButton):
self.pgb.setGeometry(0, 0, self.width(), 10) self.pgb.setGeometry(0, 0, self.width(), 10)
class PlaylistTrack: class FadeCurve:
""" GraphWidget = None
Used to provide a single reference point for specific playlist tracks,
typically the previous, current and next track.
"""
def __init__(self) -> None: def __init__(self, track):
""" """
Only initialises data structure. Call set_plr to populate. Set up fade graph array
Do NOT store row_number here - that changes if tracks are reordered
in playlist (add, remove, drag/drop) and we shouldn't care about row
number: that's the playlist's problem.
""" """
self.artist: Optional[str] = None audio = helpers.get_audio_segment(track.path)
self.duration: Optional[int] = None if not audio:
self.end_time: Optional[datetime] = None return None
self.fade_at: Optional[int] = None
self.fade_length: Optional[int] = None
self.path: Optional[str] = None
self.playlist_id: Optional[int] = None
self.playlist_tab: Optional[PlaylistTab] = None
self.plr_id: Optional[int] = None
self.silence_at: Optional[int] = None
self.start_gap: Optional[int] = None
self.start_time: Optional[datetime] = None
self.title: Optional[str] = None
self.track_id: Optional[int] = None
def __repr__(self) -> str: # Start point of curve is Config.FADE_CURVE_MS_BEFORE_FADE
return ( # milliseconds before fade starts to silence
f"<PlaylistTrack(title={self.title}, artist={self.artist}, " self.start_ms = max(
f"playlist_id={self.playlist_id}>" 0, track.fade_at - Config.FADE_CURVE_MS_BEFORE_FADE - 1)
self.end_ms = track.silence_at
self.audio_segment = audio[self.start_ms:self.end_ms]
self.graph_array = np.array(self.audio_segment.get_array_of_samples())
# Calculate the factor to map milliseconds of track to array
self.ms_to_array_factor = (
len(self.graph_array) / (self.end_ms - self.start_ms)
) )
def set_plr(self, session: scoped_session, plr: PlaylistRows, self.region = None
tab: PlaylistTab) -> None:
"""
Update with new plr information
"""
self.playlist_tab = tab def clear(self) -> None:
"""Clear the current graph"""
session.add(plr) if self.GraphWidget:
track = plr.track self.GraphWidget.clear()
self.artist = track.artist def plot(self):
self.duration = track.duration self.curve = self.GraphWidget.plot(self.graph_array)
self.end_time = None self.curve.setPen(Config.FADE_CURVE_FOREGROUND)
self.fade_at = track.fade_at
self.path = track.path
self.playlist_id = plr.playlist_id
self.plr_id = plr.id
self.silence_at = track.silence_at
self.start_gap = track.start_gap
self.start_time = None
self.title = track.title
self.track_id = track.id
if track.silence_at and track.fade_at: def tick(self, play_position) -> None:
self.fade_length = track.silence_at - track.fade_at """Update volume fade curve"""
def start(self) -> None: if not self.GraphWidget:
""" return
Called when track starts playing
"""
self.start_time = datetime.now() ms_of_graph = play_position - self.start_ms
if self.duration: if ms_of_graph < 0:
self.end_time = ( return
self.start_time + timedelta(milliseconds=self.duration))
if self.region is None:
# Create the region now that we're into fade
self.region = pg.LinearRegionItem(
[0, 0],
bounds=[0, len(self.graph_array)]
)
self.GraphWidget.addItem(self.region)
# Update region position
self.region.setRegion([0, ms_of_graph * self.ms_to_array_factor])
class ImportTrack(QObject): class ImportTrack(QObject):
@ -261,6 +249,84 @@ class MusicMusterSignals(QObject):
set_next_track_signal = pyqtSignal(int, int) set_next_track_signal = pyqtSignal(int, int)
class PlaylistTrack:
"""
Used to provide a single reference point for specific playlist tracks,
typically the previous, current and next track.
"""
def __init__(self) -> None:
"""
Only initialises data structure. Call set_plr to populate.
Do NOT store row_number here - that changes if tracks are reordered
in playlist (add, remove, drag/drop) and we shouldn't care about row
number: that's the playlist's problem.
"""
self.artist: Optional[str] = None
self.duration: Optional[int] = None
self.end_time: Optional[datetime] = None
self.fade_at: Optional[int] = None
self.fade_curve: Optional[FadeCurve] = None
self.fade_length: Optional[int] = None
self.path: Optional[str] = None
self.playlist_id: Optional[int] = None
self.playlist_tab: Optional[PlaylistTab] = None
self.plr_id: Optional[int] = None
self.silence_at: Optional[int] = None
self.start_gap: Optional[int] = None
self.start_time: Optional[datetime] = None
self.title: Optional[str] = None
self.track_id: Optional[int] = None
def __repr__(self) -> str:
return (
f"<PlaylistTrack(title={self.title}, artist={self.artist}, "
f"playlist_id={self.playlist_id}>"
)
def set_plr(self, session: scoped_session, plr: PlaylistRows,
tab: PlaylistTab) -> None:
"""
Update with new plr information
"""
if not plr.track:
return
self.playlist_tab = tab
session.add(plr)
track = plr.track
self.artist = track.artist
self.duration = track.duration
self.end_time = None
self.fade_at = track.fade_at
self.fade_graph = FadeCurve(track)
self.path = track.path
self.playlist_id = plr.playlist_id
self.plr_id = plr.id
self.silence_at = track.silence_at
self.start_gap = track.start_gap
self.start_time = None
self.title = track.title
self.track_id = track.id
if track.silence_at and track.fade_at:
self.fade_length = track.silence_at - track.fade_at
def start(self) -> None:
"""
Called when track starts playing
"""
self.start_time = datetime.now()
if self.duration:
self.end_time = (
self.start_time + timedelta(milliseconds=self.duration))
class Window(QMainWindow, Ui_MainWindow): class Window(QMainWindow, Ui_MainWindow):
def __init__(self, parent=None, *args, **kwargs) -> None: def __init__(self, parent=None, *args, **kwargs) -> None:
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
@ -289,6 +355,10 @@ class Window(QMainWindow, Ui_MainWindow):
self.txtSearch.setHidden(True) self.txtSearch.setHidden(True)
self.hide_played_tracks = False self.hide_played_tracks = False
mixer.init() mixer.init()
self.widgetFadeVolume.hideAxis('bottom')
self.widgetFadeVolume.hideAxis('left')
self.widgetFadeVolume.setBackground(Config.FADE_CURVE_BACKGROUND)
FadeCurve.GraphWidget = self.widgetFadeVolume
self.visible_playlist_tab: Callable[[], PlaylistTab] = \ self.visible_playlist_tab: Callable[[], PlaylistTab] = \
self.tabPlaylist.currentWidget self.tabPlaylist.currentWidget
@ -300,6 +370,7 @@ class Window(QMainWindow, Ui_MainWindow):
else: else:
self.carts_init() self.carts_init()
self.enable_play_next_controls() self.enable_play_next_controls()
self.clock_counter = 0
self.timer.start(Config.TIMER_MS) self.timer.start(Config.TIMER_MS)
self.connect_signals_slots() self.connect_signals_slots()
@ -751,6 +822,7 @@ class Window(QMainWindow, Ui_MainWindow):
- Tell playlist_tab track has finished - Tell playlist_tab track has finished
- Reset PlaylistTrack objects - Reset PlaylistTrack objects
- Reset clocks - Reset clocks
- Reset fade graph
- Update headers - Update headers
- Enable controls - Enable controls
""" """
@ -763,6 +835,9 @@ class Window(QMainWindow, Ui_MainWindow):
if self.current_track.playlist_tab: if self.current_track.playlist_tab:
self.current_track.playlist_tab.play_ended() self.current_track.playlist_tab.play_ended()
# Reset fade graph
self.current_track.fade_graph.clear()
# Reset PlaylistTrack objects # Reset PlaylistTrack objects
if self.current_track.track_id: if self.current_track.track_id:
self.previous_track = self.current_track self.previous_track = self.current_track
@ -775,21 +850,6 @@ class Window(QMainWindow, Ui_MainWindow):
self.label_end_timer.setText("00:00") self.label_end_timer.setText("00:00")
self.label_fade_timer.setText("00:00") self.label_fade_timer.setText("00:00")
self.label_silent_timer.setText("00:00") self.label_silent_timer.setText("00:00")
self.label_start_time.setText("00:00:00")
self.label_end_time.setText("00:00:00")
if self.next_track.track_id:
self.label_track_length.setText(
helpers.ms_to_mmss(self.next_track.duration)
)
if self.next_track.silence_at and self.next_track.fade_at:
self.label_fade_length.setText(helpers.ms_to_mmss(
self.next_track.silence_at - self.next_track.fade_at))
else:
self.label_fade_length.setText("0:00")
else:
self.label_track_length.setText("0:00")
self.label_fade_length.setText("0:00")
# Update headers # Update headers
self.update_headers() self.update_headers()
@ -1249,6 +1309,9 @@ class Window(QMainWindow, Ui_MainWindow):
break break
sleep(0.1) sleep(0.1)
# Show closing volume graph
self.current_track.fade_graph.plot()
# Tell database to record it as played # Tell database to record it as played
Playdates(session, self.current_track.track_id) Playdates(session, self.current_track.track_id)
@ -1265,21 +1328,6 @@ class Window(QMainWindow, Ui_MainWindow):
# Update headers # Update headers
self.update_headers() self.update_headers()
# Update clocks
self.label_track_length.setText(
helpers.ms_to_mmss(self.current_track.duration)
)
self.label_fade_length.setText(
helpers.ms_to_mmss(self.current_track.fade_length))
if self.current_track.start_time:
self.label_start_time.setText(
self.current_track.start_time.strftime(
Config.TRACK_TIME_FORMAT))
if self.current_track.end_time:
self.label_end_time.setText(
self.current_track.end_time.strftime(
Config.TRACK_TIME_FORMAT))
def preview(self) -> None: def preview(self) -> None:
""" """
Preview selected or next track. We use a different mechanism to Preview selected or next track. We use a different mechanism to
@ -1548,7 +1596,7 @@ class Window(QMainWindow, Ui_MainWindow):
def set_next_plr_id(self, next_plr_id: Optional[int], def set_next_plr_id(self, next_plr_id: Optional[int],
playlist_tab: PlaylistTab) -> None: playlist_tab: PlaylistTab) -> None:
""" """
Set passed plr_id as next track to play, or clear next track if None Set passed plr_id as next track to play, or clear next track if None
Actions required: Actions required:
- Update self.next_track PlaylistTrack structure - Update self.next_track PlaylistTrack structure
@ -1625,6 +1673,11 @@ class Window(QMainWindow, Ui_MainWindow):
""" """
Carry out clock tick actions. Carry out clock tick actions.
self.clock_counter is incrememted at each tick (100ms), and this
value is used to determine the actions to take.
The Fade Volume graph is updated every 100ms.
The Time of Day clock and any cart progress bars are updated The Time of Day clock and any cart progress bars are updated
every tick (500ms). every tick (500ms).
@ -1634,6 +1687,7 @@ class Window(QMainWindow, Ui_MainWindow):
updating. That looks odd. updating. That looks odd.
Actions required: Actions required:
- Update Fade Volume graph
- Update TOD clock - Update TOD clock
- Call cart_tick - Call cart_tick
- If track is playing: - If track is playing:
@ -1642,74 +1696,78 @@ class Window(QMainWindow, Ui_MainWindow):
run stop_track run stop_track
""" """
# Update TOD clock # Update volume fade curve
self.lblTOD.setText(datetime.now().strftime(Config.TOD_TIME_FORMAT)) if self.current_track.track_id and self.current_track.fade_graph:
# Update carts self.current_track.fade_graph.tick(self.music.get_playtime())
self.cart_tick()
self.even_tick = not self.even_tick if self.clock_counter % 2 == 0:
if not self.even_tick: # Update TOD clock
return self.lblTOD.setText(datetime.now().strftime(
if not self.playing: Config.TOD_TIME_FORMAT))
return # Update carts
self.cart_tick()
# If track is playing, update track clocks time and colours if self.clock_counter % 5 == 0:
# There is a discrete time between starting playing a track and if not self.playing:
# player.is_playing() returning True, so assume playing if less return
# than Config.PLAY_SETTLE microseconds have passed since
# starting play.
if self.music.player and self.current_track.start_time and (
self.music.player.is_playing() or
(datetime.now() - self.current_track.start_time)
< timedelta(microseconds=Config.PLAY_SETTLE)):
playtime = self.music.get_playtime()
time_to_fade = (self.current_track.fade_at - playtime)
time_to_silence = (
self.current_track.silence_at - playtime)
time_to_end = (self.current_track.duration - playtime)
# Elapsed time # If track is playing, update track clocks time and colours
self.label_elapsed_timer.setText(helpers.ms_to_mmss(playtime)) # There is a discrete time between starting playing a track and
# player.is_playing() returning True, so assume playing if less
# than Config.PLAY_SETTLE microseconds have passed since
# starting play.
if self.music.player and self.current_track.start_time and (
self.music.player.is_playing() or
(datetime.now() - self.current_track.start_time)
< timedelta(microseconds=Config.PLAY_SETTLE)):
playtime = self.music.get_playtime()
time_to_fade = (self.current_track.fade_at - playtime)
time_to_silence = (
self.current_track.silence_at - playtime)
time_to_end = (self.current_track.duration - playtime)
# Time to fade # Elapsed time
self.label_fade_timer.setText(helpers.ms_to_mmss(time_to_fade)) self.label_elapsed_timer.setText(helpers.ms_to_mmss(playtime))
# If silent in the next 5 seconds, put warning colour on # Time to fade
# time to silence box and enable play controls self.label_fade_timer.setText(helpers.ms_to_mmss(time_to_fade))
if time_to_silence <= 5500:
self.frame_silent.setStyleSheet( # If silent in the next 5 seconds, put warning colour on
f"background: {Config.COLOUR_ENDING_TIMER}" # time to silence box and enable play controls
if time_to_silence <= 5500:
self.frame_silent.setStyleSheet(
f"background: {Config.COLOUR_ENDING_TIMER}"
)
self.enable_play_next_controls()
# Set warning colour on time to silence box when fade starts
elif time_to_fade <= 500:
self.frame_silent.setStyleSheet(
f"background: {Config.COLOUR_WARNING_TIMER}"
)
# Five seconds before fade starts, set warning colour on
# time to silence box and enable play controls
elif time_to_fade <= 5500:
self.frame_fade.setStyleSheet(
f"background: {Config.COLOUR_WARNING_TIMER}"
)
self.enable_play_next_controls()
else:
self.frame_silent.setStyleSheet("")
self.frame_fade.setStyleSheet("")
self.label_silent_timer.setText(
helpers.ms_to_mmss(time_to_silence)
) )
self.enable_play_next_controls()
# Set warning colour on time to silence box when fade starts # Time to end
elif time_to_fade <= 500: self.label_end_timer.setText(helpers.ms_to_mmss(time_to_end))
self.frame_silent.setStyleSheet(
f"background: {Config.COLOUR_WARNING_TIMER}" # Autoplay next track
) # if time_to_silence <= 1500:
# Five seconds before fade starts, set warning colour on # self.play_next()
# time to silence box and enable play controls
elif time_to_fade <= 5500:
self.frame_fade.setStyleSheet(
f"background: {Config.COLOUR_WARNING_TIMER}"
)
self.enable_play_next_controls()
else: else:
self.frame_silent.setStyleSheet("") if self.playing:
self.frame_fade.setStyleSheet("") self.stop_playing()
self.label_silent_timer.setText(
helpers.ms_to_mmss(time_to_silence)
)
# Time to end
self.label_end_timer.setText(helpers.ms_to_mmss(time_to_end))
# Autoplay next track
# if time_to_silence <= 1500:
# self.play_next()
else:
if self.playing:
self.stop_playing()
def update_headers(self) -> None: def update_headers(self) -> None:
""" """

File diff suppressed because it is too large Load Diff

View File

@ -349,6 +349,12 @@ padding-left: 8px;</string>
</item> </item>
<item row="5" column="0"> <item row="5" column="0">
<widget class="QFrame" name="InfoFooterFrame"> <widget class="QFrame" name="InfoFooterFrame">
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="styleSheet"> <property name="styleSheet">
<string notr="true">background-color: rgb(192, 191, 188)</string> <string notr="true">background-color: rgb(192, 191, 188)</string>
</property> </property>
@ -365,8 +371,14 @@ padding-left: 8px;</string>
<widget class="QFrame" name="FadeStopInfoFrame"> <widget class="QFrame" name="FadeStopInfoFrame">
<property name="minimumSize"> <property name="minimumSize">
<size> <size>
<width>321</width> <width>152</width>
<height>0</height> <height>112</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>184</width>
<height>16777215</height>
</size> </size>
</property> </property>
<property name="frameShape"> <property name="frameShape">
@ -376,28 +388,20 @@ padding-left: 8px;</string>
<enum>QFrame::Raised</enum> <enum>QFrame::Raised</enum>
</property> </property>
<layout class="QGridLayout" name="gridLayout"> <layout class="QGridLayout" name="gridLayout">
<item row="1" column="0"> <item row="0" column="0" colspan="2">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Fade length:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QLabel" name="label_x_2">
<property name="text">
<string>Start:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="2" column="0" colspan="2">
<widget class="QPushButton" name="btnFade"> <widget class="QPushButton" name="btnFade">
<property name="minimumSize">
<size>
<width>132</width>
<height>36</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>164</width>
<height>16777215</height>
</size>
</property>
<property name="text"> <property name="text">
<string> Fade</string> <string> Fade</string>
</property> </property>
@ -413,92 +417,14 @@ padding-left: 8px;</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="0" column="3"> <item row="1" column="0" colspan="2">
<widget class="QLabel" name="label_start_time">
<property name="font">
<font>
<family>FreeSans</family>
<pointsize>16</pointsize>
</font>
</property>
<property name="text">
<string>00:00:00</string>
</property>
<property name="scaledContents">
<bool>false</bool>
</property>
</widget>
</item>
<item row="1" column="3">
<widget class="QLabel" name="label_end_time">
<property name="font">
<font>
<family>FreeSans</family>
<pointsize>16</pointsize>
</font>
</property>
<property name="text">
<string>00:00:00</string>
</property>
<property name="scaledContents">
<bool>false</bool>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_x">
<property name="text">
<string>Track length:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="label_fade_length">
<property name="font">
<font>
<family>FreeSans</family>
<pointsize>16</pointsize>
</font>
</property>
<property name="text">
<string>0:00</string>
</property>
<property name="scaledContents">
<bool>false</bool>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QLabel" name="label_8">
<property name="text">
<string>End:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="label_track_length">
<property name="font">
<font>
<family>FreeSans</family>
<pointsize>16</pointsize>
</font>
</property>
<property name="text">
<string>0:00</string>
</property>
<property name="scaledContents">
<bool>false</bool>
</property>
</widget>
</item>
<item row="2" column="2" colspan="2">
<widget class="QPushButton" name="btnPreview"> <widget class="QPushButton" name="btnPreview">
<property name="minimumSize">
<size>
<width>132</width>
<height>36</height>
</size>
</property>
<property name="text"> <property name="text">
<string> Preview</string> <string> Preview</string>
</property> </property>
@ -524,7 +450,7 @@ padding-left: 8px;</string>
<widget class="QFrame" name="frame_elapsed"> <widget class="QFrame" name="frame_elapsed">
<property name="minimumSize"> <property name="minimumSize">
<size> <size>
<width>0</width> <width>152</width>
<height>112</height> <height>112</height>
</size> </size>
</property> </property>
@ -576,7 +502,7 @@ padding-left: 8px;</string>
<widget class="QFrame" name="frame_fade"> <widget class="QFrame" name="frame_fade">
<property name="minimumSize"> <property name="minimumSize">
<size> <size>
<width>0</width> <width>152</width>
<height>112</height> <height>112</height>
</size> </size>
</property> </property>
@ -622,10 +548,26 @@ padding-left: 8px;</string>
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QFrame" name="frame_silent"> <widget class="PlotWidget" name="widgetFadeVolume" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize"> <property name="minimumSize">
<size> <size>
<width>0</width> <width>0</width>
<height>0</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QFrame" name="frame_silent">
<property name="minimumSize">
<size>
<width>152</width>
<height>112</height> <height>112</height>
</size> </size>
</property> </property>
@ -674,7 +616,7 @@ padding-left: 8px;</string>
<widget class="QFrame" name="frame_end"> <widget class="QFrame" name="frame_end">
<property name="minimumSize"> <property name="minimumSize">
<size> <size>
<width>0</width> <width>152</width>
<height>112</height> <height>112</height>
</size> </size>
</property> </property>
@ -1228,6 +1170,12 @@ padding-left: 8px;</string>
<header>infotabs</header> <header>infotabs</header>
<container>1</container> <container>1</container>
</customwidget> </customwidget>
<customwidget>
<class>PlotWidget</class>
<extends>QWidget</extends>
<header>pyqtgraph</header>
<container>1</container>
</customwidget>
</customwidgets> </customwidgets>
<resources> <resources>
<include location="icons.qrc"/> <include location="icons.qrc"/>

View File

@ -179,6 +179,7 @@ class Ui_MainWindow(object):
self.tabInfolist.setObjectName("tabInfolist") self.tabInfolist.setObjectName("tabInfolist")
self.gridLayout_4.addWidget(self.splitter, 4, 0, 1, 1) self.gridLayout_4.addWidget(self.splitter, 4, 0, 1, 1)
self.InfoFooterFrame = QtWidgets.QFrame(parent=self.centralwidget) self.InfoFooterFrame = QtWidgets.QFrame(parent=self.centralwidget)
self.InfoFooterFrame.setMaximumSize(QtCore.QSize(16777215, 16777215))
self.InfoFooterFrame.setStyleSheet("background-color: rgb(192, 191, 188)") self.InfoFooterFrame.setStyleSheet("background-color: rgb(192, 191, 188)")
self.InfoFooterFrame.setFrameShape(QtWidgets.QFrame.Shape.StyledPanel) self.InfoFooterFrame.setFrameShape(QtWidgets.QFrame.Shape.StyledPanel)
self.InfoFooterFrame.setFrameShadow(QtWidgets.QFrame.Shadow.Raised) self.InfoFooterFrame.setFrameShadow(QtWidgets.QFrame.Shadow.Raised)
@ -188,78 +189,34 @@ class Ui_MainWindow(object):
self.horizontalLayout = QtWidgets.QHBoxLayout() self.horizontalLayout = QtWidgets.QHBoxLayout()
self.horizontalLayout.setObjectName("horizontalLayout") self.horizontalLayout.setObjectName("horizontalLayout")
self.FadeStopInfoFrame = QtWidgets.QFrame(parent=self.InfoFooterFrame) self.FadeStopInfoFrame = QtWidgets.QFrame(parent=self.InfoFooterFrame)
self.FadeStopInfoFrame.setMinimumSize(QtCore.QSize(321, 0)) self.FadeStopInfoFrame.setMinimumSize(QtCore.QSize(152, 112))
self.FadeStopInfoFrame.setMaximumSize(QtCore.QSize(184, 16777215))
self.FadeStopInfoFrame.setFrameShape(QtWidgets.QFrame.Shape.StyledPanel) self.FadeStopInfoFrame.setFrameShape(QtWidgets.QFrame.Shape.StyledPanel)
self.FadeStopInfoFrame.setFrameShadow(QtWidgets.QFrame.Shadow.Raised) self.FadeStopInfoFrame.setFrameShadow(QtWidgets.QFrame.Shadow.Raised)
self.FadeStopInfoFrame.setObjectName("FadeStopInfoFrame") self.FadeStopInfoFrame.setObjectName("FadeStopInfoFrame")
self.gridLayout = QtWidgets.QGridLayout(self.FadeStopInfoFrame) self.gridLayout = QtWidgets.QGridLayout(self.FadeStopInfoFrame)
self.gridLayout.setObjectName("gridLayout") self.gridLayout.setObjectName("gridLayout")
self.label_7 = QtWidgets.QLabel(parent=self.FadeStopInfoFrame)
self.label_7.setAlignment(QtCore.Qt.AlignmentFlag.AlignRight|QtCore.Qt.AlignmentFlag.AlignTrailing|QtCore.Qt.AlignmentFlag.AlignVCenter)
self.label_7.setObjectName("label_7")
self.gridLayout.addWidget(self.label_7, 1, 0, 1, 1)
self.label_x_2 = QtWidgets.QLabel(parent=self.FadeStopInfoFrame)
self.label_x_2.setAlignment(QtCore.Qt.AlignmentFlag.AlignRight|QtCore.Qt.AlignmentFlag.AlignTrailing|QtCore.Qt.AlignmentFlag.AlignVCenter)
self.label_x_2.setObjectName("label_x_2")
self.gridLayout.addWidget(self.label_x_2, 0, 2, 1, 1)
self.btnFade = QtWidgets.QPushButton(parent=self.FadeStopInfoFrame) self.btnFade = QtWidgets.QPushButton(parent=self.FadeStopInfoFrame)
self.btnFade.setMinimumSize(QtCore.QSize(132, 36))
self.btnFade.setMaximumSize(QtCore.QSize(164, 16777215))
icon1 = QtGui.QIcon() icon1 = QtGui.QIcon()
icon1.addPixmap(QtGui.QPixmap(":/icons/fade"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off) icon1.addPixmap(QtGui.QPixmap(":/icons/fade"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
self.btnFade.setIcon(icon1) self.btnFade.setIcon(icon1)
self.btnFade.setIconSize(QtCore.QSize(30, 30)) self.btnFade.setIconSize(QtCore.QSize(30, 30))
self.btnFade.setObjectName("btnFade") self.btnFade.setObjectName("btnFade")
self.gridLayout.addWidget(self.btnFade, 2, 0, 1, 2) self.gridLayout.addWidget(self.btnFade, 0, 0, 1, 2)
self.label_start_time = QtWidgets.QLabel(parent=self.FadeStopInfoFrame)
font = QtGui.QFont()
font.setFamily("FreeSans")
font.setPointSize(16)
self.label_start_time.setFont(font)
self.label_start_time.setScaledContents(False)
self.label_start_time.setObjectName("label_start_time")
self.gridLayout.addWidget(self.label_start_time, 0, 3, 1, 1)
self.label_end_time = QtWidgets.QLabel(parent=self.FadeStopInfoFrame)
font = QtGui.QFont()
font.setFamily("FreeSans")
font.setPointSize(16)
self.label_end_time.setFont(font)
self.label_end_time.setScaledContents(False)
self.label_end_time.setObjectName("label_end_time")
self.gridLayout.addWidget(self.label_end_time, 1, 3, 1, 1)
self.label_x = QtWidgets.QLabel(parent=self.FadeStopInfoFrame)
self.label_x.setAlignment(QtCore.Qt.AlignmentFlag.AlignRight|QtCore.Qt.AlignmentFlag.AlignTrailing|QtCore.Qt.AlignmentFlag.AlignVCenter)
self.label_x.setObjectName("label_x")
self.gridLayout.addWidget(self.label_x, 0, 0, 1, 1)
self.label_fade_length = QtWidgets.QLabel(parent=self.FadeStopInfoFrame)
font = QtGui.QFont()
font.setFamily("FreeSans")
font.setPointSize(16)
self.label_fade_length.setFont(font)
self.label_fade_length.setScaledContents(False)
self.label_fade_length.setObjectName("label_fade_length")
self.gridLayout.addWidget(self.label_fade_length, 1, 1, 1, 1)
self.label_8 = QtWidgets.QLabel(parent=self.FadeStopInfoFrame)
self.label_8.setAlignment(QtCore.Qt.AlignmentFlag.AlignRight|QtCore.Qt.AlignmentFlag.AlignTrailing|QtCore.Qt.AlignmentFlag.AlignVCenter)
self.label_8.setObjectName("label_8")
self.gridLayout.addWidget(self.label_8, 1, 2, 1, 1)
self.label_track_length = QtWidgets.QLabel(parent=self.FadeStopInfoFrame)
font = QtGui.QFont()
font.setFamily("FreeSans")
font.setPointSize(16)
self.label_track_length.setFont(font)
self.label_track_length.setScaledContents(False)
self.label_track_length.setObjectName("label_track_length")
self.gridLayout.addWidget(self.label_track_length, 0, 1, 1, 1)
self.btnPreview = QtWidgets.QPushButton(parent=self.FadeStopInfoFrame) self.btnPreview = QtWidgets.QPushButton(parent=self.FadeStopInfoFrame)
self.btnPreview.setMinimumSize(QtCore.QSize(132, 36))
icon2 = QtGui.QIcon() icon2 = QtGui.QIcon()
icon2.addPixmap(QtGui.QPixmap(":/icons/headphones"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off) icon2.addPixmap(QtGui.QPixmap(":/icons/headphones"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
self.btnPreview.setIcon(icon2) self.btnPreview.setIcon(icon2)
self.btnPreview.setIconSize(QtCore.QSize(30, 30)) self.btnPreview.setIconSize(QtCore.QSize(30, 30))
self.btnPreview.setCheckable(True) self.btnPreview.setCheckable(True)
self.btnPreview.setObjectName("btnPreview") self.btnPreview.setObjectName("btnPreview")
self.gridLayout.addWidget(self.btnPreview, 2, 2, 1, 2) self.gridLayout.addWidget(self.btnPreview, 1, 0, 1, 2)
self.horizontalLayout.addWidget(self.FadeStopInfoFrame) self.horizontalLayout.addWidget(self.FadeStopInfoFrame)
self.frame_elapsed = QtWidgets.QFrame(parent=self.InfoFooterFrame) self.frame_elapsed = QtWidgets.QFrame(parent=self.InfoFooterFrame)
self.frame_elapsed.setMinimumSize(QtCore.QSize(0, 112)) self.frame_elapsed.setMinimumSize(QtCore.QSize(152, 112))
self.frame_elapsed.setStyleSheet("") self.frame_elapsed.setStyleSheet("")
self.frame_elapsed.setFrameShape(QtWidgets.QFrame.Shape.StyledPanel) self.frame_elapsed.setFrameShape(QtWidgets.QFrame.Shape.StyledPanel)
self.frame_elapsed.setFrameShadow(QtWidgets.QFrame.Shadow.Raised) self.frame_elapsed.setFrameShadow(QtWidgets.QFrame.Shadow.Raised)
@ -283,7 +240,7 @@ class Ui_MainWindow(object):
self.verticalLayout_4.addWidget(self.label_elapsed_timer) self.verticalLayout_4.addWidget(self.label_elapsed_timer)
self.horizontalLayout.addWidget(self.frame_elapsed) self.horizontalLayout.addWidget(self.frame_elapsed)
self.frame_fade = QtWidgets.QFrame(parent=self.InfoFooterFrame) self.frame_fade = QtWidgets.QFrame(parent=self.InfoFooterFrame)
self.frame_fade.setMinimumSize(QtCore.QSize(0, 112)) self.frame_fade.setMinimumSize(QtCore.QSize(152, 112))
self.frame_fade.setStyleSheet("") self.frame_fade.setStyleSheet("")
self.frame_fade.setFrameShape(QtWidgets.QFrame.Shape.StyledPanel) self.frame_fade.setFrameShape(QtWidgets.QFrame.Shape.StyledPanel)
self.frame_fade.setFrameShadow(QtWidgets.QFrame.Shadow.Raised) self.frame_fade.setFrameShadow(QtWidgets.QFrame.Shadow.Raised)
@ -305,8 +262,17 @@ class Ui_MainWindow(object):
self.label_fade_timer.setObjectName("label_fade_timer") self.label_fade_timer.setObjectName("label_fade_timer")
self.verticalLayout_2.addWidget(self.label_fade_timer) self.verticalLayout_2.addWidget(self.label_fade_timer)
self.horizontalLayout.addWidget(self.frame_fade) self.horizontalLayout.addWidget(self.frame_fade)
self.widgetFadeVolume = PlotWidget(parent=self.InfoFooterFrame)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Preferred)
sizePolicy.setHorizontalStretch(1)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.widgetFadeVolume.sizePolicy().hasHeightForWidth())
self.widgetFadeVolume.setSizePolicy(sizePolicy)
self.widgetFadeVolume.setMinimumSize(QtCore.QSize(0, 0))
self.widgetFadeVolume.setObjectName("widgetFadeVolume")
self.horizontalLayout.addWidget(self.widgetFadeVolume)
self.frame_silent = QtWidgets.QFrame(parent=self.InfoFooterFrame) self.frame_silent = QtWidgets.QFrame(parent=self.InfoFooterFrame)
self.frame_silent.setMinimumSize(QtCore.QSize(0, 112)) self.frame_silent.setMinimumSize(QtCore.QSize(152, 112))
self.frame_silent.setStyleSheet("") self.frame_silent.setStyleSheet("")
self.frame_silent.setFrameShape(QtWidgets.QFrame.Shape.StyledPanel) self.frame_silent.setFrameShape(QtWidgets.QFrame.Shape.StyledPanel)
self.frame_silent.setFrameShadow(QtWidgets.QFrame.Shadow.Raised) self.frame_silent.setFrameShadow(QtWidgets.QFrame.Shadow.Raised)
@ -329,7 +295,7 @@ class Ui_MainWindow(object):
self.verticalLayout_5.addWidget(self.label_silent_timer) self.verticalLayout_5.addWidget(self.label_silent_timer)
self.horizontalLayout.addWidget(self.frame_silent) self.horizontalLayout.addWidget(self.frame_silent)
self.frame_end = QtWidgets.QFrame(parent=self.InfoFooterFrame) self.frame_end = QtWidgets.QFrame(parent=self.InfoFooterFrame)
self.frame_end.setMinimumSize(QtCore.QSize(0, 112)) self.frame_end.setMinimumSize(QtCore.QSize(152, 112))
self.frame_end.setStyleSheet("") self.frame_end.setStyleSheet("")
self.frame_end.setFrameShape(QtWidgets.QFrame.Shape.StyledPanel) self.frame_end.setFrameShape(QtWidgets.QFrame.Shape.StyledPanel)
self.frame_end.setFrameShadow(QtWidgets.QFrame.Shadow.Raised) self.frame_end.setFrameShadow(QtWidgets.QFrame.Shadow.Raised)
@ -574,15 +540,7 @@ class Ui_MainWindow(object):
self.current_track_2.setText(_translate("MainWindow", "Current track:")) self.current_track_2.setText(_translate("MainWindow", "Current track:"))
self.next_track_2.setText(_translate("MainWindow", "Next track:")) self.next_track_2.setText(_translate("MainWindow", "Next track:"))
self.lblTOD.setText(_translate("MainWindow", "00:00:00")) self.lblTOD.setText(_translate("MainWindow", "00:00:00"))
self.label_7.setText(_translate("MainWindow", "Fade length:"))
self.label_x_2.setText(_translate("MainWindow", "Start:"))
self.btnFade.setText(_translate("MainWindow", " Fade")) self.btnFade.setText(_translate("MainWindow", " Fade"))
self.label_start_time.setText(_translate("MainWindow", "00:00:00"))
self.label_end_time.setText(_translate("MainWindow", "00:00:00"))
self.label_x.setText(_translate("MainWindow", "Track length:"))
self.label_fade_length.setText(_translate("MainWindow", "0:00"))
self.label_8.setText(_translate("MainWindow", "End:"))
self.label_track_length.setText(_translate("MainWindow", "0:00"))
self.btnPreview.setText(_translate("MainWindow", " Preview")) self.btnPreview.setText(_translate("MainWindow", " Preview"))
self.label.setText(_translate("MainWindow", "Elapsed time")) self.label.setText(_translate("MainWindow", "Elapsed time"))
self.label_elapsed_timer.setText(_translate("MainWindow", "00:00")) self.label_elapsed_timer.setText(_translate("MainWindow", "00:00"))
@ -664,3 +622,4 @@ class Ui_MainWindow(object):
self.actionSearch_title_in_Songfacts.setText(_translate("MainWindow", "Search title in Songfacts")) self.actionSearch_title_in_Songfacts.setText(_translate("MainWindow", "Search title in Songfacts"))
self.actionSearch_title_in_Songfacts.setShortcut(_translate("MainWindow", "Ctrl+S")) self.actionSearch_title_in_Songfacts.setShortcut(_translate("MainWindow", "Ctrl+S"))
from infotabs import InfoTabs from infotabs import InfoTabs
from pyqtgraph import PlotWidget

55
poetry.lock generated
View File

@ -631,6 +631,44 @@ files = [
{file = "mysqlclient-2.1.1.tar.gz", hash = "sha256:828757e419fb11dd6c5ed2576ec92c3efaa93a0f7c39e263586d1ee779c3d782"}, {file = "mysqlclient-2.1.1.tar.gz", hash = "sha256:828757e419fb11dd6c5ed2576ec92c3efaa93a0f7c39e263586d1ee779c3d782"},
] ]
[[package]]
name = "numpy"
version = "1.24.3"
description = "Fundamental package for array computing in Python"
category = "main"
optional = false
python-versions = ">=3.8"
files = [
{file = "numpy-1.24.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3c1104d3c036fb81ab923f507536daedc718d0ad5a8707c6061cdfd6d184e570"},
{file = "numpy-1.24.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:202de8f38fc4a45a3eea4b63e2f376e5f2dc64ef0fa692838e31a808520efaf7"},
{file = "numpy-1.24.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8535303847b89aa6b0f00aa1dc62867b5a32923e4d1681a35b5eef2d9591a463"},
{file = "numpy-1.24.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2d926b52ba1367f9acb76b0df6ed21f0b16a1ad87c6720a1121674e5cf63e2b6"},
{file = "numpy-1.24.3-cp310-cp310-win32.whl", hash = "sha256:f21c442fdd2805e91799fbe044a7b999b8571bb0ab0f7850d0cb9641a687092b"},
{file = "numpy-1.24.3-cp310-cp310-win_amd64.whl", hash = "sha256:ab5f23af8c16022663a652d3b25dcdc272ac3f83c3af4c02eb8b824e6b3ab9d7"},
{file = "numpy-1.24.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9a7721ec204d3a237225db3e194c25268faf92e19338a35f3a224469cb6039a3"},
{file = "numpy-1.24.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d6cc757de514c00b24ae8cf5c876af2a7c3df189028d68c0cb4eaa9cd5afc2bf"},
{file = "numpy-1.24.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76e3f4e85fc5d4fd311f6e9b794d0c00e7002ec122be271f2019d63376f1d385"},
{file = "numpy-1.24.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a1d3c026f57ceaad42f8231305d4653d5f05dc6332a730ae5c0bea3513de0950"},
{file = "numpy-1.24.3-cp311-cp311-win32.whl", hash = "sha256:c91c4afd8abc3908e00a44b2672718905b8611503f7ff87390cc0ac3423fb096"},
{file = "numpy-1.24.3-cp311-cp311-win_amd64.whl", hash = "sha256:5342cf6aad47943286afa6f1609cad9b4266a05e7f2ec408e2cf7aea7ff69d80"},
{file = "numpy-1.24.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7776ea65423ca6a15255ba1872d82d207bd1e09f6d0894ee4a64678dd2204078"},
{file = "numpy-1.24.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ae8d0be48d1b6ed82588934aaaa179875e7dc4f3d84da18d7eae6eb3f06c242c"},
{file = "numpy-1.24.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ecde0f8adef7dfdec993fd54b0f78183051b6580f606111a6d789cd14c61ea0c"},
{file = "numpy-1.24.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4749e053a29364d3452c034827102ee100986903263e89884922ef01a0a6fd2f"},
{file = "numpy-1.24.3-cp38-cp38-win32.whl", hash = "sha256:d933fabd8f6a319e8530d0de4fcc2e6a61917e0b0c271fded460032db42a0fe4"},
{file = "numpy-1.24.3-cp38-cp38-win_amd64.whl", hash = "sha256:56e48aec79ae238f6e4395886b5eaed058abb7231fb3361ddd7bfdf4eed54289"},
{file = "numpy-1.24.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4719d5aefb5189f50887773699eaf94e7d1e02bf36c1a9d353d9f46703758ca4"},
{file = "numpy-1.24.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0ec87a7084caa559c36e0a2309e4ecb1baa03b687201d0a847c8b0ed476a7187"},
{file = "numpy-1.24.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ea8282b9bcfe2b5e7d491d0bf7f3e2da29700cec05b49e64d6246923329f2b02"},
{file = "numpy-1.24.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:210461d87fb02a84ef243cac5e814aad2b7f4be953b32cb53327bb49fd77fbb4"},
{file = "numpy-1.24.3-cp39-cp39-win32.whl", hash = "sha256:784c6da1a07818491b0ffd63c6bbe5a33deaa0e25a20e1b3ea20cf0e43f8046c"},
{file = "numpy-1.24.3-cp39-cp39-win_amd64.whl", hash = "sha256:d5036197ecae68d7f491fcdb4df90082b0d4960ca6599ba2659957aafced7c17"},
{file = "numpy-1.24.3-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:352ee00c7f8387b44d19f4cada524586f07379c0d49270f87233983bc5087ca0"},
{file = "numpy-1.24.3-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1a7d6acc2e7524c9955e5c903160aa4ea083736fde7e91276b0e5d98e6332812"},
{file = "numpy-1.24.3-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:35400e6a8d102fd07c71ed7dcadd9eb62ee9a6e84ec159bd48c28235bbb0f8e4"},
{file = "numpy-1.24.3.tar.gz", hash = "sha256:ab344f1bf21f140adab8e47fdbc7c35a477dc01408791f8ba00d018dd0bc5155"},
]
[[package]] [[package]]
name = "obsws-python" name = "obsws-python"
version = "1.4.2" version = "1.4.2"
@ -1134,6 +1172,21 @@ files = [
{file = "PyQt6_WebEngine_Qt6-6.5.0-py3-none-win_amd64.whl", hash = "sha256:5acadcc6608df8d9eba385e04ced2fc88e7eb92e366556ee4ac3c57a02c00088"}, {file = "PyQt6_WebEngine_Qt6-6.5.0-py3-none-win_amd64.whl", hash = "sha256:5acadcc6608df8d9eba385e04ced2fc88e7eb92e366556ee4ac3c57a02c00088"},
] ]
[[package]]
name = "pyqtgraph"
version = "0.13.3"
description = "Scientific Graphics and GUI Library for Python"
category = "main"
optional = false
python-versions = ">=3.8"
files = [
{file = "pyqtgraph-0.13.3-py3-none-any.whl", hash = "sha256:fdcc04ac4b32a7bedf1bf3cf74cbb93ab3ba5687791712bbfa8d0712377d2f2b"},
{file = "pyqtgraph-0.13.3.tar.gz", hash = "sha256:58108d8411c7054e0841d8b791ee85e101fc296b9b359c0e01dde38a98ff2ace"},
]
[package.dependencies]
numpy = ">=1.20.0"
[[package]] [[package]]
name = "pyqtwebengine" name = "pyqtwebengine"
version = "5.15.6" version = "5.15.6"
@ -1606,4 +1659,4 @@ test = ["websockets"]
[metadata] [metadata]
lock-version = "2.0" lock-version = "2.0"
python-versions = "^3.9" python-versions = "^3.9"
content-hash = "5b335197cebe3355472e3d0024a978e4853efce33802008987351b5196d8746d" content-hash = "e195143fc7756994b10a3c4472a17f2288829ebd6a75ef75f6b683905cb8a543"

View File

@ -26,6 +26,7 @@ obsws-python = "^1.4.2"
pyqt6 = "^6.5.0" pyqt6 = "^6.5.0"
pyqt6-webengine = "^6.5.0" pyqt6-webengine = "^6.5.0"
pygame = "^2.4.0" pygame = "^2.4.0"
pyqtgraph = "^0.13.3"
[tool.poetry.dev-dependencies] [tool.poetry.dev-dependencies]
ipdb = "^0.13.9" ipdb = "^0.13.9"