Compare commits
32 Commits
dda74782b6
...
6bf9330b62
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6bf9330b62 | ||
|
|
f3631b2c2b | ||
|
|
3197c844a5 | ||
|
|
e22351386f | ||
|
|
ee422aacb3 | ||
|
|
380806d27a | ||
|
|
c6840d2356 | ||
|
|
453e42172b | ||
|
|
019bc87eb0 | ||
|
|
ee64a4a035 | ||
|
|
9c67b9bd8e | ||
|
|
3cc90f8c11 | ||
|
|
71daccab12 | ||
|
|
ca86f59736 | ||
|
|
d609656ae3 | ||
|
|
f96e02d9ae | ||
|
|
6c53d59f1a | ||
|
|
b9fd7a5d21 | ||
|
|
669125794f | ||
|
|
4094b63f44 | ||
|
|
b126a70139 | ||
|
|
f30fff5356 | ||
|
|
80e698680b | ||
|
|
39ec7f470b | ||
|
|
16ad7ae5aa | ||
|
|
d54f1bedda | ||
|
|
ad071bb74b | ||
|
|
2422adea21 | ||
|
|
ee7436221e | ||
|
|
889d32cc90 | ||
|
|
ae1835a421 | ||
|
|
8dd13a2ba2 |
@ -10,7 +10,6 @@ class Config(object):
|
|||||||
CART_DIRECTORY = "/home/kae/radio/CartTracks"
|
CART_DIRECTORY = "/home/kae/radio/CartTracks"
|
||||||
CARTS_COUNT = 10
|
CARTS_COUNT = 10
|
||||||
CARTS_HIDE = True
|
CARTS_HIDE = True
|
||||||
COLON_IN_PATH_FIX = True
|
|
||||||
COLOUR_BITRATE_LOW = "#ffcdd2"
|
COLOUR_BITRATE_LOW = "#ffcdd2"
|
||||||
COLOUR_BITRATE_MEDIUM = "#ffeb6f"
|
COLOUR_BITRATE_MEDIUM = "#ffeb6f"
|
||||||
COLOUR_BITRATE_OK = "#dcedc8"
|
COLOUR_BITRATE_OK = "#dcedc8"
|
||||||
@ -50,6 +49,7 @@ class Config(object):
|
|||||||
ERRORS_TO = ['kae@midnighthax.com']
|
ERRORS_TO = ['kae@midnighthax.com']
|
||||||
FADE_STEPS = 20
|
FADE_STEPS = 20
|
||||||
FADE_TIME = 3000
|
FADE_TIME = 3000
|
||||||
|
HIDE_AFTER_PLAYING_OFFSET = 5000
|
||||||
INFO_TAB_TITLE_LENGTH = 15
|
INFO_TAB_TITLE_LENGTH = 15
|
||||||
LAST_PLAYED_TODAY_STRING = "Today"
|
LAST_PLAYED_TODAY_STRING = "Today"
|
||||||
LOG_LEVEL_STDERR = logging.ERROR
|
LOG_LEVEL_STDERR = logging.ERROR
|
||||||
@ -67,6 +67,7 @@ class Config(object):
|
|||||||
MINIMUM_ROW_HEIGHT = 30
|
MINIMUM_ROW_HEIGHT = 30
|
||||||
MYSQL_CONNECT = os.environ.get('MYSQL_CONNECT') or "mysql+mysqldb://musicmuster:musicmuster@localhost/musicmuster_v2" # noqa E501
|
MYSQL_CONNECT = os.environ.get('MYSQL_CONNECT') or "mysql+mysqldb://musicmuster:musicmuster@localhost/musicmuster_v2" # noqa E501
|
||||||
NOTE_TIME_FORMAT = "%H:%M:%S"
|
NOTE_TIME_FORMAT = "%H:%M:%S"
|
||||||
|
PLAY_SETTLE = 500000
|
||||||
ROOT = os.environ.get('ROOT') or "/home/kae/music"
|
ROOT = os.environ.get('ROOT') or "/home/kae/music"
|
||||||
IMPORT_DESTINATION = os.path.join(ROOT, "Singles")
|
IMPORT_DESTINATION = os.path.join(ROOT, "Singles")
|
||||||
SCROLL_TOP_MARGIN = 3
|
SCROLL_TOP_MARGIN = 3
|
||||||
|
|||||||
@ -46,7 +46,10 @@ def Session() -> Generator[scoped_session, None, None]:
|
|||||||
lineno = frame.lineno
|
lineno = frame.lineno
|
||||||
Session = scoped_session(sessionmaker(bind=engine, future=True))
|
Session = scoped_session(sessionmaker(bind=engine, future=True))
|
||||||
log.debug(f"SqlA: session acquired [{hex(id(Session))}]")
|
log.debug(f"SqlA: session acquired [{hex(id(Session))}]")
|
||||||
log.debug(f"Session acquisition: {function}:{lineno} [{hex(id(Session))}]")
|
log.debug(
|
||||||
|
f"Session acquisition: {file}:{function}:{lineno} "
|
||||||
|
f"[{hex(id(Session))}]"
|
||||||
|
)
|
||||||
yield Session
|
yield Session
|
||||||
log.debug(f" SqlA: session released [{hex(id(Session))}]")
|
log.debug(f" SqlA: session released [{hex(id(Session))}]")
|
||||||
Session.commit()
|
Session.commit()
|
||||||
|
|||||||
@ -55,15 +55,15 @@ def fade_point(
|
|||||||
return int(trim_ms)
|
return int(trim_ms)
|
||||||
|
|
||||||
|
|
||||||
def file_is_readable(path: Optional[str]) -> bool:
|
def file_is_unreadable(path: Optional[str]) -> bool:
|
||||||
"""
|
"""
|
||||||
Returns True if passed path is readable, else False
|
Returns True if passed path is readable, else False
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if not path:
|
if not path:
|
||||||
return False
|
return True
|
||||||
|
|
||||||
return os.access(path, os.R_OK)
|
return not os.access(path, os.R_OK)
|
||||||
|
|
||||||
|
|
||||||
def get_audio_segment(path: str) -> Optional[AudioSegment]:
|
def get_audio_segment(path: str) -> Optional[AudioSegment]:
|
||||||
|
|||||||
@ -20,6 +20,7 @@ class InfoTabs(QTabWidget):
|
|||||||
# Dictionary to record when tabs were last updated (so we can
|
# Dictionary to record when tabs were last updated (so we can
|
||||||
# re-use the oldest one later)
|
# re-use the oldest one later)
|
||||||
self.last_update: Dict[QWebEngineView, datetime] = {}
|
self.last_update: Dict[QWebEngineView, datetime] = {}
|
||||||
|
self.tabtitles: Dict[int, str] = {}
|
||||||
|
|
||||||
def open_in_songfacts(self, title):
|
def open_in_songfacts(self, title):
|
||||||
"""Search Songfacts for title"""
|
"""Search Songfacts for title"""
|
||||||
@ -39,10 +40,19 @@ class InfoTabs(QTabWidget):
|
|||||||
|
|
||||||
def open_tab(self, url: str, title: str) -> None:
|
def open_tab(self, url: str, title: str) -> None:
|
||||||
"""
|
"""
|
||||||
Open passed URL. Create new tab if we're below the maximum
|
Open passed URL. If URL currently displayed, switch to that tab.
|
||||||
|
Create new tab if we're below the maximum
|
||||||
number otherwise reuse oldest content tab.
|
number otherwise reuse oldest content tab.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
if url in self.tabtitles.values():
|
||||||
|
self.setCurrentIndex(
|
||||||
|
list(self.tabtitles.keys())[
|
||||||
|
list(self.tabtitles.values()).index(url)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
short_title = title[:Config.INFO_TAB_TITLE_LENGTH]
|
short_title = title[:Config.INFO_TAB_TITLE_LENGTH]
|
||||||
|
|
||||||
if self.count() < Config.MAX_INFO_TABS:
|
if self.count() < Config.MAX_INFO_TABS:
|
||||||
@ -61,6 +71,7 @@ class InfoTabs(QTabWidget):
|
|||||||
|
|
||||||
widget.setUrl(QUrl(url))
|
widget.setUrl(QUrl(url))
|
||||||
self.last_update[widget] = datetime.now()
|
self.last_update[widget] = datetime.now()
|
||||||
|
self.tabtitles[tab_index] = url
|
||||||
|
|
||||||
# Show newly updated tab
|
# Show newly updated tab
|
||||||
self.setCurrentIndex(tab_index)
|
self.setCurrentIndex(tab_index)
|
||||||
|
|||||||
@ -75,7 +75,8 @@ def log_uncaught_exceptions(_ex_cls, ex, tb):
|
|||||||
print("\033[1;31;47m")
|
print("\033[1;31;47m")
|
||||||
logging.critical(''.join(traceback.format_tb(tb)))
|
logging.critical(''.join(traceback.format_tb(tb)))
|
||||||
print("\033[1;37;40m")
|
print("\033[1;37;40m")
|
||||||
print(stackprinter.format(ex, style="darkbg2", add_summary=True))
|
print(stackprinter.format(ex, show_vals="all", add_summary=True,
|
||||||
|
style="darkbg"))
|
||||||
if os.environ["MM_ENV"] == "PRODUCTION":
|
if os.environ["MM_ENV"] == "PRODUCTION":
|
||||||
msg = stackprinter.format(ex)
|
msg = stackprinter.format(ex)
|
||||||
send_mail(Config.ERRORS_TO, Config.ERRORS_FROM,
|
send_mail(Config.ERRORS_TO, Config.ERRORS_FROM,
|
||||||
|
|||||||
@ -98,13 +98,13 @@ class NoteColours(Base):
|
|||||||
)
|
)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_colour(session: scoped_session, text: str) -> str:
|
def get_colour(session: scoped_session, text: str) -> Optional[str]:
|
||||||
"""
|
"""
|
||||||
Parse text and return colour string if matched, else empty string
|
Parse text and return colour string if matched, else empty string
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if not text:
|
if not text:
|
||||||
return ""
|
return None
|
||||||
|
|
||||||
for rec in session.execute(
|
for rec in session.execute(
|
||||||
select(NoteColours)
|
select(NoteColours)
|
||||||
@ -126,7 +126,7 @@ class NoteColours(Base):
|
|||||||
if rec.substring.lower() in text.lower():
|
if rec.substring.lower() in text.lower():
|
||||||
return rec.colour
|
return rec.colour
|
||||||
|
|
||||||
return ""
|
return None
|
||||||
|
|
||||||
|
|
||||||
class Playdates(Base):
|
class Playdates(Base):
|
||||||
@ -464,26 +464,32 @@ class PlaylistRows(Base):
|
|||||||
session.commit()
|
session.commit()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_section_header_rows(cls, session: scoped_session,
|
def get_from_id_list(cls, session: scoped_session, playlist_id: int,
|
||||||
playlist_id: int) -> List["PlaylistRows"]:
|
plr_ids: List[int]) -> List["PlaylistRows"]:
|
||||||
"""
|
"""
|
||||||
Return a list of PlaylistRows that are section headers for this
|
Take a list of PlaylistRows ids and return a list of corresponding
|
||||||
playlist
|
PlaylistRows objects
|
||||||
"""
|
"""
|
||||||
|
|
||||||
plrs = session.execute(
|
plrs = session.execute(
|
||||||
select(cls)
|
select(cls)
|
||||||
.where(
|
.where(
|
||||||
cls.playlist_id == playlist_id,
|
cls.playlist_id == playlist_id,
|
||||||
cls.track_id.is_(None),
|
cls.id.in_(plr_ids)
|
||||||
(
|
|
||||||
cls.note.endswith("-") |
|
|
||||||
cls.note.endswith("+")
|
|
||||||
)
|
|
||||||
).order_by(cls.row_number)).scalars().all()
|
).order_by(cls.row_number)).scalars().all()
|
||||||
|
|
||||||
return plrs
|
return plrs
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_last_used_row(session: scoped_session,
|
||||||
|
playlist_id: int) -> Optional[int]:
|
||||||
|
"""Return the last used row for playlist, or None if no rows"""
|
||||||
|
|
||||||
|
return session.execute(
|
||||||
|
select(func.max(PlaylistRows.row_number))
|
||||||
|
.where(PlaylistRows.playlist_id == playlist_id)
|
||||||
|
).scalar_one()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_track_plr(session: scoped_session, track_id: int,
|
def get_track_plr(session: scoped_session, track_id: int,
|
||||||
playlist_id: int) -> Optional["PlaylistRows"]:
|
playlist_id: int) -> Optional["PlaylistRows"]:
|
||||||
@ -498,16 +504,6 @@ class PlaylistRows(Base):
|
|||||||
.limit(1)
|
.limit(1)
|
||||||
).first()
|
).first()
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_last_used_row(session: scoped_session,
|
|
||||||
playlist_id: int) -> Optional[int]:
|
|
||||||
"""Return the last used row for playlist, or None if no rows"""
|
|
||||||
|
|
||||||
return session.execute(
|
|
||||||
select(func.max(PlaylistRows.row_number))
|
|
||||||
.where(PlaylistRows.playlist_id == playlist_id)
|
|
||||||
).scalar_one()
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_played_rows(cls, session: scoped_session,
|
def get_played_rows(cls, session: scoped_session,
|
||||||
playlist_id: int) -> List["PlaylistRows"]:
|
playlist_id: int) -> List["PlaylistRows"]:
|
||||||
@ -572,27 +568,6 @@ class PlaylistRows(Base):
|
|||||||
|
|
||||||
return plrs
|
return plrs
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def indexed_by_id(session: scoped_session,
|
|
||||||
plr_ids: Union[Iterable[int], ValuesView]) -> dict:
|
|
||||||
"""
|
|
||||||
Return a dictionary of playlist_rows indexed by their plr id from
|
|
||||||
the passed plr_id list.
|
|
||||||
"""
|
|
||||||
|
|
||||||
plrs = session.execute(
|
|
||||||
select(PlaylistRows)
|
|
||||||
.where(
|
|
||||||
PlaylistRows.id.in_(plr_ids)
|
|
||||||
)
|
|
||||||
).scalars().all()
|
|
||||||
|
|
||||||
result = {}
|
|
||||||
for plr in plrs:
|
|
||||||
result[plr.id] = plr
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def move_rows_down(session: scoped_session, playlist_id: int,
|
def move_rows_down(session: scoped_session, playlist_id: int,
|
||||||
starting_row: int, move_by: int) -> None:
|
starting_row: int, move_by: int) -> None:
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import vlc # type: ignore
|
|||||||
#
|
#
|
||||||
from config import Config
|
from config import Config
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from helpers import file_is_readable
|
from helpers import file_is_unreadable
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
from time import sleep
|
from time import sleep
|
||||||
|
|
||||||
@ -101,17 +101,14 @@ class Music:
|
|||||||
Log and return if path not found.
|
Log and return if path not found.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if not file_is_readable(path):
|
if file_is_unreadable(path):
|
||||||
log.error(f"play({path}): path not readable")
|
log.error(f"play({path}): path not readable")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
status = -1
|
status = -1
|
||||||
|
|
||||||
if Config.COLON_IN_PATH_FIX:
|
|
||||||
media = self.VLC.media_new_path(path)
|
media = self.VLC.media_new_path(path)
|
||||||
self.player = media.player_new_from_media()
|
self.player = media.player_new_from_media()
|
||||||
else:
|
|
||||||
self.player = self.VLC.media_player_new(path)
|
|
||||||
if self.player:
|
if self.player:
|
||||||
self.player.audio_set_volume(self.max_volume)
|
self.player.audio_set_volume(self.max_volume)
|
||||||
status = self.player.play()
|
status = self.player.play()
|
||||||
|
|||||||
@ -257,7 +257,7 @@ class MusicMusterSignals(QObject):
|
|||||||
emit-a-signal-from-another-class-to-main-class
|
emit-a-signal-from-another-class-to-main-class
|
||||||
"""
|
"""
|
||||||
|
|
||||||
save_playlist_signal = pyqtSignal()
|
update_row_note_signal = pyqtSignal(int)
|
||||||
|
|
||||||
|
|
||||||
class Window(QMainWindow, Ui_MainWindow):
|
class Window(QMainWindow, Ui_MainWindow):
|
||||||
@ -314,7 +314,7 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
btn.setEnabled(False)
|
btn.setEnabled(False)
|
||||||
btn.pgb.setVisible(False)
|
btn.pgb.setVisible(False)
|
||||||
if cart.path:
|
if cart.path:
|
||||||
if helpers.file_is_readable(cart.path):
|
if not helpers.file_is_unreadable(cart.path):
|
||||||
colour = Config.COLOUR_CART_READY
|
colour = Config.COLOUR_CART_READY
|
||||||
btn.path = cart.path
|
btn.path = cart.path
|
||||||
btn.player = self.music.VLC.media_player_new(cart.path)
|
btn.player = self.music.VLC.media_player_new(cart.path)
|
||||||
@ -339,7 +339,7 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
if not isinstance(btn, CartButton):
|
if not isinstance(btn, CartButton):
|
||||||
return
|
return
|
||||||
|
|
||||||
if helpers.file_is_readable(btn.path):
|
if not helpers.file_is_unreadable(btn.path):
|
||||||
# Don't allow clicks while we're playing
|
# Don't allow clicks while we're playing
|
||||||
btn.setEnabled(False)
|
btn.setEnabled(False)
|
||||||
if not btn.player:
|
if not btn.player:
|
||||||
@ -377,7 +377,7 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
if not path:
|
if not path:
|
||||||
QMessageBox.warning(self, "Error", "Filename required")
|
QMessageBox.warning(self, "Error", "Filename required")
|
||||||
return
|
return
|
||||||
if cart.path and helpers.file_is_readable(cart.path):
|
if cart.path and not helpers.file_is_unreadable(cart.path):
|
||||||
tags = helpers.get_tags(cart.path)
|
tags = helpers.get_tags(cart.path)
|
||||||
cart.duration = tags['duration']
|
cart.duration = tags['duration']
|
||||||
|
|
||||||
@ -530,7 +530,7 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
|
|
||||||
# Attempt to close next track playlist
|
# Attempt to close next track playlist
|
||||||
if self.tabPlaylist.widget(tab_index) == self.next_track.playlist_tab:
|
if self.tabPlaylist.widget(tab_index) == self.next_track.playlist_tab:
|
||||||
self.next_track.playlist_tab.mark_unnext()
|
self.next_track.playlist_tab.clear_next()
|
||||||
|
|
||||||
# Record playlist as closed and update remaining playlist tabs
|
# Record playlist as closed and update remaining playlist tabs
|
||||||
with Session() as session:
|
with Session() as session:
|
||||||
@ -726,11 +726,9 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
|
|
||||||
Actions required:
|
Actions required:
|
||||||
- Set flag to say we're not playing a track
|
- Set flag to say we're not playing a track
|
||||||
- Reset current track
|
|
||||||
- Tell playlist_tab track has finished
|
- Tell playlist_tab track has finished
|
||||||
- Reset current playlist_tab
|
- Reset PlaylistTrack objects
|
||||||
- Reset clocks
|
- Reset clocks
|
||||||
- Reset end time
|
|
||||||
- Update headers
|
- Update headers
|
||||||
- Enable controls
|
- Enable controls
|
||||||
"""
|
"""
|
||||||
@ -739,7 +737,7 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
# doesn't see player=None and kick off end-of-track actions
|
# doesn't see player=None and kick off end-of-track actions
|
||||||
self.playing = False
|
self.playing = False
|
||||||
|
|
||||||
# Remove currently playing track colour
|
# Tell playlist_tab track has finished
|
||||||
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()
|
||||||
|
|
||||||
@ -868,11 +866,8 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
self.hide_played_tracks = True
|
self.hide_played_tracks = True
|
||||||
self.btnHidePlayed.setText("Show played")
|
self.btnHidePlayed.setText("Show played")
|
||||||
|
|
||||||
# Update all displayed playlists
|
# Update displayed playlist
|
||||||
with Session() as session:
|
self.visible_playlist_tab().hide_or_show_played_tracks()
|
||||||
for i in range(self.tabPlaylist.count()):
|
|
||||||
self.tabPlaylist.widget(i).hide_played_tracks(
|
|
||||||
self.hide_played_tracks)
|
|
||||||
|
|
||||||
def import_track(self) -> None:
|
def import_track(self) -> None:
|
||||||
"""Import track file"""
|
"""Import track file"""
|
||||||
@ -1271,7 +1266,7 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
self.current_track.playlist_tab != self.visible_playlist_tab()
|
self.current_track.playlist_tab != self.visible_playlist_tab()
|
||||||
and self.previous_track.plr_id
|
and self.previous_track.plr_id
|
||||||
):
|
):
|
||||||
self.previous_track.playlist_tab.reset_next()
|
self.previous_track.playlist_tab.clear_next()
|
||||||
|
|
||||||
# Update headers
|
# Update headers
|
||||||
self.update_headers()
|
self.update_headers()
|
||||||
@ -1517,8 +1512,8 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
# May also be called when last tab is closed
|
# May also be called when last tab is closed
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def this_is_the_next_playlist_row(self, session: scoped_session,
|
def this_is_the_next_playlist_row(
|
||||||
plr: PlaylistRows,
|
self, session: scoped_session, plr: PlaylistRows,
|
||||||
next_track_playlist_tab: PlaylistTab) -> None:
|
next_track_playlist_tab: PlaylistTab) -> None:
|
||||||
"""
|
"""
|
||||||
This is notification from a playlist tab that it holds the next
|
This is notification from a playlist tab that it holds the next
|
||||||
@ -1551,7 +1546,7 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
|
|
||||||
# Discard now-incorrect next_track PlaylistTrack and tell
|
# Discard now-incorrect next_track PlaylistTrack and tell
|
||||||
# playlist_tab too
|
# playlist_tab too
|
||||||
self.next_track.playlist_tab.reset_next()
|
self.next_track.playlist_tab.clear_next()
|
||||||
self.clear_next()
|
self.clear_next()
|
||||||
|
|
||||||
# Populate self.next_track
|
# Populate self.next_track
|
||||||
@ -1612,7 +1607,14 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
return
|
return
|
||||||
|
|
||||||
# If track is playing, update track clocks time and colours
|
# If track is playing, update track clocks time and colours
|
||||||
if self.music.player and self.music.player.is_playing():
|
# 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()
|
playtime = self.music.get_playtime()
|
||||||
time_to_fade = (self.current_track.fade_at - playtime)
|
time_to_fade = (self.current_track.fade_at - playtime)
|
||||||
time_to_silence = (
|
time_to_silence = (
|
||||||
@ -1812,8 +1814,10 @@ class DbDialog(QDialog):
|
|||||||
self.musicmuster.visible_playlist_tab().insert_header(
|
self.musicmuster.visible_playlist_tab().insert_header(
|
||||||
self.session, note=self.ui.txtNote.text())
|
self.session, note=self.ui.txtNote.text())
|
||||||
|
|
||||||
# Save to database (which will also commit changes)
|
# TODO: this shouldn't be needed as insert_track() saves
|
||||||
self.musicmuster.visible_playlist_tab().save_playlist(self.session)
|
# playlist
|
||||||
|
# # Save to database (which will also commit changes)
|
||||||
|
# self.musicmuster.visible_playlist_tab().save_playlist(self.session)
|
||||||
# Clear note field and select search text to make it easier for
|
# Clear note field and select search text to make it easier for
|
||||||
# next search
|
# next search
|
||||||
self.ui.txtNote.clear()
|
self.ui.txtNote.clear()
|
||||||
|
|||||||
885
app/playlists.py
885
app/playlists.py
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user