Compare commits

...

11 Commits

Author SHA1 Message Date
Keith Edmunds
0391eed88e Optionally remove header colour directives from header 2024-12-14 14:49:07 +00:00
Keith Edmunds
f7f4cdc622 Implement header row foreground colour 2024-12-14 12:01:41 +00:00
Keith Edmunds
b7b825f0ef Restart Alembic migations
Alembic was generating empty migraiton files. Restart Alembic
from scracth which resolved problem.
2024-12-14 11:58:54 +00:00
Keith Edmunds
3c8f5910df Add notes to .envrc 2024-12-14 11:56:37 +00:00
Keith Edmunds
cc01d04fb8 Remove section timing marks from displayed headers 2024-12-14 10:22:25 +00:00
Keith Edmunds
ac18773ebd Merge branch 'dev' 2024-12-13 21:37:11 +00:00
Keith Edmunds
61dcf7fc91 Don't bring Audacity to focus when starting app 2024-12-13 12:54:48 +00:00
Keith Edmunds
d0d3d5b09a Allow combined +- in header rows 2024-12-13 12:48:05 +00:00
Keith Edmunds
ba32473f06 Fix header row heights too large 2024-12-13 12:45:42 +00:00
Keith Edmunds
d7751008bd Merge dev 2024-12-11 12:49:01 +00:00
Keith Edmunds
57765a64a7 Temp changes for profiling 2024-12-05 17:42:46 +00:00
38 changed files with 325 additions and 1141 deletions

2
.envrc
View File

@ -13,6 +13,8 @@ branch=$(git branch --show-current)
if [ $(pwd) == /home/kae/mm ]; then
export MM_ENV="PRODUCTION"
export DATABASE_URL="mysql+mysqldb://musicmuster:musicmuster@localhost/musicmuster_prod"
# on_git_branch is a direnv directive
# See https://github.com/direnv/direnv/blob/master/man/direnv-stdlib.1.md
elif on_git_branch master; then
export MM_ENV="PRODUCTION"
export DATABASE_URL="mysql+mysqldb://musicmuster:musicmuster@localhost/musicmuster_prod"

View File

