Compare commits
No commits in common. "d4f542cc292d3519f58501c604064d7ebb272792" and "6336eb921511706e6980a0507a0c937cf6351ab0" have entirely different histories.
d4f542cc29
...
6336eb9215
@ -1,5 +1,4 @@
|
|||||||
from datetime import datetime
|
from datetime import datetime, date
|
||||||
from PyQt5.QtWidgets import QMessageBox
|
|
||||||
|
|
||||||
|
|
||||||
def get_relative_date(past_date, reference_date=None):
|
def get_relative_date(past_date, reference_date=None):
|
||||||
@ -37,12 +36,6 @@ def get_relative_date(past_date, reference_date=None):
|
|||||||
return f"{weeks} {weeks_str}, {days} {days_str} ago"
|
return f"{weeks} {weeks_str}, {days} {days_str} ago"
|
||||||
|
|
||||||
|
|
||||||
def show_warning(title, msg):
|
|
||||||
"Display a warning to user"
|
|
||||||
|
|
||||||
QMessageBox.warning(None, title, msg, buttons=QMessageBox.Cancel)
|
|
||||||
|
|
||||||
|
|
||||||
def ms_to_mmss(ms, decimals=0, negative=False):
|
def ms_to_mmss(ms, decimals=0, negative=False):
|
||||||
if not ms:
|
if not ms:
|
||||||
return "-"
|
return "-"
|
||||||
|
|||||||
116
app/model.py
116
app/model.py
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import sqlalchemy
|
import sqlalchemy
|
||||||
|
|
||||||
from datetime import datetime
|
from datetime import datetime, time
|
||||||
from sqlalchemy.ext.declarative import declarative_base
|
from sqlalchemy.ext.declarative import declarative_base
|
||||||
from sqlalchemy import (
|
from sqlalchemy import (
|
||||||
Boolean,
|
Boolean,
|
||||||
@ -53,8 +53,6 @@ class Notes(Base):
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def add_note(session, playlist_id, row, text):
|
def add_note(session, playlist_id, row, text):
|
||||||
"Add note"
|
|
||||||
|
|
||||||
DEBUG(f"add_note(playlist_id={playlist_id}, row={row}, text={text})")
|
DEBUG(f"add_note(playlist_id={playlist_id}, row={row}, text={text})")
|
||||||
note = Notes()
|
note = Notes()
|
||||||
note.playlist_id = playlist_id
|
note.playlist_id = playlist_id
|
||||||
@ -66,13 +64,16 @@ class Notes(Base):
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def delete_note(session, id):
|
def delete_note(session, id):
|
||||||
"Delete note"
|
|
||||||
|
|
||||||
DEBUG(f"delete_note(id={id}")
|
DEBUG(f"delete_note(id={id}")
|
||||||
|
|
||||||
session.query(Notes).filter(Notes.id == id).delete()
|
session.query(Notes).filter(Notes.id == id).delete()
|
||||||
session.commit()
|
session.commit()
|
||||||
|
|
||||||
|
# Not currently used 1 June 2021
|
||||||
|
# @staticmethod
|
||||||
|
# def get_note(session, id):
|
||||||
|
# return session.query(Notes).filter(Notes.id == id).one()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def update_note(cls, session, id, row, text=None):
|
def update_note(cls, session, id, row, text=None):
|
||||||
"""
|
"""
|
||||||
@ -98,8 +99,6 @@ class Playdates(Base):
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def add_playdate(session, track):
|
def add_playdate(session, track):
|
||||||
"Record that track was played"
|
|
||||||
|
|
||||||
DEBUG(f"add_playdate(track={track})")
|
DEBUG(f"add_playdate(track={track})")
|
||||||
pd = Playdates()
|
pd = Playdates()
|
||||||
pd.lastplayed = datetime.now()
|
pd.lastplayed = datetime.now()
|
||||||
@ -452,16 +451,6 @@ class Tracks(Base):
|
|||||||
f"<Track(id={self.id}, title={self.title}, "
|
f"<Track(id={self.id}, title={self.title}, "
|
||||||
f"artist={self.artist}, path={self.path}>"
|
f"artist={self.artist}, path={self.path}>"
|
||||||
)
|
)
|
||||||
# Not currently used 1 June 2021
|
|
||||||
# @staticmethod
|
|
||||||
# def get_note(session, id):
|
|
||||||
# return session.query(Notes).filter(Notes.id == id).one()
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_all_paths(session):
|
|
||||||
"Return a list of paths of all tracks"
|
|
||||||
|
|
||||||
return [a[0] for a in session.query(Tracks.path).all()]
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_or_create(cls, session, path):
|
def get_or_create(cls, session, path):
|
||||||
@ -483,6 +472,53 @@ class Tracks(Base):
|
|||||||
ERROR(f"Can't find track id {id}")
|
ERROR(f"Can't find track id {id}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_all_paths(session):
|
||||||
|
"Return a list of paths of all tracks"
|
||||||
|
|
||||||
|
return [a[0] for a in session.query(Tracks.path).all()]
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_path(session, id):
|
||||||
|
try:
|
||||||
|
return session.query(Tracks.path).filter(Tracks.id == id).one()[0]
|
||||||
|
except NoResultFound:
|
||||||
|
ERROR(f"Can't find track id {id}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_track(session, id):
|
||||||
|
try:
|
||||||
|
DEBUG(f"Tracks.get_track(track_id={id})")
|
||||||
|
track = session.query(Tracks).filter(Tracks.id == id).one()
|
||||||
|
return track
|
||||||
|
except NoResultFound:
|
||||||
|
ERROR(f"get_track({id}): not found")
|
||||||
|
return None
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def search(session, title=None, artist=None, duration=None):
|
||||||
|
"""
|
||||||
|
Return any tracks matching passed criteria
|
||||||
|
"""
|
||||||
|
|
||||||
|
DEBUG(
|
||||||
|
f"Tracks.search({title=}, {artist=}), {duration=})"
|
||||||
|
)
|
||||||
|
|
||||||
|
if not title and not artist and not duration:
|
||||||
|
return None
|
||||||
|
|
||||||
|
q = session.query(Tracks).filter(False)
|
||||||
|
if title:
|
||||||
|
q = q.filter(Tracks.title == title)
|
||||||
|
if artist:
|
||||||
|
q = q.filter(Tracks.artist == artist)
|
||||||
|
if duration:
|
||||||
|
q = q.filter(Tracks.duration == duration)
|
||||||
|
|
||||||
|
return q.all()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_track_from_filename(session, filename):
|
def get_track_from_filename(session, filename):
|
||||||
"""
|
"""
|
||||||
@ -510,29 +546,6 @@ class Tracks(Base):
|
|||||||
|
|
||||||
return session.query(Tracks).filter(Tracks.path == path).first()
|
return session.query(Tracks).filter(Tracks.path == path).first()
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_path(session, track_id):
|
|
||||||
"Return path of passed track_id, or None"
|
|
||||||
|
|
||||||
try:
|
|
||||||
return session.query(Tracks.path).filter(
|
|
||||||
Tracks.id == track_id).one()[0]
|
|
||||||
except NoResultFound:
|
|
||||||
ERROR(f"Can't find track id {track_id}")
|
|
||||||
return None
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_track(session, track_id):
|
|
||||||
"Return track or None"
|
|
||||||
|
|
||||||
try:
|
|
||||||
DEBUG(f"Tracks.get_track(track_id={track_id})")
|
|
||||||
track = session.query(Tracks).filter(Tracks.id == track_id).one()
|
|
||||||
return track
|
|
||||||
except NoResultFound:
|
|
||||||
ERROR(f"get_track({track_id}): not found")
|
|
||||||
return None
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def remove_path(session, path):
|
def remove_path(session, path):
|
||||||
"Remove track with passed path from database"
|
"Remove track with passed path from database"
|
||||||
@ -545,29 +558,6 @@ class Tracks(Base):
|
|||||||
except IntegrityError as exception:
|
except IntegrityError as exception:
|
||||||
ERROR(f"Can't remove track with {path=} ({exception=})")
|
ERROR(f"Can't remove track with {path=} ({exception=})")
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def search(session, title=None, artist=None, duration=None):
|
|
||||||
"""
|
|
||||||
Return any tracks matching passed criteria
|
|
||||||
"""
|
|
||||||
|
|
||||||
DEBUG(
|
|
||||||
f"Tracks.search({title=}, {artist=}), {duration=})"
|
|
||||||
)
|
|
||||||
|
|
||||||
if not title and not artist and not duration:
|
|
||||||
return None
|
|
||||||
|
|
||||||
q = session.query(Tracks).filter(False)
|
|
||||||
if title:
|
|
||||||
q = q.filter(Tracks.title == title)
|
|
||||||
if artist:
|
|
||||||
q = q.filter(Tracks.artist == artist)
|
|
||||||
if duration:
|
|
||||||
q = q.filter(Tracks.duration == duration)
|
|
||||||
|
|
||||||
return q.all()
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def search_titles(session, text):
|
def search_titles(session, text):
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import urllib.parse
|
|||||||
|
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from log import DEBUG, EXCEPTION
|
from log import DEBUG, EXCEPTION
|
||||||
|
from slugify import slugify
|
||||||
|
|
||||||
from PyQt5.QtCore import Qt, QTimer
|
from PyQt5.QtCore import Qt, QTimer
|
||||||
from PyQt5.QtWidgets import (
|
from PyQt5.QtWidgets import (
|
||||||
@ -17,6 +18,7 @@ from PyQt5.QtWidgets import (
|
|||||||
QInputDialog,
|
QInputDialog,
|
||||||
QListWidgetItem,
|
QListWidgetItem,
|
||||||
QMainWindow,
|
QMainWindow,
|
||||||
|
QMessageBox,
|
||||||
)
|
)
|
||||||
|
|
||||||
import helpers
|
import helpers
|
||||||
@ -137,10 +139,10 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
self.actionOpenPlaylist.triggered.connect(self.open_playlist)
|
self.actionOpenPlaylist.triggered.connect(self.open_playlist)
|
||||||
self.actionPlay_next.triggered.connect(self.play_next)
|
self.actionPlay_next.triggered.connect(self.play_next)
|
||||||
self.actionSearch_database.triggered.connect(self.search_database)
|
self.actionSearch_database.triggered.connect(self.search_database)
|
||||||
self.actionSelect_next_track.triggered.connect(self.select_next_row)
|
self.actionSelect_next_track.triggered.connect(self.select_next_track)
|
||||||
self.actionSelect_played_tracks.triggered.connect(self.select_played)
|
self.actionSelect_played_tracks.triggered.connect(self.select_played)
|
||||||
self.actionSelect_previous_track.triggered.connect(
|
self.actionSelect_previous_track.triggered.connect(
|
||||||
self.select_previous_row)
|
self.select_previous_track)
|
||||||
self.actionSelect_unplayed_tracks.triggered.connect(
|
self.actionSelect_unplayed_tracks.triggered.connect(
|
||||||
self.select_unplayed)
|
self.select_unplayed)
|
||||||
self.actionSetNext.triggered.connect(self.set_next_track)
|
self.actionSetNext.triggered.connect(self.set_next_track)
|
||||||
@ -222,10 +224,6 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
def end_of_track_actions(self):
|
def end_of_track_actions(self):
|
||||||
"Clean up after track played"
|
"Clean up after track played"
|
||||||
|
|
||||||
# Set self.playing to False so that tick() doesn't see
|
|
||||||
# player=None and kick off end-of-track actions
|
|
||||||
self.playing = False
|
|
||||||
|
|
||||||
# Clean up metadata
|
# Clean up metadata
|
||||||
self.previous_track = self.current_track
|
self.previous_track = self.current_track
|
||||||
if self.current_track_playlist_tab:
|
if self.current_track_playlist_tab:
|
||||||
@ -233,6 +231,7 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
self.current_track_playlist_tab.clear_current()
|
self.current_track_playlist_tab.clear_current()
|
||||||
self.current_track_playlist_tab = None
|
self.current_track_playlist_tab = None
|
||||||
self.current_track = None
|
self.current_track = None
|
||||||
|
self.playing = False
|
||||||
|
|
||||||
# Clean up display
|
# Clean up display
|
||||||
self.label_end_timer.setText("00:00")
|
self.label_end_timer.setText("00:00")
|
||||||
@ -240,9 +239,6 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
self.frame_fade.setStyleSheet("")
|
self.frame_fade.setStyleSheet("")
|
||||||
self.update_headers()
|
self.update_headers()
|
||||||
|
|
||||||
# Enable controls
|
|
||||||
self.enable_play_next_controls()
|
|
||||||
|
|
||||||
def export_playlist_tab(self):
|
def export_playlist_tab(self):
|
||||||
"Export the current playlist to an m3u file"
|
"Export the current playlist to an m3u file"
|
||||||
|
|
||||||
@ -289,6 +285,10 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
if not self.current_track:
|
if not self.current_track:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# Set self.playing to False so that tick() doesn't see
|
||||||
|
# player=None and kick off end-of-track actions
|
||||||
|
self.playing = False
|
||||||
|
self.enable_play_next_controls()
|
||||||
self.previous_track_position = self.music.fade()
|
self.previous_track_position = self.music.fade()
|
||||||
self.end_of_track_actions()
|
self.end_of_track_actions()
|
||||||
|
|
||||||
@ -415,15 +415,17 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
self.music.play(self.current_track.path)
|
self.music.play(self.current_track.path)
|
||||||
|
|
||||||
# Update metadata
|
# Update metadata
|
||||||
# Get next track for this playlist. May be None if there is
|
# TODO is this valid if next track is on different playlist?
|
||||||
# no automatic next track, and may later be overriden by
|
|
||||||
# user selecting a different track on this or another
|
|
||||||
# playlist.
|
|
||||||
next_track_id = self.current_track_playlist_tab.play_started()
|
next_track_id = self.current_track_playlist_tab.play_started()
|
||||||
|
|
||||||
if next_track_id is not None:
|
if next_track_id is not None:
|
||||||
self.next_track = Tracks.get_track(session, next_track_id)
|
self.next_track = Tracks.get_track(session, next_track_id)
|
||||||
self.next_track_playlist_tab = self.current_track_playlist_tab
|
self.next_track_playlist_tab = self.current_track_playlist_tab
|
||||||
|
# Check we can read it
|
||||||
|
if not self.file_is_readable(self.next_track.path):
|
||||||
|
self.show_warning(
|
||||||
|
"Can't read next track",
|
||||||
|
self.next_track.path)
|
||||||
else:
|
else:
|
||||||
self.next_track = self.next_track_playlist_tab = None
|
self.next_track = self.next_track_playlist_tab = None
|
||||||
|
|
||||||
@ -464,20 +466,20 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
playlist_db = Playlists.open(session, dlg.plid)
|
playlist_db = Playlists.open(session, dlg.plid)
|
||||||
self.load_playlist(session, playlist_db)
|
self.load_playlist(session, playlist_db)
|
||||||
|
|
||||||
def select_next_row(self):
|
def select_next_track(self):
|
||||||
"Select next or first row in playlist"
|
"Select next or first track in playlist"
|
||||||
|
|
||||||
self.visible_playlist_tab().select_next_row()
|
self.visible_playlist_tab().select_next_track()
|
||||||
|
|
||||||
def select_played(self):
|
def select_played(self):
|
||||||
"Select all played tracks in playlist"
|
"Select all played tracks in playlist"
|
||||||
|
|
||||||
self.visible_playlist_tab().select_played_tracks()
|
self.visible_playlist_tab().select_played_tracks()
|
||||||
|
|
||||||
def select_previous_row(self):
|
def select_previous_track(self):
|
||||||
"Select previous or first row in playlist"
|
"Select previous or first track in playlist"
|
||||||
|
|
||||||
self.visible_playlist_tab().select_previous_row()
|
self.visible_playlist_tab().select_previous_track()
|
||||||
|
|
||||||
def set_next_track(self, next_track_id=None):
|
def set_next_track(self, next_track_id=None):
|
||||||
"Set selected track as next"
|
"Set selected track as next"
|
||||||
@ -499,6 +501,11 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
|
|
||||||
self.visible_playlist_tab().select_unplayed_tracks()
|
self.visible_playlist_tab().select_unplayed_tracks()
|
||||||
|
|
||||||
|
def show_warning(self, title, msg):
|
||||||
|
"Display a warning to user"
|
||||||
|
|
||||||
|
QMessageBox.warning(None, title, msg, buttons=QMessageBox.Cancel)
|
||||||
|
|
||||||
def song_info_search(self):
|
def song_info_search(self):
|
||||||
"""
|
"""
|
||||||
Open browser tabs for Wikipedia, searching for
|
Open browser tabs for Wikipedia, searching for
|
||||||
@ -527,11 +534,12 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
DEBUG("musicmuster.stop()")
|
DEBUG("musicmuster.stop()")
|
||||||
|
|
||||||
self.stop_playing(fade=False)
|
self.stop_playing(fade=False)
|
||||||
|
self.enable_play_next_controls()
|
||||||
|
|
||||||
def stop_playing(self, fade=True):
|
def stop_playing(self, fade=True):
|
||||||
"Stop playing current track"
|
"Stop playing current track"
|
||||||
|
|
||||||
DEBUG(f"musicmuster.stop_playing({fade=})", True)
|
DEBUG("musicmuster.stop_playing()", True)
|
||||||
|
|
||||||
if not self.music.playing():
|
if not self.music.playing():
|
||||||
DEBUG("musicmuster.stop_playing(): not playing", True)
|
DEBUG("musicmuster.stop_playing(): not playing", True)
|
||||||
@ -543,8 +551,8 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
DEBUG("musicmuster.stop_playing(): fading music", True)
|
DEBUG("musicmuster.stop_playing(): fading music", True)
|
||||||
self.music.fade()
|
self.music.fade()
|
||||||
else:
|
else:
|
||||||
DEBUG("musicmuster.stop_playing(): stopping music", True)
|
|
||||||
self.music.stop()
|
self.music.stop()
|
||||||
|
DEBUG("musicmuster.stop_playing(): stopping music", True)
|
||||||
|
|
||||||
self.end_of_track_actions()
|
self.end_of_track_actions()
|
||||||
|
|
||||||
@ -612,20 +620,16 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
# Time to fade
|
# Time to fade
|
||||||
self.label_fade_timer.setText(helpers.ms_to_mmss(time_to_fade))
|
self.label_fade_timer.setText(helpers.ms_to_mmss(time_to_fade))
|
||||||
|
|
||||||
# If silent in the next 5 seconds, put warning colour on
|
# Time to silence
|
||||||
# time to silence box and enable play controls
|
|
||||||
if time_to_silence <= 5500:
|
if time_to_silence <= 5500:
|
||||||
self.frame_silent.setStyleSheet(
|
self.frame_silent.setStyleSheet(
|
||||||
f"background: {Config.COLOUR_ENDING_TIMER}"
|
f"background: {Config.COLOUR_ENDING_TIMER}"
|
||||||
)
|
)
|
||||||
self.enable_play_next_controls()
|
self.enable_play_next_controls()
|
||||||
# Set warning colour on time to silence box when fade starts
|
|
||||||
elif time_to_fade <= 500:
|
elif time_to_fade <= 500:
|
||||||
self.frame_silent.setStyleSheet(
|
self.frame_silent.setStyleSheet(
|
||||||
f"background: {Config.COLOUR_WARNING_TIMER}"
|
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:
|
elif time_to_fade <= 5500:
|
||||||
self.frame_fade.setStyleSheet(
|
self.frame_fade.setStyleSheet(
|
||||||
f"background: {Config.COLOUR_WARNING_TIMER}"
|
f"background: {Config.COLOUR_WARNING_TIMER}"
|
||||||
|
|||||||
@ -16,7 +16,7 @@ import os
|
|||||||
|
|
||||||
from config import Config
|
from config import Config
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from helpers import get_relative_date, show_warning
|
from helpers import get_relative_date
|
||||||
from log import DEBUG, ERROR
|
from log import DEBUG, ERROR
|
||||||
from model import (
|
from model import (
|
||||||
Notes, Playdates, Playlists, PlaylistTracks, Session, Settings, Tracks
|
Notes, Playdates, Playlists, PlaylistTracks, Session, Settings, Tracks
|
||||||
@ -155,8 +155,8 @@ class PlaylistTab(QTableWidget):
|
|||||||
self.menu.addSeparator()
|
self.menu.addSeparator()
|
||||||
act_delete = self.menu.addAction('Delete')
|
act_delete = self.menu.addAction('Delete')
|
||||||
act_delete.triggered.connect(lambda: self._delete_row(row))
|
act_delete.triggered.connect(lambda: self._delete_row(row))
|
||||||
act_info = self.menu.addAction('Info')
|
act_delete = self.menu.addAction('Info')
|
||||||
act_info.triggered.connect(lambda: self._info_row(row))
|
act_delete.triggered.connect(lambda: self._info_row(row))
|
||||||
|
|
||||||
return super(PlaylistTab, self).eventFilter(source, event)
|
return super(PlaylistTab, self).eventFilter(source, event)
|
||||||
|
|
||||||
@ -357,10 +357,7 @@ class PlaylistTab(QTableWidget):
|
|||||||
# Scroll to put current track in centre
|
# Scroll to put current track in centre
|
||||||
scroll_to = self.item(current_row, self.COL_INDEX)
|
scroll_to = self.item(current_row, self.COL_INDEX)
|
||||||
self.scrollToItem(scroll_to, QAbstractItemView.PositionAtCenter)
|
self.scrollToItem(scroll_to, QAbstractItemView.PositionAtCenter)
|
||||||
|
next_track_id = self._mark_next_track()
|
||||||
# Get next track
|
|
||||||
next_track_row = self._find_next_track_row()
|
|
||||||
next_track_id = self._set_next(next_track_row)
|
|
||||||
self._repaint()
|
self._repaint()
|
||||||
return next_track_id
|
return next_track_id
|
||||||
|
|
||||||
@ -410,9 +407,9 @@ class PlaylistTab(QTableWidget):
|
|||||||
# Called when we change tabs
|
# Called when we change tabs
|
||||||
self._repaint()
|
self._repaint()
|
||||||
|
|
||||||
def select_next_row(self):
|
def select_next_track(self):
|
||||||
"""
|
"""
|
||||||
Select next or first row. Don't select notes. Wrap at last row.
|
Select next or first track. Don't select notes. Wrap at last row.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
selected_rows = [row for row in
|
selected_rows = [row for row in
|
||||||
@ -457,7 +454,7 @@ class PlaylistTab(QTableWidget):
|
|||||||
# Reset extended selection
|
# Reset extended selection
|
||||||
self.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
|
self.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
|
||||||
|
|
||||||
def select_previous_row(self):
|
def select_previous_track(self):
|
||||||
"""
|
"""
|
||||||
Select previous or last track. Don't select notes. Wrap at first row.
|
Select previous or last track. Don't select notes. Wrap at first row.
|
||||||
"""
|
"""
|
||||||
@ -517,8 +514,7 @@ class PlaylistTab(QTableWidget):
|
|||||||
if not self.selectionModel().hasSelection():
|
if not self.selectionModel().hasSelection():
|
||||||
return
|
return
|
||||||
|
|
||||||
self._set_next(self.currentRow())
|
return self._set_next(self.currentRow())
|
||||||
self._repaint()
|
|
||||||
|
|
||||||
# ########## Internally called functions ##########
|
# ########## Internally called functions ##########
|
||||||
|
|
||||||
@ -549,10 +545,12 @@ class PlaylistTab(QTableWidget):
|
|||||||
DEBUG(f"playlist._delete_row({row})")
|
DEBUG(f"playlist._delete_row({row})")
|
||||||
|
|
||||||
if row == self._meta_get_current():
|
if row == self._meta_get_current():
|
||||||
show_warning("Silly", "Can't delete playing track")
|
# TODO
|
||||||
|
DEBUG("playlist._delete_row(): Can't delete playing track")
|
||||||
return
|
return
|
||||||
elif row == self._meta_get_next():
|
elif row == self._meta_get_next():
|
||||||
show_warning("Safety", "Can't delete next track")
|
# TODO
|
||||||
|
DEBUG("playlist._delete_row(): Can't delete next track")
|
||||||
return
|
return
|
||||||
|
|
||||||
with Session() as session:
|
with Session() as session:
|
||||||
@ -650,13 +648,13 @@ class PlaylistTab(QTableWidget):
|
|||||||
and pos.y() >= rect.center().y() # noqa W503
|
and pos.y() >= rect.center().y() # noqa W503
|
||||||
)
|
)
|
||||||
|
|
||||||
def _find_next_track_row(self):
|
def _mark_next_track(self):
|
||||||
"""
|
"""
|
||||||
Find next track to play.
|
Find next track to play.
|
||||||
|
|
||||||
If not found, return None.
|
If not found, return None.
|
||||||
|
|
||||||
If found, return row number.
|
If found, mark row with metadata and return track_id.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
found_next_track = False
|
found_next_track = False
|
||||||
@ -669,14 +667,16 @@ class PlaylistTab(QTableWidget):
|
|||||||
for row in range(start, self.rowCount()):
|
for row in range(start, self.rowCount()):
|
||||||
if row in notes_rows:
|
if row in notes_rows:
|
||||||
continue
|
continue
|
||||||
|
self._meta_set_next(row)
|
||||||
found_next_track = True
|
found_next_track = True
|
||||||
break
|
break
|
||||||
|
|
||||||
if found_next_track:
|
if not found_next_track:
|
||||||
return row
|
|
||||||
else:
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
track_id = self._get_row_id(row)
|
||||||
|
return track_id
|
||||||
|
|
||||||
def _meta_clear(self, row):
|
def _meta_clear(self, row):
|
||||||
"Clear metadata for row"
|
"Clear metadata for row"
|
||||||
|
|
||||||
@ -813,12 +813,11 @@ class PlaylistTab(QTableWidget):
|
|||||||
track_id = self._get_row_id(row)
|
track_id = self._get_row_id(row)
|
||||||
if track_id:
|
if track_id:
|
||||||
if self._track_path_is_readable(track_id):
|
if self._track_path_is_readable(track_id):
|
||||||
self._meta_set_next(row)
|
self._meta_set_next(self.currentRow())
|
||||||
self.master_process.set_next_track(track_id)
|
self.master_process.set_next_track(track_id)
|
||||||
else:
|
else:
|
||||||
self._meta_set_unreadable(row)
|
self._meta_set_unreadable(self.currentRow())
|
||||||
track_id = None
|
self._repaint()
|
||||||
return track_id
|
|
||||||
|
|
||||||
def _repaint(self, clear_selection=True):
|
def _repaint(self, clear_selection=True):
|
||||||
"Set row colours, fonts, etc"
|
"Set row colours, fonts, etc"
|
||||||
|
|||||||
@ -31,15 +31,12 @@ def fade_point(audio_segment, fade_threshold=-12, chunk_size=10):
|
|||||||
print(f"Fade last {int(segment_length - trim_ms)/1000} seconds")
|
print(f"Fade last {int(segment_length - trim_ms)/1000} seconds")
|
||||||
|
|
||||||
|
|
||||||
# print("Shout:")
|
print("Shout:")
|
||||||
# segment = AudioSegment.from_mp3("../archive/shout.mp3")
|
segment = AudioSegment.from_mp3("../archive/shout.mp3")
|
||||||
# fade_point(segment)
|
fade_point(segment)
|
||||||
# print("Champagne:")
|
print("Champagne:")
|
||||||
# segment = AudioSegment.from_mp3("../archive/champ.mp3")
|
segment = AudioSegment.from_mp3("../archive/champ.mp3")
|
||||||
# fade_point(segment)
|
fade_point(segment)
|
||||||
# print("Be good:")
|
print("Be good:")
|
||||||
# segment = AudioSegment.from_mp3("../archive/wibg.mp3")
|
segment = AudioSegment.from_mp3("../archive/wibg.mp3")
|
||||||
# fade_point(segment)
|
|
||||||
print("Be good:")
|
|
||||||
segment = AudioSegment.from_file("/tmp/bia.flac", "flac")
|
|
||||||
fade_point(segment)
|
fade_point(segment)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user