Remove rows from playlist works and db updates
This commit is contained in:
parent
35b101a538
commit
444c3e4fb4
@ -457,7 +457,7 @@ class PlaylistRows(Base):
|
|||||||
-> None:
|
-> None:
|
||||||
"""
|
"""
|
||||||
Delete rows in given playlist that have a higher row number
|
Delete rows in given playlist that have a higher row number
|
||||||
than 'row'
|
than 'maxrow'
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Log the rows to be deleted
|
# Log the rows to be deleted
|
||||||
@ -470,9 +470,7 @@ class PlaylistRows(Base):
|
|||||||
return
|
return
|
||||||
|
|
||||||
for row in rows_to_go:
|
for row in rows_to_go:
|
||||||
log.debug(f"Should delete: {row}")
|
session.delete(row)
|
||||||
# If needed later:
|
|
||||||
# session.delete(row)
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def delete_rows(session: Session, ids: List[int]) -> None:
|
def delete_rows(session: Session, ids: List[int]) -> None:
|
||||||
@ -617,23 +615,22 @@ class PlaylistRows(Base):
|
|||||||
)
|
)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def indexed_by_row(session: Session, playlist_id: int) -> dict:
|
def indexed_by_id(session: Session, plr_ids: List[int]) -> dict:
|
||||||
"""
|
"""
|
||||||
Return a dictionary of playlist_rows indexed by row number for
|
Return a dictionary of playlist_rows indexed by their plr id from
|
||||||
the passed playlist_id.
|
the passed plr_id list.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
plrs = session.execute(
|
plrs = session.execute(
|
||||||
select(PlaylistRows)
|
select(PlaylistRows)
|
||||||
.where(
|
.where(
|
||||||
PlaylistRows.playlist_id == playlist_id,
|
PlaylistRows.id.in_(plr_ids)
|
||||||
)
|
)
|
||||||
.order_by(PlaylistRows.row_number)
|
|
||||||
).scalars().all()
|
).scalars().all()
|
||||||
|
|
||||||
result = {}
|
result = {}
|
||||||
for plr in plrs:
|
for plr in plrs:
|
||||||
result[plr.row_number] = plr
|
result[plr.id] = plr
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|||||||
156
app/playlists.py
156
app/playlists.py
@ -822,22 +822,39 @@ class PlaylistTab(QTableWidget):
|
|||||||
|
|
||||||
def save_playlist(self, session: Session) -> None:
|
def save_playlist(self, session: Session) -> None:
|
||||||
"""
|
"""
|
||||||
All playlist rows have a PlaylistRows id. Check that that id points
|
Get the PlaylistRow objects for each row in the display. Correct
|
||||||
to this playlist (in case track has been moved from other) and that
|
the row_number and playlist_id if necessary. Remove any row
|
||||||
the row number is correct (in case tracks have been reordered).
|
numbers in the database that are higher than the last row in
|
||||||
|
the display.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
plr_dict = PlaylistRows.indexed_by_row(session, self.playlist_id)
|
# Build a dictionary of
|
||||||
|
# {display_row_number: display_row_plr_id}
|
||||||
|
display_plr_ids = {row_number: self._get_playlistrow_id(row_number)
|
||||||
|
for row_number in range(self.rowCount())}
|
||||||
|
|
||||||
|
# Now build a dictionary of
|
||||||
|
# {display_row_number: display_row_plr}
|
||||||
|
plr_dict_by_id = PlaylistRows.indexed_by_id(session,
|
||||||
|
display_plr_ids.values())
|
||||||
|
|
||||||
|
# Finally a dictionary of
|
||||||
|
# {display_row_number: plr}
|
||||||
|
row_plr = {row_number: plr_dict_by_id[display_plr_ids[row_number]]
|
||||||
|
for row_number in range(self.rowCount())}
|
||||||
|
|
||||||
|
# Ensure all row plrs have correct row number and playlist_id
|
||||||
for row in range(self.rowCount()):
|
for row in range(self.rowCount()):
|
||||||
# Set the row number and playlist id (even if correct)
|
row_plr[row].row_number = row
|
||||||
plr_dict[row].row_number = row
|
row_plr[row].playlist_id = self.playlist_id
|
||||||
plr_dict[row].playlist_id = self.playlist_id
|
|
||||||
|
|
||||||
# Any rows in the database with a row_number higher that the
|
# Any rows in the database with a row_number higher that the
|
||||||
# current value of 'row' should not be there. Commit session
|
# current value of 'row' should not be there. Commit session
|
||||||
# first to ensure any changes made above are committed.
|
# first to ensure any changes made above are committed.
|
||||||
session.commit()
|
session.commit()
|
||||||
PlaylistRows.delete_higher_rows(session, self.playlist_id, row)
|
PlaylistRows.delete_higher_rows(session, self.playlist_id,
|
||||||
|
self.rowCount() - 1)
|
||||||
|
session.commit()
|
||||||
|
|
||||||
def scroll_current_to_top(self) -> None:
|
def scroll_current_to_top(self) -> None:
|
||||||
"""Scroll currently-playing row to top"""
|
"""Scroll currently-playing row to top"""
|
||||||
@ -860,65 +877,6 @@ class PlaylistTab(QTableWidget):
|
|||||||
return
|
return
|
||||||
self._search(next=True)
|
self._search(next=True)
|
||||||
|
|
||||||
def _search(self, next: bool = True) -> None:
|
|
||||||
"""
|
|
||||||
Select next/previous row containg self.search_string. Start from
|
|
||||||
top selected row if there is one, else from top.
|
|
||||||
|
|
||||||
Wrap at last/first row.
|
|
||||||
"""
|
|
||||||
|
|
||||||
if not self.search_text:
|
|
||||||
return
|
|
||||||
|
|
||||||
selected_row = self._get_selected_row()
|
|
||||||
if next:
|
|
||||||
if selected_row is not None and selected_row < self.rowCount() - 1:
|
|
||||||
starting_row = selected_row + 1
|
|
||||||
else:
|
|
||||||
starting_row = 0
|
|
||||||
else:
|
|
||||||
if selected_row is not None and selected_row > 0:
|
|
||||||
starting_row = selected_row - 1
|
|
||||||
else:
|
|
||||||
starting_row = self.rowCount() - 1
|
|
||||||
|
|
||||||
wrapped = False
|
|
||||||
match_row = None
|
|
||||||
row = starting_row
|
|
||||||
needle = self.search_text.lower()
|
|
||||||
while True:
|
|
||||||
# Check for match in title, artist or notes
|
|
||||||
title = self._get_row_title(row)
|
|
||||||
if title and needle in title.lower():
|
|
||||||
match_row = row
|
|
||||||
break
|
|
||||||
artist = self._get_row_artist(row)
|
|
||||||
if artist and needle in artist.lower():
|
|
||||||
match_row = row
|
|
||||||
break
|
|
||||||
note = self._get_row_note(row)
|
|
||||||
if note and needle in note.lower():
|
|
||||||
match_row = row
|
|
||||||
break
|
|
||||||
if next:
|
|
||||||
row += 1
|
|
||||||
if wrapped and row >= starting_row:
|
|
||||||
break
|
|
||||||
if row >= self.rowCount():
|
|
||||||
row = 0
|
|
||||||
wrapped = True
|
|
||||||
else:
|
|
||||||
row -= 1
|
|
||||||
if wrapped and row <= starting_row:
|
|
||||||
break
|
|
||||||
if row < 0:
|
|
||||||
row = self.rowCount() - 1
|
|
||||||
wrapped = True
|
|
||||||
|
|
||||||
if match_row is not None:
|
|
||||||
self.selectRow(row)
|
|
||||||
|
|
||||||
def search_next(self) -> None:
|
def search_next(self) -> None:
|
||||||
"""
|
"""
|
||||||
Select next row containg self.search_string.
|
Select next row containg self.search_string.
|
||||||
@ -1541,11 +1499,6 @@ class PlaylistTab(QTableWidget):
|
|||||||
|
|
||||||
return self._meta_search(RowMeta.UNREADABLE, one=False)
|
return self._meta_search(RowMeta.UNREADABLE, one=False)
|
||||||
|
|
||||||
# def _header_click(self, index: int) -> None:
|
|
||||||
# """Handle playlist header click"""
|
|
||||||
|
|
||||||
# print(f"_header_click({index=})")
|
|
||||||
|
|
||||||
def _info_row(self, track_id: int) -> None:
|
def _info_row(self, track_id: int) -> None:
|
||||||
"""Display popup with info re row"""
|
"""Display popup with info re row"""
|
||||||
|
|
||||||
@ -1765,6 +1718,65 @@ class PlaylistTab(QTableWidget):
|
|||||||
scroll_item = self.item(top_row, 0)
|
scroll_item = self.item(top_row, 0)
|
||||||
self.scrollToItem(scroll_item, QAbstractItemView.PositionAtTop)
|
self.scrollToItem(scroll_item, QAbstractItemView.PositionAtTop)
|
||||||
|
|
||||||
|
def _search(self, next: bool = True) -> None:
|
||||||
|
"""
|
||||||
|
Select next/previous row containg self.search_string. Start from
|
||||||
|
top selected row if there is one, else from top.
|
||||||
|
|
||||||
|
Wrap at last/first row.
|
||||||
|
"""
|
||||||
|
|
||||||
|
if not self.search_text:
|
||||||
|
return
|
||||||
|
|
||||||
|
selected_row = self._get_selected_row()
|
||||||
|
if next:
|
||||||
|
if selected_row is not None and selected_row < self.rowCount() - 1:
|
||||||
|
starting_row = selected_row + 1
|
||||||
|
else:
|
||||||
|
starting_row = 0
|
||||||
|
else:
|
||||||
|
if selected_row is not None and selected_row > 0:
|
||||||
|
starting_row = selected_row - 1
|
||||||
|
else:
|
||||||
|
starting_row = self.rowCount() - 1
|
||||||
|
|
||||||
|
wrapped = False
|
||||||
|
match_row = None
|
||||||
|
row = starting_row
|
||||||
|
needle = self.search_text.lower()
|
||||||
|
while True:
|
||||||
|
# Check for match in title, artist or notes
|
||||||
|
title = self._get_row_title(row)
|
||||||
|
if title and needle in title.lower():
|
||||||
|
match_row = row
|
||||||
|
break
|
||||||
|
artist = self._get_row_artist(row)
|
||||||
|
if artist and needle in artist.lower():
|
||||||
|
match_row = row
|
||||||
|
break
|
||||||
|
note = self._get_row_note(row)
|
||||||
|
if note and needle in note.lower():
|
||||||
|
match_row = row
|
||||||
|
break
|
||||||
|
if next:
|
||||||
|
row += 1
|
||||||
|
if wrapped and row >= starting_row:
|
||||||
|
break
|
||||||
|
if row >= self.rowCount():
|
||||||
|
row = 0
|
||||||
|
wrapped = True
|
||||||
|
else:
|
||||||
|
row -= 1
|
||||||
|
if wrapped and row <= starting_row:
|
||||||
|
break
|
||||||
|
if row < 0:
|
||||||
|
row = self.rowCount() - 1
|
||||||
|
wrapped = True
|
||||||
|
|
||||||
|
if match_row is not None:
|
||||||
|
self.selectRow(row)
|
||||||
|
|
||||||
def _select_event(self) -> None:
|
def _select_event(self) -> None:
|
||||||
"""
|
"""
|
||||||
Called when item selection changes.
|
Called when item selection changes.
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user