@ -107,7 +107,11 @@ class AudacityController:
f"and pipes exist at {self.pipe_to} and {self.pipe_from}."
)
# Send test command to Audacity
def _test_connectivity(self) -> None:
"""
Send test command to Audacity
"""
response = self._send_command(Config.AUDACITY_TEST_COMMAND)
if response != Config.AUDACITY_TEST_RESPONSE:
raise ApplicationError(

View File

@ -95,6 +95,8 @@ class Config(object):
ROOT = os.environ.get("ROOT") or "/home/kae/music"
ROWS_FROM_ZERO = True
SCROLL_TOP_MARGIN = 3
SECTION_ENDINGS = ("-", "+-", "-+")
SECTION_STARTS = ("+", "+-", "-+")
SONGFACTS_ON_NEXT = False
START_GAP_WARNING_THRESHOLD = 300
TEXT_NO_TRACK_NO_NOTE = "[Section header]"

View File

@ -30,9 +30,11 @@ class NoteColoursTable(Model):
substring: Mapped[str] = mapped_column(String(256), index=False)
colour: Mapped[str] = mapped_column(String(21), index=False)
enabled: Mapped[bool] = mapped_column(default=True, index=True)
foreground: Mapped[Optional[str]] = mapped_column(String(21), index=False)
is_regex: 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)
strip_substring: Mapped[bool] = mapped_column(default=True, index=False)
def __repr__(self) -> str:
return (

View File

@ -333,6 +333,32 @@ def normalise_track(path: str) -> None:
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:
# From https://docs.python.org/3/library/email.examples.html

View File

@ -22,9 +22,9 @@ from sqlalchemy.orm import joinedload
from sqlalchemy.orm.session import Session
# App imports
from config import Config
from dbmanager import DatabaseManager
import dbtables
from config import Config
from log import log
@ -70,17 +70,22 @@ class NoteColours(dbtables.NoteColoursTable):
return result
@staticmethod
def get_colour(session: Session, text: str) -> Optional[str]:
def get_colour(session: Session, text: str, foreground: bool = False) -> Optional[str]:
"""
Parse text and return colour string if matched, else empty string
Parse text and return background (foreground if foreground==True) colour
string if matched, else None
"""
if not text:
return None
match = False
for rec in session.scalars(
select(NoteColours)
.filter(NoteColours.enabled.is_(True))
.where(
NoteColours.enabled.is_(True),
)
.order_by(NoteColours.order)
).all():
if rec.is_regex:
@ -89,15 +94,20 @@ class NoteColours(dbtables.NoteColoursTable):
flags |= re.IGNORECASE
p = re.compile(rec.substring, flags)
if p.match(text):
return rec.colour
match = True
else:
if rec.is_casesensitive:
if rec.substring in text:
return rec.colour
match = True
else:
if rec.substring.lower() in text.lower():
return rec.colour
match = True
if match:
if foreground:
return rec.foreground
else:
return rec.colour
return None

View File

@ -45,6 +45,7 @@ from helpers import (
get_embedded_time,
get_relative_date,
ms_to_mmss,
remove_substring_case_insensitive,
set_track_metadata,
)
from log import log
@ -147,9 +148,9 @@ class PlaylistModel(QAbstractTableModel):
if self.is_header_row(row):
# Check for specific header colouring
with db.Session() as session:
note_colour = NoteColours.get_colour(session, rat.note)
if note_colour:
return QBrush(QColor(note_colour))
note_background = NoteColours.get_colour(session, rat.note)
if note_background:
return QBrush(QColor(note_background))
else:
return QBrush(QColor(Config.COLOUR_NOTES_PLAYLIST))
# Unreadable track file
@ -184,9 +185,9 @@ class PlaylistModel(QAbstractTableModel):
if column == Col.NOTE.value:
if rat.note:
with db.Session() as session:
note_colour = NoteColours.get_colour(session, rat.note)
if note_colour:
return QBrush(QColor(note_colour))
note_background = NoteColours.get_colour(session, rat.note)
if note_background:
return QBrush(QColor(note_background))
return QBrush()
@ -303,6 +304,7 @@ class PlaylistModel(QAbstractTableModel):
int(Qt.ItemDataRole.DisplayRole): self.display_role,
int(Qt.ItemDataRole.EditRole): self.edit_role,
int(Qt.ItemDataRole.FontRole): self.font_role,
int(Qt.ItemDataRole.ForegroundRole): self.foreground_role,
int(Qt.ItemDataRole.ToolTipRole): self.tooltip_role,
}
@ -316,7 +318,6 @@ class PlaylistModel(QAbstractTableModel):
Qt.ItemDataRole.WhatsThisRole,
Qt.ItemDataRole.SizeHintRole,
Qt.ItemDataRole.TextAlignmentRole,
Qt.ItemDataRole.ForegroundRole,
Qt.ItemDataRole.CheckStateRole,
Qt.ItemDataRole.InitialSortOrderRole,
]:
@ -377,7 +378,7 @@ class PlaylistModel(QAbstractTableModel):
else:
return QVariant(self.header_text(rat))
else:
return QVariant()
return QVariant("")
if column == Col.START_TIME.value:
start_time = rat.forecast_start_time
@ -447,6 +448,19 @@ class PlaylistModel(QAbstractTableModel):
return QVariant()
def foreground_role(self, row: int, column: int, rat: RowAndTrack) -> QBrush:
"""Return header foreground colour or QBrush() if none"""
if self.is_header_row(row):
with db.Session() as session:
note_foreground = NoteColours.get_colour(
session, rat.note, foreground=True
)
if note_foreground:
return QBrush(QColor(note_foreground))
return QBrush()
def flags(self, index: QModelIndex) -> Qt.ItemFlag:
"""
Standard model flags
@ -618,7 +632,7 @@ class PlaylistModel(QAbstractTableModel):
Process possible section timing directives embeded in header
"""
if rat.note.endswith("+"):
if rat.note.endswith(Config.SECTION_STARTS):
return self.start_of_timed_section_header(rat)
elif rat.note.endswith("="):
@ -727,6 +741,36 @@ class PlaylistModel(QAbstractTableModel):
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:
"""
Mark row as unplayed
@ -996,7 +1040,9 @@ class PlaylistModel(QAbstractTableModel):
self.invalidate_row(track_sequence.previous.row_number)
@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
@ -1026,39 +1072,6 @@ class PlaylistModel(QAbstractTableModel):
# 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: 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
def refresh_row(self, session, row_number):
"""Populate dict for one row from database"""
@ -1134,7 +1147,7 @@ class PlaylistModel(QAbstractTableModel):
# Safety check
if not ask_yes_no(
title="Remove comments",
question=f"Remove comments from {len(row_numbers)} rows?"
question=f"Remove comments from {len(row_numbers)} rows?",
):
return
@ -1186,6 +1199,49 @@ class PlaylistModel(QAbstractTableModel):
log.debug(f"{self}: _reversed_contiguous_row_groups() returned: {result=}")
return result
def remove_section_timer_markers(self, header_text: str) -> str:
"""
Remove characters used to mark section timeings from
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):
header_text = header_text[0:-1]
while header_text.endswith(Config.SECTION_ENDINGS):
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
def rowCount(self, index: QModelIndex = QModelIndex()) -> int:
"""Standard function for view"""
@ -1229,10 +1285,10 @@ class PlaylistModel(QAbstractTableModel):
", section end time "
+ section_end_time.strftime(Config.TRACK_TIME_FORMAT)
)
stripped_note = rat.note[:-1].strip()
if stripped_note:
clean_header = self.remove_section_timer_markers(rat.note)
if clean_header:
return (
f"{stripped_note} ["
f"{clean_header} ["
f"{unplayed_count}/{count} track{'s' if count > 1 else ''} "
f"({ms_to_mmss(duration)}) unplayed{end_time_str}]"
)
@ -1442,12 +1498,14 @@ class PlaylistModel(QAbstractTableModel):
unplayed_count: int = 0
duration: int = 0
clean_header = self.remove_section_timer_markers(rat.note)
for row_number in range(rat.row_number + 1, len(self.playlist_rows)):
row_rat = self.playlist_rows[row_number]
if self.is_header_row(row_number):
if row_rat.note.endswith("-"):
if row_rat.note.endswith(Config.SECTION_ENDINGS):
return (
f"{rat.note[:-1].strip()} "
f"{clean_header} "
f"[{count} tracks, {ms_to_mmss(duration)} unplayed]"
)
else:
@ -1458,7 +1516,7 @@ class PlaylistModel(QAbstractTableModel):
unplayed_count += 1
duration += row_rat.duration
return (
f"{rat.note[:-1].strip()} "
f"{clean_header} "
f"[{count} tracks, {ms_to_mmss(duration, none='none')} "
"unplayed (to end of playlist)]"
)

