Optionally remove header colour directives from header
This commit is contained in:
parent
f7f4cdc622
commit
0391eed88e
@ -34,6 +34,7 @@ class NoteColoursTable(Model):
|
|||||||
is_regex: Mapped[bool] = mapped_column(default=False, index=False)
|
is_regex: Mapped[bool] = mapped_column(default=False, index=False)
|
||||||
is_casesensitive: Mapped[bool] = mapped_column(default=False, index=False)
|
is_casesensitive: Mapped[bool] = mapped_column(default=False, index=False)
|
||||||
order: Mapped[Optional[int]] = mapped_column(index=True)
|
order: Mapped[Optional[int]] = mapped_column(index=True)
|
||||||
|
strip_substring: Mapped[bool] = mapped_column(default=True, index=False)
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -333,6 +333,32 @@ def normalise_track(path: str) -> None:
|
|||||||
os.remove(temp_path)
|
os.remove(temp_path)
|
||||||
|
|
||||||
|
|
||||||
|
def remove_substring_case_insensitive(parent_string: str, substring: str) -> str:
|
||||||
|
"""
|
||||||
|
Remove all instances of substring from parent string, case insensitively
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Convert both strings to lowercase for case-insensitive comparison
|
||||||
|
lower_parent = parent_string.lower()
|
||||||
|
lower_substring = substring.lower()
|
||||||
|
|
||||||
|
# Initialize the result string
|
||||||
|
result = parent_string
|
||||||
|
|
||||||
|
# Continue removing the substring until it's no longer found
|
||||||
|
while lower_substring in lower_parent:
|
||||||
|
# Find the index of the substring
|
||||||
|
index = lower_parent.find(lower_substring)
|
||||||
|
|
||||||
|
# Remove the substring
|
||||||
|
result = result[:index] + result[index + len(substring):]
|
||||||
|
|
||||||
|
# Update the lowercase versions
|
||||||
|
lower_parent = result.lower()
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
def send_mail(to_addr: str, from_addr: str, subj: str, body: str) -> None:
|
def send_mail(to_addr: str, from_addr: str, subj: str, body: str) -> None:
|
||||||
# From https://docs.python.org/3/library/email.examples.html
|
# From https://docs.python.org/3/library/email.examples.html
|
||||||
|
|
||||||
|
|||||||
@ -22,9 +22,9 @@ from sqlalchemy.orm import joinedload
|
|||||||
from sqlalchemy.orm.session import Session
|
from sqlalchemy.orm.session import Session
|
||||||
|
|
||||||
# App imports
|
# App imports
|
||||||
|
from config import Config
|
||||||
from dbmanager import DatabaseManager
|
from dbmanager import DatabaseManager
|
||||||
import dbtables
|
import dbtables
|
||||||
from config import Config
|
|
||||||
from log import log
|
from log import log
|
||||||
|
|
||||||
|
|
||||||
@ -83,7 +83,9 @@ class NoteColours(dbtables.NoteColoursTable):
|
|||||||
match = False
|
match = False
|
||||||
for rec in session.scalars(
|
for rec in session.scalars(
|
||||||
select(NoteColours)
|
select(NoteColours)
|
||||||
.filter(NoteColours.enabled.is_(True))
|
.where(
|
||||||
|
NoteColours.enabled.is_(True),
|
||||||
|
)
|
||||||
.order_by(NoteColours.order)
|
.order_by(NoteColours.order)
|
||||||
).all():
|
).all():
|
||||||
if rec.is_regex:
|
if rec.is_regex:
|
||||||
|
|||||||
@ -45,6 +45,7 @@ from helpers import (
|
|||||||
get_embedded_time,
|
get_embedded_time,
|
||||||
get_relative_date,
|
get_relative_date,
|
||||||
ms_to_mmss,
|
ms_to_mmss,
|
||||||
|
remove_substring_case_insensitive,
|
||||||
set_track_metadata,
|
set_track_metadata,
|
||||||
)
|
)
|
||||||
from log import log
|
from log import log
|
||||||
@ -452,7 +453,9 @@ class PlaylistModel(QAbstractTableModel):
|
|||||||
|
|
||||||
if self.is_header_row(row):
|
if self.is_header_row(row):
|
||||||
with db.Session() as session:
|
with db.Session() as session:
|
||||||
note_foreground = NoteColours.get_colour(session, rat.note, foreground=True)
|
note_foreground = NoteColours.get_colour(
|
||||||
|
session, rat.note, foreground=True
|
||||||
|
)
|
||||||
if note_foreground:
|
if note_foreground:
|
||||||
return QBrush(QColor(note_foreground))
|
return QBrush(QColor(note_foreground))
|
||||||
|
|
||||||
@ -738,6 +741,36 @@ class PlaylistModel(QAbstractTableModel):
|
|||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def load_data(
|
||||||
|
self, session: db.session, dummy_for_profiling: Optional[int] = None
|
||||||
|
) -> None:
|
||||||
|
"""
|
||||||
|
Same as refresh data, but only used when creating playslit.
|
||||||
|
Distinguishes profile time between initial load and other
|
||||||
|
refreshes.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# We used to clear self.playlist_rows each time but that's
|
||||||
|
# expensive and slow on big playlists
|
||||||
|
|
||||||
|
# Note where each playlist_id is
|
||||||
|
plid_to_row: dict[int, int] = {}
|
||||||
|
for oldrow in self.playlist_rows:
|
||||||
|
plrdata = self.playlist_rows[oldrow]
|
||||||
|
plid_to_row[plrdata.playlistrow_id] = plrdata.row_number
|
||||||
|
|
||||||
|
# build a new playlist_rows
|
||||||
|
new_playlist_rows: dict[int, RowAndTrack] = {}
|
||||||
|
for p in PlaylistRows.get_playlist_rows(session, self.playlist_id):
|
||||||
|
if p.id not in plid_to_row:
|
||||||
|
new_playlist_rows[p.row_number] = RowAndTrack(p)
|
||||||
|
else:
|
||||||
|
new_playlist_rows[p.row_number] = self.playlist_rows[plid_to_row[p.id]]
|
||||||
|
new_playlist_rows[p.row_number].row_number = p.row_number
|
||||||
|
|
||||||
|
# Copy to self.playlist_rows
|
||||||
|
self.playlist_rows = new_playlist_rows
|
||||||
|
|
||||||
def mark_unplayed(self, row_numbers: list[int]) -> None:
|
def mark_unplayed(self, row_numbers: list[int]) -> None:
|
||||||
"""
|
"""
|
||||||
Mark row as unplayed
|
Mark row as unplayed
|
||||||
@ -1007,7 +1040,9 @@ class PlaylistModel(QAbstractTableModel):
|
|||||||
self.invalidate_row(track_sequence.previous.row_number)
|
self.invalidate_row(track_sequence.previous.row_number)
|
||||||
|
|
||||||
@line_profiler.profile
|
@line_profiler.profile
|
||||||
def refresh_data(self, session: db.session, dummy_for_profiling=None) -> None:
|
def refresh_data(
|
||||||
|
self, session: db.session, dummy_for_profiling: Optional[int] = None
|
||||||
|
) -> None:
|
||||||
"""
|
"""
|
||||||
Populate self.playlist_rows with playlist data
|
Populate self.playlist_rows with playlist data
|
||||||
|
|
||||||
@ -1037,66 +1072,6 @@ class PlaylistModel(QAbstractTableModel):
|
|||||||
# Copy to self.playlist_rows
|
# Copy to self.playlist_rows
|
||||||
self.playlist_rows = new_playlist_rows
|
self.playlist_rows = new_playlist_rows
|
||||||
|
|
||||||
# Same as refresh data, but only used when creating playslit.
|
|
||||||
# Distinguishes profile time between initial load and other
|
|
||||||
# refreshes.
|
|
||||||
def load_data(
|
|
||||||
self, session: db.session, dummy_for_profiling: Optional[int] = None
|
|
||||||
) -> None:
|
|
||||||
"""Populate self.playlist_rows with playlist data"""
|
|
||||||
|
|
||||||
# Same as refresh data, but only used when creating playslit.
|
|
||||||
# Distinguishes profile time between initial load and other
|
|
||||||
# refreshes.
|
|
||||||
|
|
||||||
# We used to clear self.playlist_rows each time but that's
|
|
||||||
# expensive and slow on big playlists
|
|
||||||
|
|
||||||
# Note where each playlist_id is
|
|
||||||
plid_to_row: dict[int, int] = {}
|
|
||||||
for oldrow in self.playlist_rows:
|
|
||||||
plrdata = self.playlist_rows[oldrow]
|
|
||||||
plid_to_row[plrdata.playlistrow_id] = plrdata.row_number
|
|
||||||
|
|
||||||
# build a new playlist_rows
|
|
||||||
new_playlist_rows: dict[int, RowAndTrack] = {}
|
|
||||||
for p in PlaylistRows.get_playlist_rows(session, self.playlist_id):
|
|
||||||
if p.id not in plid_to_row:
|
|
||||||
new_playlist_rows[p.row_number] = RowAndTrack(p)
|
|
||||||
else:
|
|
||||||
new_playlist_rows[p.row_number] = self.playlist_rows[plid_to_row[p.id]]
|
|
||||||
new_playlist_rows[p.row_number].row_number = p.row_number
|
|
||||||
|
|
||||||
# Copy to self.playlist_rows
|
|
||||||
self.playlist_rows = new_playlist_rows
|
|
||||||
|
|
||||||
# Same as refresh data, but only used when creating playslit.
|
|
||||||
# Distinguishes profile time between initial load and other
|
|
||||||
# refreshes.
|
|
||||||
def load_data(self, session: db.session, dummy_for_profiling=None) -> None:
|
|
||||||
"""Populate self.playlist_rows with playlist data"""
|
|
||||||
|
|
||||||
# We used to clear self.playlist_rows each time but that's
|
|
||||||
# expensive and slow on big playlists
|
|
||||||
|
|
||||||
# Note where each playlist_id is
|
|
||||||
plid_to_row: dict[int, int] = {}
|
|
||||||
for oldrow in self.playlist_rows:
|
|
||||||
plrdata = self.playlist_rows[oldrow]
|
|
||||||
plid_to_row[plrdata.playlistrow_id] = plrdata.row_number
|
|
||||||
|
|
||||||
# build a new playlist_rows
|
|
||||||
new_playlist_rows: dict[int, RowAndTrack] = {}
|
|
||||||
for p in PlaylistRows.get_playlist_rows(session, self.playlist_id):
|
|
||||||
if p.id not in plid_to_row:
|
|
||||||
new_playlist_rows[p.row_number] = RowAndTrack(p)
|
|
||||||
else:
|
|
||||||
new_playlist_rows[p.row_number] = self.playlist_rows[plid_to_row[p.id]]
|
|
||||||
new_playlist_rows[p.row_number].row_number = p.row_number
|
|
||||||
|
|
||||||
# Copy to self.playlist_rows
|
|
||||||
self.playlist_rows = new_playlist_rows
|
|
||||||
|
|
||||||
def refresh_row(self, session, row_number):
|
def refresh_row(self, session, row_number):
|
||||||
"""Populate dict for one row from database"""
|
"""Populate dict for one row from database"""
|
||||||
|
|
||||||
@ -1172,7 +1147,7 @@ class PlaylistModel(QAbstractTableModel):
|
|||||||
# Safety check
|
# Safety check
|
||||||
if not ask_yes_no(
|
if not ask_yes_no(
|
||||||
title="Remove comments",
|
title="Remove comments",
|
||||||
question=f"Remove comments from {len(row_numbers)} rows?"
|
question=f"Remove comments from {len(row_numbers)} rows?",
|
||||||
):
|
):
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -1227,7 +1202,12 @@ class PlaylistModel(QAbstractTableModel):
|
|||||||
def remove_section_timer_markers(self, header_text: str) -> str:
|
def remove_section_timer_markers(self, header_text: str) -> str:
|
||||||
"""
|
"""
|
||||||
Remove characters used to mark section timeings from
|
Remove characters used to mark section timeings from
|
||||||
passed header text. Return header text witout markers
|
passed header text.
|
||||||
|
|
||||||
|
Remove text using to signal header colours if colour entry
|
||||||
|
is so marked.
|
||||||
|
|
||||||
|
Return header text witout markers
|
||||||
"""
|
"""
|
||||||
|
|
||||||
while header_text.endswith(Config.SECTION_STARTS):
|
while header_text.endswith(Config.SECTION_STARTS):
|
||||||
@ -1235,6 +1215,31 @@ class PlaylistModel(QAbstractTableModel):
|
|||||||
while header_text.endswith(Config.SECTION_ENDINGS):
|
while header_text.endswith(Config.SECTION_ENDINGS):
|
||||||
header_text = header_text[0:-1]
|
header_text = header_text[0:-1]
|
||||||
|
|
||||||
|
# Parse passed header text and remove the first colour match string
|
||||||
|
with db.Session() as session:
|
||||||
|
for rec in NoteColours.get_all(session):
|
||||||
|
if not rec.strip_substring:
|
||||||
|
continue
|
||||||
|
if rec.is_regex:
|
||||||
|
flags = re.UNICODE
|
||||||
|
if not rec.is_casesensitive:
|
||||||
|
flags |= re.IGNORECASE
|
||||||
|
p = re.compile(rec.substring, flags)
|
||||||
|
if p.match(header_text):
|
||||||
|
header_text = re.sub(p, "", header_text)
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
if rec.is_casesensitive:
|
||||||
|
if rec.substring.lower() in header_text.lower():
|
||||||
|
header_text = remove_substring_case_insensitive(
|
||||||
|
header_text, rec.substring
|
||||||
|
)
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
if rec.substring in header_text:
|
||||||
|
header_text = header_text.replace(rec.substring, "")
|
||||||
|
break
|
||||||
|
|
||||||
return header_text
|
return header_text
|
||||||
|
|
||||||
def rowCount(self, index: QModelIndex = QModelIndex()) -> int:
|
def rowCount(self, index: QModelIndex = QModelIndex()) -> int:
|
||||||
|
|||||||
@ -0,0 +1,44 @@
|
|||||||
|
"""Add strip_substring to NoteColoursTable
|
||||||
|
|
||||||
|
Revision ID: a524796269fa
|
||||||
|
Revises: 708a21f5c271
|
||||||
|
Create Date: 2024-12-14 12:42:45.214707
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = 'a524796269fa'
|
||||||
|
down_revision = '708a21f5c271'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade(engine_name: str) -> None:
|
||||||
|
globals()["upgrade_%s" % engine_name]()
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade(engine_name: str) -> None:
|
||||||
|
globals()["downgrade_%s" % engine_name]()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade_() -> None:
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
with op.batch_alter_table('notecolours', schema=None) as batch_op:
|
||||||
|
batch_op.add_column(sa.Column('strip_substring', sa.Boolean(), nullable=False))
|
||||||
|
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade_() -> None:
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
with op.batch_alter_table('notecolours', schema=None) as batch_op:
|
||||||
|
batch_op.drop_column('strip_substring')
|
||||||
|
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
Loading…
Reference in New Issue
Block a user