View File

@ -214,6 +214,24 @@ class PlaylistDelegate(QStyledItemDelegate):
doc.setDefaultFont(option.font)
doc.setDocumentMargin(0)
doc.setHtml(option.text)
# For debugging +++
# Calculate sizes
# document_size = doc.documentLayout().documentSize()
# ideal_width = doc.idealWidth()
# height = document_size.height()
# rect_width = option.rect.width()
# text = option.text
# # Debug output
# print(f"Index: {index.row()}, {index.column()}")
# print(f"Text: {text}")
# print(f"Option.rect width: {rect_width}")
# print(f"Document idealWidth: {ideal_width}")
# print(f"Document height: {height}")
# print(f"---")
# --- For debugging
return QSize(int(doc.idealWidth()), int(doc.size().height()))
def setEditorData(self, editor, index):

View File

@ -1,4 +1,7 @@
"""${message}
<%!
import re
%>"""${message}
Revision ID: ${up_revision}
Revises: ${down_revision | comma,n}
@ -16,9 +19,27 @@ branch_labels = ${repr(branch_labels)}
depends_on = ${repr(depends_on)}
def upgrade():
${upgrades if upgrades else "pass"}
def upgrade(engine_name: str) -> None:
globals()["upgrade_%s" % engine_name]()
def downgrade():
${downgrades if downgrades else "pass"}
def downgrade(engine_name: str) -> None:
globals()["downgrade_%s" % engine_name]()
<%
db_names = config.get_main_option("databases")
%>
## generate an "upgrade_<xyz>() / downgrade_<xyz>()" function
## for each database name in the ini file.
% for db_name in re.split(r',\s*', db_names):
def upgrade_${db_name}() -> None:
${context.get("%s_upgrades" % db_name, "pass")}
def downgrade_${db_name}() -> None:
${context.get("%s_downgrades" % db_name, "pass")}
% endfor

View File

@ -1,32 +0,0 @@
"""Add sort_column, deleted and query to playlists table
Revision ID: 07dcbe6c4f0e
Revises: 4a7b4ab3354f
Create Date: 2022-12-25 10:26:38.200941
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '07dcbe6c4f0e'
down_revision = '4a7b4ab3354f'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('playlists', sa.Column('sort_column', sa.Integer(), nullable=True))
op.add_column('playlists', sa.Column('query', sa.String(length=256), nullable=True))
op.add_column('playlists', sa.Column('deleted', sa.Boolean(), nullable=False))
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column('playlists', 'deleted')
op.drop_column('playlists', 'query')
op.drop_column('playlists', 'sort_column')
# ### end Alembic commands ###

View File

@ -1,32 +0,0 @@
"""Add 'played' column to playlist_rows
Revision ID: 0c604bf490f8
Revises: 29c0d7ffc741
Create Date: 2022-08-12 14:12:38.419845
"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import mysql
# revision identifiers, used by Alembic.
revision = "0c604bf490f8"
down_revision = "29c0d7ffc741"
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.add_column("playlist_rows", sa.Column("played", sa.Boolean(), nullable=False))
op.drop_index("ix_tracks_lastplayed", table_name="tracks")
op.drop_column("tracks", "lastplayed")
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.add_column("tracks", sa.Column("lastplayed", mysql.DATETIME(), nullable=True))
op.create_index("ix_tracks_lastplayed", "tracks", ["lastplayed"], unique=False)
op.drop_column("playlist_rows", "played")
# ### end Alembic commands ###

View File

@ -1,40 +0,0 @@
"""Add columns to track table
Revision ID: 1bc727e5e87f
Revises: 52d82712d218
Create Date: 2021-03-22 22:43:40.458197
"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import mysql
# revision identifiers, used by Alembic.
revision = '1bc727e5e87f'
down_revision = '52d82712d218'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('tracks', sa.Column('duration', sa.Integer(), nullable=True))
op.add_column('tracks', sa.Column('fade_at', sa.Integer(), nullable=True))
op.add_column('tracks', sa.Column('silence_at', sa.Integer(), nullable=True))
op.add_column('tracks', sa.Column('start_gap', sa.Integer(), nullable=True))
op.drop_index('ix_tracks_length', table_name='tracks')
op.create_index(op.f('ix_tracks_duration'), 'tracks', ['duration'], unique=False)
op.drop_column('tracks', 'length')
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('tracks', sa.Column('length', mysql.INTEGER(display_width=11), autoincrement=False, nullable=True))
op.drop_index(op.f('ix_tracks_duration'), table_name='tracks')
op.create_index('ix_tracks_length', 'tracks', ['length'], unique=False)
op.drop_column('tracks', 'start_gap')
op.drop_column('tracks', 'silence_at')
op.drop_column('tracks', 'fade_at')
op.drop_column('tracks', 'duration')
# ### end Alembic commands ###

View File

@ -1,34 +0,0 @@
"""Add constraint to playlist_tracks
Revision ID: 1c4048efee96
Revises: 52cbded98e7c
Create Date: 2022-03-29 19:26:27.378185
"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import mysql
# revision identifiers, used by Alembic.
revision = '1c4048efee96'
down_revision = '52cbded98e7c'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.create_unique_constraint('uniquerow', 'playlist_tracks', ['row', 'playlist_id'])
op.alter_column('playlists', 'loaded',
existing_type=mysql.TINYINT(display_width=1),
nullable=False)
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.alter_column('playlists', 'loaded',
existing_type=mysql.TINYINT(display_width=1),
nullable=True)
op.drop_constraint('uniquerow', 'playlist_tracks', type_='unique')
# ### end Alembic commands ###

View File

@ -1,34 +0,0 @@
"""Fixup playdates relationship
Revision ID: 269a002f989d
Revises: 9bf80ba3635f
Create Date: 2021-03-28 14:36:59.103846
"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import mysql
# revision identifiers, used by Alembic.
revision = '269a002f989d'
down_revision = '9bf80ba3635f'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('playdates', sa.Column('track_id', sa.Integer(), nullable=True))
op.create_foreign_key(None, 'playdates', 'tracks', ['track_id'], ['id'])
op.drop_constraint('tracks_ibfk_1', 'tracks', type_='foreignkey')
op.drop_column('tracks', 'playdates_id')
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('tracks', sa.Column('playdates_id', mysql.INTEGER(display_width=11), autoincrement=False, nullable=True))
op.create_foreign_key('tracks_ibfk_1', 'tracks', 'playdates', ['playdates_id'], ['id'])
op.drop_constraint(None, 'playdates', type_='foreignkey')
op.drop_column('playdates', 'track_id')
# ### end Alembic commands ###

View File

@ -1,24 +0,0 @@
"""Drop uniquerow index on playlist_rows
Revision ID: 29c0d7ffc741
Revises: 3b063011ed67
Create Date: 2022-08-06 22:21:46.881378
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '29c0d7ffc741'
down_revision = '3b063011ed67'
branch_labels = None
depends_on = None
def upgrade():
op.drop_index('uniquerow', table_name='playlist_rows')
def downgrade():
op.create_index('uniquerow', 'playlist_rows', ['row_number', 'playlist_id'], unique=True)

View File

@ -1,110 +0,0 @@
"""add Tracks.intro column
Revision ID: 2caa3d37f211
Revises: 5bb2c572e1e5
Create Date: 2024-05-07 20:06:00.845979
"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import mysql
# revision identifiers, used by Alembic.
revision = '2caa3d37f211'
down_revision = '5bb2c572e1e5'
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('carts', schema=None) as batch_op:
batch_op.alter_column('name',
existing_type=mysql.VARCHAR(length=256),
nullable=False)
with op.batch_alter_table('notecolours', schema=None) as batch_op:
batch_op.alter_column('substring',
existing_type=mysql.VARCHAR(length=256),
nullable=False)
batch_op.alter_column('colour',
existing_type=mysql.VARCHAR(length=21),
nullable=False)
batch_op.alter_column('enabled',
existing_type=mysql.TINYINT(display_width=1),
nullable=False)
batch_op.alter_column('is_regex',
existing_type=mysql.TINYINT(display_width=1),
nullable=False)
batch_op.alter_column('is_casesensitive',
existing_type=mysql.TINYINT(display_width=1),
nullable=False)
with op.batch_alter_table('playdates', schema=None) as batch_op:
batch_op.alter_column('lastplayed',
existing_type=mysql.DATETIME(),
nullable=False)
batch_op.alter_column('track_id',
existing_type=mysql.INTEGER(display_width=11),
nullable=False)
with op.batch_alter_table('playlists', schema=None) as batch_op:
batch_op.drop_index('tab')
with op.batch_alter_table('tracks', schema=None) as batch_op:
batch_op.add_column(sa.Column('intro', sa.Integer(), nullable=True))
# ### end Alembic commands ###
def downgrade_() -> None:
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('tracks', schema=None) as batch_op:
batch_op.drop_column('intro')
with op.batch_alter_table('playlists', schema=None) as batch_op:
batch_op.create_index('tab', ['tab'], unique=True)
with op.batch_alter_table('playdates', schema=None) as batch_op:
batch_op.alter_column('track_id',
existing_type=mysql.INTEGER(display_width=11),
nullable=True)
batch_op.alter_column('lastplayed',
existing_type=mysql.DATETIME(),
nullable=True)
with op.batch_alter_table('notecolours', schema=None) as batch_op:
batch_op.alter_column('is_casesensitive',
existing_type=mysql.TINYINT(display_width=1),
nullable=True)
batch_op.alter_column('is_regex',
existing_type=mysql.TINYINT(display_width=1),
nullable=True)
batch_op.alter_column('enabled',
existing_type=mysql.TINYINT(display_width=1),
nullable=True)
batch_op.alter_column('colour',
existing_type=mysql.VARCHAR(length=21),
nullable=True)
batch_op.alter_column('substring',
existing_type=mysql.VARCHAR(length=256),
nullable=True)
with op.batch_alter_table('carts', schema=None) as batch_op:
batch_op.alter_column('name',
existing_type=mysql.VARCHAR(length=256),
nullable=True)
# ### end Alembic commands ###

View File

@ -1,30 +0,0 @@
"""Add playlist dates and loaded
Revision ID: 2cc37d3cf07f
Revises: e3b04db5506f
Create Date: 2021-04-27 21:55:50.639406
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = "2cc37d3cf07f"
down_revision = "e3b04db5506f"
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.add_column("playlists", sa.Column("last_used", sa.DateTime(), nullable=True))
op.add_column("playlists", sa.Column("loaded", sa.Boolean(), nullable=True))
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column("playlists", "loaded")
op.drop_column("playlists", "last_used")
# ### end Alembic commands ###

View File

@ -1,72 +0,0 @@
"""Migrate SQLA 2 and remove redundant columns
Revision ID: 3a53a9fb26ab
Revises: 07dcbe6c4f0e
Create Date: 2023-10-15 09:39:16.449419
"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import mysql
# revision identifiers, used by Alembic.
revision = '3a53a9fb26ab'
down_revision = '07dcbe6c4f0e'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column('playlists', 'query')
op.drop_column('playlists', 'sort_column')
op.alter_column('tracks', 'title',
existing_type=mysql.VARCHAR(length=256),
nullable=False)
op.alter_column('tracks', 'artist',
existing_type=mysql.VARCHAR(length=256),
nullable=False)
op.alter_column('tracks', 'duration',
existing_type=mysql.INTEGER(display_width=11),
nullable=False)
op.alter_column('tracks', 'start_gap',
existing_type=mysql.INTEGER(display_width=11),
nullable=False)
op.alter_column('tracks', 'fade_at',
existing_type=mysql.INTEGER(display_width=11),
nullable=False)
op.alter_column('tracks', 'silence_at',
existing_type=mysql.INTEGER(display_width=11),
nullable=False)
op.alter_column('tracks', 'mtime',
existing_type=mysql.FLOAT(),
nullable=False)
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.alter_column('tracks', 'mtime',
existing_type=mysql.FLOAT(),
nullable=True)
op.alter_column('tracks', 'silence_at',
existing_type=mysql.INTEGER(display_width=11),
nullable=True)
op.alter_column('tracks', 'fade_at',
existing_type=mysql.INTEGER(display_width=11),
nullable=True)
op.alter_column('tracks', 'start_gap',
existing_type=mysql.INTEGER(display_width=11),
nullable=True)
op.alter_column('tracks', 'duration',
existing_type=mysql.INTEGER(display_width=11),
nullable=True)
op.alter_column('tracks', 'artist',
existing_type=mysql.VARCHAR(length=256),
nullable=True)
op.alter_column('tracks', 'title',
existing_type=mysql.VARCHAR(length=256),
nullable=True)
op.add_column('playlists', sa.Column('sort_column', mysql.INTEGER(display_width=11), autoincrement=False, nullable=True))
op.add_column('playlists', sa.Column('query', mysql.VARCHAR(length=256), nullable=True))
# ### end Alembic commands ###

View File

@ -1,54 +0,0 @@
"""schema changes for row notes
Revision ID: 3b063011ed67
Revises: 51f61433256f
Create Date: 2022-07-06 19:48:23.960471
"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import mysql
# revision identifiers, used by Alembic.
revision = '3b063011ed67'
down_revision = '51f61433256f'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_table('notes')
op.add_column('playlist_rows', sa.Column('note', sa.String(length=2048), nullable=True))
op.alter_column('playlist_rows', 'track_id',
existing_type=mysql.INTEGER(display_width=11),
nullable=True)
op.drop_index('uniquerow', table_name='playlist_rows')
op.drop_column('playlist_rows', 'text')
op.alter_column('playlist_rows', 'row', new_column_name='row_number',
existing_type=mysql.INTEGER(display_width=11),
nullable=False)
op.create_index('uniquerow', 'playlist_rows', ['row_number', 'playlist_id'], unique=True)
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.alter_column('playlist_rows', 'row_number', new_column_name='row',
existing_type=mysql.INTEGER(display_width=11),
nullable=False)
op.add_column('playlist_rows', sa.Column('text', mysql.VARCHAR(length=2048), nullable=True))
op.drop_index('uniquerow', table_name='playlist_rows')
op.create_index('uniquerow', 'playlist_rows', ['row', 'playlist_id'], unique=False)
op.drop_column('playlist_rows', 'note')
op.create_table('notes',
sa.Column('id', mysql.INTEGER(display_width=11), autoincrement=True, nullable=False),
sa.Column('playlist_id', mysql.INTEGER(display_width=11), autoincrement=False, nullable=True),
sa.Column('row', mysql.INTEGER(display_width=11), autoincrement=False, nullable=False),
sa.Column('note', mysql.VARCHAR(length=256), nullable=True),
sa.ForeignKeyConstraint(['playlist_id'], ['playlists.id'], name='notes_ibfk_1'),
sa.PrimaryKeyConstraint('id'),
mysql_default_charset='utf8mb4',
mysql_engine='InnoDB'
)
# ### end Alembic commands ###

View File

@ -1,26 +0,0 @@
"""Rename playlist_tracks to playlist_rows
Revision ID: 3f55ac7d80ad
Revises: 1c4048efee96
Create Date: 2022-07-04 20:51:59.874004
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '3f55ac7d80ad'
down_revision = '1c4048efee96'
branch_labels = None
depends_on = None
def upgrade():
# Rename so as not to lose content
op.rename_table('playlist_tracks', 'playlist_rows')
def downgrade():
# Rename so as not to lose content
op.rename_table('playlist_rows', 'playlist_tracks')

View File

@ -1,32 +0,0 @@
"""Record tab number for open playlists
Revision ID: 4a7b4ab3354f
Revises: 6730f03317df
Create Date: 2022-12-20 15:38:28.318280
"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import mysql
# revision identifiers, used by Alembic.
revision = '4a7b4ab3354f'
down_revision = '6730f03317df'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('playlists', sa.Column('tab', sa.Integer(), nullable=True))
op.create_unique_constraint(None, 'playlists', ['tab'])
op.drop_column('playlists', 'loaded')
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('playlists', sa.Column('loaded', mysql.TINYINT(display_width=1), autoincrement=False, nullable=False))
op.drop_constraint(None, 'playlists', type_='unique')
op.drop_column('playlists', 'tab')
# ### end Alembic commands ###

View File

@ -1,34 +0,0 @@
"""Increase settings.name len and add playlist_rows.notes
Revision ID: 51f61433256f
Revises: 3f55ac7d80ad
Create Date: 2022-07-04 21:21:39.830406
"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import mysql
# revision identifiers, used by Alembic.
revision = '51f61433256f'
down_revision = '3f55ac7d80ad'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('playlist_rows', sa.Column('text', sa.String(length=2048), nullable=True))
op.alter_column('playlists', 'loaded',
existing_type=mysql.TINYINT(display_width=1),
nullable=False)
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.alter_column('playlists', 'loaded',
existing_type=mysql.TINYINT(display_width=1),
nullable=True)
op.drop_column('playlist_rows', 'text')
# ### end Alembic commands ###

View File

@ -1,30 +0,0 @@
"""Update notecolours table
Revision ID: 52cbded98e7c
Revises: c55992d1fe5f
Create Date: 2022-02-06 12:34:30.099417
"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import mysql
# revision identifiers, used by Alembic.
revision = '52cbded98e7c'
down_revision = 'c55992d1fe5f'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('notecolours', sa.Column('colour', sa.String(length=21), nullable=True))
op.drop_column('notecolours', 'hexcolour')
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('notecolours', sa.Column('hexcolour', mysql.VARCHAR(length=6), nullable=True))
op.drop_column('notecolours', 'colour')
# ### end Alembic commands ###

View File

@ -1,24 +0,0 @@
"""Initial
Revision ID: 52d82712d218
Revises:
Create Date: 2021-03-22 22:16:03.272827
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '52d82712d218'
down_revision = None
branch_labels = None
depends_on = None
def upgrade():
pass
def downgrade():
pass

View File

@ -1,60 +0,0 @@
"""Add 'open' field to Playlists
Revision ID: 5bb2c572e1e5
Revises: 3a53a9fb26ab
Create Date: 2023-11-18 14:19:02.643914
"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import mysql
# revision identifiers, used by Alembic.
revision = '5bb2c572e1e5'
down_revision = '3a53a9fb26ab'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.alter_column('carts', 'duration',
existing_type=mysql.INTEGER(display_width=11),
nullable=True)
op.alter_column('carts', 'path',
existing_type=mysql.VARCHAR(length=2048),
nullable=True)
op.alter_column('carts', 'enabled',
existing_type=mysql.TINYINT(display_width=1),
nullable=True)
op.alter_column('playlist_rows', 'note',
existing_type=mysql.VARCHAR(length=2048),
nullable=False)
op.add_column('playlists', sa.Column('open', sa.Boolean(), nullable=False))
op.alter_column('settings', 'name',
existing_type=mysql.VARCHAR(length=32),
type_=sa.String(length=64),
existing_nullable=False)
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.alter_column('settings', 'name',
existing_type=sa.String(length=64),
type_=mysql.VARCHAR(length=32),
existing_nullable=False)
op.drop_column('playlists', 'open')
op.alter_column('playlist_rows', 'note',
existing_type=mysql.VARCHAR(length=2048),
nullable=True)
op.alter_column('carts', 'enabled',
existing_type=mysql.TINYINT(display_width=1),
nullable=False)
op.alter_column('carts', 'path',
existing_type=mysql.VARCHAR(length=2048),
nullable=False)
op.alter_column('carts', 'duration',
existing_type=mysql.INTEGER(display_width=11),
nullable=False)
# ### end Alembic commands ###

View File

@ -1,41 +0,0 @@
"""Add carts
Revision ID: 6730f03317df
Revises: b4f524e2140c
Create Date: 2022-09-13 19:41:33.181752
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '6730f03317df'
down_revision = 'b4f524e2140c'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.create_table('carts',
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
sa.Column('cart_number', sa.Integer(), nullable=False),
sa.Column('name', sa.String(length=256), nullable=True),
sa.Column('duration', sa.Integer(), nullable=True),
sa.Column('path', sa.String(length=2048), nullable=True),
sa.Column('enabled', sa.Boolean(), nullable=False),
sa.PrimaryKeyConstraint('id'),
sa.UniqueConstraint('cart_number')
)
op.create_index(op.f('ix_carts_duration'), 'carts', ['duration'], unique=False)
op.create_index(op.f('ix_carts_name'), 'carts', ['name'], unique=False)
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_index(op.f('ix_carts_name'), table_name='carts')
op.drop_index(op.f('ix_carts_duration'), table_name='carts')
op.drop_table('carts')
# ### end Alembic commands ###

View File

@ -0,0 +1,75 @@
"""Initial migration
Revision ID: 708a21f5c271
Revises:
Create Date: 2024-12-14 11:16:09.067598
"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import mysql
# revision identifiers, used by Alembic.
revision = '708a21f5c271'
down_revision = None
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('carts', schema=None) as batch_op:
batch_op.drop_index('cart_number')
batch_op.drop_index('ix_carts_duration')
batch_op.drop_index('ix_carts_name')
op.drop_table('carts')
with op.batch_alter_table('notecolours', schema=None) as batch_op:
batch_op.add_column(sa.Column('foreground', sa.String(length=21), nullable=True))
with op.batch_alter_table('playlist_rows', schema=None) as batch_op:
batch_op.create_index(batch_op.f('ix_playlist_rows_playlist_id'), ['playlist_id'], unique=False)
batch_op.create_index(batch_op.f('ix_playlist_rows_row_number'), ['row_number'], unique=False)
# ### end Alembic commands ###
def downgrade_() -> None:
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('playlist_rows', schema=None) as batch_op:
batch_op.drop_index(batch_op.f('ix_playlist_rows_row_number'))
batch_op.drop_index(batch_op.f('ix_playlist_rows_playlist_id'))
with op.batch_alter_table('notecolours', schema=None) as batch_op:
batch_op.drop_column('foreground')
op.create_table('carts',
sa.Column('id', mysql.INTEGER(display_width=11), autoincrement=True, nullable=False),
sa.Column('cart_number', mysql.INTEGER(display_width=11), autoincrement=False, nullable=False),
sa.Column('name', mysql.VARCHAR(length=256), nullable=False),
sa.Column('duration', mysql.INTEGER(display_width=11), autoincrement=False, nullable=True),
sa.Column('path', mysql.VARCHAR(length=2048), nullable=True),
sa.Column('enabled', mysql.TINYINT(display_width=1), autoincrement=False, nullable=True),
sa.PrimaryKeyConstraint('id'),
mysql_collate='utf8mb4_general_ci',
mysql_default_charset='utf8mb4',
mysql_engine='InnoDB'
)
with op.batch_alter_table('carts', schema=None) as batch_op:
batch_op.create_index('ix_carts_name', ['name'], unique=False)
batch_op.create_index('ix_carts_duration', ['duration'], unique=False)
batch_op.create_index('cart_number', ['cart_number'], unique=True)
# ### end Alembic commands ###

View File

@ -1,34 +0,0 @@
"""Add id to playlist association table
Revision ID: 9bf80ba3635f
Revises: f071129cbd93
Create Date: 2021-03-28 12:16:14.631579
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '9bf80ba3635f'
down_revision = 'f071129cbd93'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
conn = op.get_bind()
conn.execute(
"ALTER TABLE playlistracks ADD id INT PRIMARY KEY AUTO_INCREMENT FIRST"
)
conn.execute("RENAME TABLE playlistracks TO playlisttracks")
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
conn = op.get_bind()
conn.execute("ALTER TABLE playlistracks DROP id")
conn.execute("RENAME TABLE playlisttracks TO playlistracks")
# ### end Alembic commands ###

View File

@ -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 ###

View File

@ -1,36 +0,0 @@
"""Add NoteColours table
Revision ID: a5aada49f2fc
Revises: 2cc37d3cf07f
Create Date: 2022-02-05 17:34:54.880473
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = 'a5aada49f2fc'
down_revision = '2cc37d3cf07f'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.create_table('notecolours',
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
sa.Column('substring', sa.String(length=256), nullable=True),
sa.Column('hexcolour', sa.String(length=6), nullable=True),
sa.Column('enabled', sa.Boolean(), nullable=True),
sa.Column('is_regex', sa.Boolean(), nullable=True),
sa.Column('is_casesensitive', sa.Boolean(), nullable=True),
sa.PrimaryKeyConstraint('id')
)
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_table('notecolours')
# ### end Alembic commands ###

View File

@ -1,37 +0,0 @@
"""Add settings table
Revision ID: b0983648595e
Revises: 1bc727e5e87f
Create Date: 2021-03-26 13:33:41.994508
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = "b0983648595e"
down_revision = "1bc727e5e87f"
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.create_table(
"settings",
sa.Column("id", sa.Integer(), autoincrement=True, nullable=False),
sa.Column("name", sa.String(length=32), nullable=False),
sa.Column("f_datetime", sa.DateTime(), nullable=True),
sa.Column("f_int", sa.Integer(), nullable=True),
sa.Column("f_string", sa.String(length=128), nullable=True),
sa.PrimaryKeyConstraint("id"),
sa.UniqueConstraint("name"),
)
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_table("settings")
# ### end Alembic commands ###

View File

@ -1,32 +0,0 @@
"""Add templates
Revision ID: b4f524e2140c
Revises: ed3100326c38
Create Date: 2022-10-01 13:30:21.663287
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = 'b4f524e2140c'
down_revision = 'ed3100326c38'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.create_foreign_key(None, 'playlist_rows', 'tracks', ['track_id'], ['id'])
op.create_foreign_key(None, 'playlist_rows', 'playlists', ['playlist_id'], ['id'])
op.add_column('playlists', sa.Column('is_template', sa.Boolean(), nullable=False))
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column('playlists', 'is_template')
op.drop_constraint(None, 'playlist_rows', type_='foreignkey')
op.drop_constraint(None, 'playlist_rows', type_='foreignkey')
# ### end Alembic commands ###

View File

@ -1,32 +0,0 @@
"""Add order to colours table
Revision ID: c55992d1fe5f
Revises: a5aada49f2fc
Create Date: 2022-02-05 21:28:36.391312
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = 'c55992d1fe5f'
down_revision = 'a5aada49f2fc'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('notecolours', sa.Column('order', sa.Integer(), nullable=True))
op.create_index(op.f('ix_notecolours_enabled'), 'notecolours', ['enabled'], unique=False)
op.create_index(op.f('ix_notecolours_order'), 'notecolours', ['order'], unique=False)
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_index(op.f('ix_notecolours_order'), table_name='notecolours')
op.drop_index(op.f('ix_notecolours_enabled'), table_name='notecolours')
op.drop_column('notecolours', 'order')
# ### end Alembic commands ###

View File

@ -1,51 +0,0 @@
"""Add structure for notes
Revision ID: e3b04db5506f
Revises: 269a002f989d
Create Date: 2021-04-05 16:33:50.117747
"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import mysql
# revision identifiers, used by Alembic.
revision = 'e3b04db5506f'
down_revision = '269a002f989d'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.create_table('notes',
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
sa.Column('playlist_id', sa.Integer(), nullable=True),
sa.Column('row', sa.Integer(), nullable=False),
sa.Column('note', sa.String(length=256), nullable=True),
sa.ForeignKeyConstraint(['playlist_id'], ['playlists.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.add_column('playlisttracks', sa.Column('row', sa.Integer(), nullable=False))
op.alter_column('playlisttracks', 'playlist_id',
existing_type=mysql.INTEGER(display_width=11),
nullable=False)
op.alter_column('playlisttracks', 'track_id',
existing_type=mysql.INTEGER(display_width=11),
nullable=False)
op.drop_column('playlisttracks', 'sort')
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('playlisttracks', sa.Column('sort', mysql.INTEGER(display_width=11), autoincrement=False, nullable=False))
op.alter_column('playlisttracks', 'track_id',
existing_type=mysql.INTEGER(display_width=11),
nullable=True)
op.alter_column('playlisttracks', 'playlist_id',
existing_type=mysql.INTEGER(display_width=11),
nullable=True)
op.drop_column('playlisttracks', 'row')
op.drop_table('notes')
# ### end Alembic commands ###

View File

@ -1,28 +0,0 @@
"""Add column for bitrate in Tracks
Revision ID: ed3100326c38
Revises: fe2e127b3332
Create Date: 2022-08-22 16:16:42.181848
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = 'ed3100326c38'
down_revision = 'fe2e127b3332'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('tracks', sa.Column('bitrate', sa.Integer(), nullable=True))
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column('tracks', 'bitrate')
# ### end Alembic commands ###

View File

@ -1,28 +0,0 @@
"""Add sort to playlist association table
Revision ID: f071129cbd93
Revises: f07b96a5e60f
Create Date: 2021-03-28 11:19:31.944110
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = 'f071129cbd93'
down_revision = 'f07b96a5e60f'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('playlistracks', sa.Column('sort', sa.Integer(), nullable=False))
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column('playlistracks', 'sort')
# ### end Alembic commands ###

View File

@ -1,63 +0,0 @@
"""Add playlist and playtimes
Revision ID: f07b96a5e60f
Revises: b0983648595e
Create Date: 2021-03-27 19:53:09.524989
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = "f07b96a5e60f"
down_revision = "b0983648595e"
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.create_table(
"playdates",
sa.Column("id", sa.Integer(), autoincrement=True, nullable=False),
sa.Column("lastplayed", sa.DateTime(), nullable=True),
sa.PrimaryKeyConstraint("id"),
)
op.create_index(
op.f("ix_playdates_lastplayed"), "playdates", ["lastplayed"], unique=False
)
op.create_table(
"playlists",
sa.Column("id", sa.Integer(), autoincrement=True, nullable=False),
sa.Column("name", sa.String(length=32), nullable=False),
sa.PrimaryKeyConstraint("id"),
sa.UniqueConstraint("name"),
)
op.create_table(
"playlistracks",
sa.Column("playlist_id", sa.Integer(), nullable=True),
sa.Column("track_id", sa.Integer(), nullable=True),
sa.ForeignKeyConstraint(
["playlist_id"],
["playlists.id"],
),
sa.ForeignKeyConstraint(
["track_id"],
["tracks.id"],
),
)
op.add_column("tracks", sa.Column("playdates_id", sa.Integer(), nullable=True))
op.create_foreign_key(None, "tracks", "playdates", ["playdates_id"], ["id"])
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_constraint(None, "tracks", type_="foreignkey")
op.drop_column("tracks", "playdates_id")
op.drop_table("playlistracks")
op.drop_table("playlists")
op.drop_index(op.f("ix_playdates_lastplayed"), table_name="playdates")
op.drop_table("playdates")
# ### end Alembic commands ###

View File

@ -1,28 +0,0 @@
"""Don't allow duplicate track paths
Revision ID: fe2e127b3332
Revises: 0c604bf490f8
Create Date: 2022-08-21 19:46:35.768659
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = 'fe2e127b3332'
down_revision = '0c604bf490f8'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.create_unique_constraint(None, 'tracks', ['path'])
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_constraint(None, 'tracks', type_='unique')
# ### end Alembic commands ###