mirror of
https://github.com/wahyd4/you-music.git
synced 2026-08-09 05:06:44 +10:00
Fix docker
This commit is contained in:
@@ -21,6 +21,46 @@ depends_on: Union[str, Sequence[str], None] = None
|
|||||||
def upgrade() -> None:
|
def upgrade() -> None:
|
||||||
"""Upgrade schema."""
|
"""Upgrade schema."""
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
# Create all tables
|
||||||
|
op.create_table('music',
|
||||||
|
sa.Column('id', sa.Integer(), nullable=False),
|
||||||
|
sa.Column('title', sa.String(), nullable=True),
|
||||||
|
sa.Column('artist', sa.String(), nullable=True),
|
||||||
|
sa.Column('album', sa.String(), nullable=True),
|
||||||
|
sa.Column('duration', sa.Float(), nullable=True),
|
||||||
|
sa.Column('file_path', sa.String(), nullable=True),
|
||||||
|
sa.Column('file_size', sa.Integer(), nullable=True),
|
||||||
|
sa.Column('file_format', sa.String(), nullable=True),
|
||||||
|
sa.Column('file_location', sa.String(), nullable=True),
|
||||||
|
sa.Column('file_exists', sa.Boolean(), nullable=True),
|
||||||
|
sa.Column('source_url', sa.String(), nullable=True),
|
||||||
|
sa.Column('source_type', sa.String(), nullable=True),
|
||||||
|
sa.Column('thumbnail', sa.String(), nullable=True),
|
||||||
|
sa.Column('lyrics', sa.Text(), nullable=True),
|
||||||
|
sa.Column('created_at', sa.DateTime(), nullable=True),
|
||||||
|
sa.Column('updated_at', sa.DateTime(), nullable=True),
|
||||||
|
sa.Column('last_scanned_at', sa.DateTime(), nullable=True),
|
||||||
|
sa.PrimaryKeyConstraint('id')
|
||||||
|
)
|
||||||
|
with op.batch_alter_table('music', schema=None) as batch_op:
|
||||||
|
batch_op.create_index(batch_op.f('ix_music_artist'), ['artist'], unique=False)
|
||||||
|
batch_op.create_index(batch_op.f('ix_music_id'), ['id'], unique=False)
|
||||||
|
batch_op.create_index(batch_op.f('ix_music_title'), ['title'], unique=False)
|
||||||
|
batch_op.create_unique_constraint('uq_music_file_path', ['file_path'])
|
||||||
|
|
||||||
|
op.create_table('playlists',
|
||||||
|
sa.Column('id', sa.Integer(), nullable=False),
|
||||||
|
sa.Column('name', sa.String(), nullable=True),
|
||||||
|
sa.Column('description', sa.Text(), nullable=True),
|
||||||
|
sa.Column('thumbnail', sa.String(), nullable=True),
|
||||||
|
sa.Column('created_at', sa.DateTime(), nullable=True),
|
||||||
|
sa.Column('updated_at', sa.DateTime(), nullable=True),
|
||||||
|
sa.PrimaryKeyConstraint('id')
|
||||||
|
)
|
||||||
|
with op.batch_alter_table('playlists', schema=None) as batch_op:
|
||||||
|
batch_op.create_index(batch_op.f('ix_playlists_id'), ['id'], unique=False)
|
||||||
|
batch_op.create_index(batch_op.f('ix_playlists_name'), ['name'], unique=True)
|
||||||
|
|
||||||
op.create_table('app_settings',
|
op.create_table('app_settings',
|
||||||
sa.Column('id', sa.Integer(), nullable=False),
|
sa.Column('id', sa.Integer(), nullable=False),
|
||||||
sa.Column('key', sa.String(), nullable=True),
|
sa.Column('key', sa.String(), nullable=True),
|
||||||
@@ -32,27 +72,37 @@ def upgrade() -> None:
|
|||||||
batch_op.create_index(batch_op.f('ix_app_settings_id'), ['id'], unique=False)
|
batch_op.create_index(batch_op.f('ix_app_settings_id'), ['id'], unique=False)
|
||||||
batch_op.create_index(batch_op.f('ix_app_settings_key'), ['key'], unique=True)
|
batch_op.create_index(batch_op.f('ix_app_settings_key'), ['key'], unique=True)
|
||||||
|
|
||||||
with op.batch_alter_table('music', schema=None) as batch_op:
|
op.create_table('playlist_music',
|
||||||
batch_op.add_column(sa.Column('file_format', sa.String(), nullable=True))
|
sa.Column('playlist_id', sa.Integer(), nullable=False),
|
||||||
batch_op.add_column(sa.Column('file_location', sa.String(), nullable=True))
|
sa.Column('music_id', sa.Integer(), nullable=False),
|
||||||
batch_op.add_column(sa.Column('file_exists', sa.Boolean(), nullable=True))
|
sa.Column('position', sa.Integer(), nullable=True),
|
||||||
batch_op.add_column(sa.Column('last_scanned_at', sa.DateTime(), nullable=True))
|
sa.Column('added_at', sa.DateTime(), nullable=True),
|
||||||
|
sa.ForeignKeyConstraint(['music_id'], ['music.id'], ),
|
||||||
|
sa.ForeignKeyConstraint(['playlist_id'], ['playlists.id'], ),
|
||||||
|
sa.PrimaryKeyConstraint('playlist_id', 'music_id')
|
||||||
|
)
|
||||||
# ### end Alembic commands ###
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
def downgrade() -> None:
|
def downgrade() -> None:
|
||||||
"""Downgrade schema."""
|
"""Downgrade schema."""
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
with op.batch_alter_table('music', schema=None) as batch_op:
|
op.drop_table('playlist_music')
|
||||||
batch_op.drop_column('last_scanned_at')
|
|
||||||
batch_op.drop_column('file_exists')
|
|
||||||
batch_op.drop_column('file_location')
|
|
||||||
batch_op.drop_column('file_format')
|
|
||||||
|
|
||||||
with op.batch_alter_table('app_settings', schema=None) as batch_op:
|
with op.batch_alter_table('app_settings', schema=None) as batch_op:
|
||||||
batch_op.drop_index(batch_op.f('ix_app_settings_key'))
|
batch_op.drop_index(batch_op.f('ix_app_settings_key'))
|
||||||
batch_op.drop_index(batch_op.f('ix_app_settings_id'))
|
batch_op.drop_index(batch_op.f('ix_app_settings_id'))
|
||||||
|
|
||||||
op.drop_table('app_settings')
|
op.drop_table('app_settings')
|
||||||
|
|
||||||
|
with op.batch_alter_table('playlists', schema=None) as batch_op:
|
||||||
|
batch_op.drop_index(batch_op.f('ix_playlists_name'))
|
||||||
|
batch_op.drop_index(batch_op.f('ix_playlists_id'))
|
||||||
|
op.drop_table('playlists')
|
||||||
|
|
||||||
|
with op.batch_alter_table('music', schema=None) as batch_op:
|
||||||
|
batch_op.drop_constraint('uq_music_file_path', type_='unique')
|
||||||
|
batch_op.drop_index(batch_op.f('ix_music_title'))
|
||||||
|
batch_op.drop_index(batch_op.f('ix_music_id'))
|
||||||
|
batch_op.drop_index(batch_op.f('ix_music_artist'))
|
||||||
|
op.drop_table('music')
|
||||||
# ### end Alembic commands ###
|
# ### end Alembic commands ###
|
||||||
|
|||||||
@@ -1,51 +0,0 @@
|
|||||||
"""Populate file_location and file_format
|
|
||||||
|
|
||||||
Revision ID: 49793394b596
|
|
||||||
Revises: c1fd223a3556
|
|
||||||
Create Date: 2025-10-30 21:56:40.131970
|
|
||||||
|
|
||||||
"""
|
|
||||||
from typing import Sequence, Union
|
|
||||||
|
|
||||||
from alembic import op
|
|
||||||
import sqlalchemy as sa
|
|
||||||
|
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
|
||||||
revision: str = '49793394b596'
|
|
||||||
down_revision: Union[str, Sequence[str], None] = 'c1fd223a3556'
|
|
||||||
branch_labels: Union[str, Sequence[str], None] = None
|
|
||||||
depends_on: Union[str, Sequence[str], None] = None
|
|
||||||
|
|
||||||
|
|
||||||
def upgrade() -> None:
|
|
||||||
"""Upgrade schema."""
|
|
||||||
# Populate file_location from MUSIC_DIR + file_path for existing records
|
|
||||||
# Note: This uses SQLite-specific syntax
|
|
||||||
op.execute("""
|
|
||||||
UPDATE music
|
|
||||||
SET file_location = './data/music/' || file_path
|
|
||||||
WHERE file_location IS NULL OR file_location = ''
|
|
||||||
""")
|
|
||||||
|
|
||||||
# Populate file_format from file_path extension
|
|
||||||
op.execute("""
|
|
||||||
UPDATE music
|
|
||||||
SET file_format = LOWER(
|
|
||||||
CASE
|
|
||||||
WHEN file_path LIKE '%.mp3' THEN 'mp3'
|
|
||||||
WHEN file_path LIKE '%.m4a' THEN 'm4a'
|
|
||||||
WHEN file_path LIKE '%.flac' THEN 'flac'
|
|
||||||
WHEN file_path LIKE '%.wav' THEN 'wav'
|
|
||||||
WHEN file_path LIKE '%.ogg' THEN 'ogg'
|
|
||||||
WHEN file_path LIKE '%.opus' THEN 'opus'
|
|
||||||
ELSE SUBSTR(file_path, INSTR(file_path, '.') + 1)
|
|
||||||
END
|
|
||||||
)
|
|
||||||
WHERE file_format IS NULL OR file_format = ''
|
|
||||||
""")
|
|
||||||
|
|
||||||
|
|
||||||
def downgrade() -> None:
|
|
||||||
"""Downgrade schema."""
|
|
||||||
pass
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
"""Add file tracking columns
|
|
||||||
|
|
||||||
Revision ID: c1fd223a3556
|
|
||||||
Revises: 01209c730b33
|
|
||||||
Create Date: 2025-10-30 21:48:22.894324
|
|
||||||
|
|
||||||
"""
|
|
||||||
from typing import Sequence, Union
|
|
||||||
|
|
||||||
from alembic import op
|
|
||||||
import sqlalchemy as sa
|
|
||||||
|
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
|
||||||
revision: str = 'c1fd223a3556'
|
|
||||||
down_revision: Union[str, Sequence[str], None] = '01209c730b33'
|
|
||||||
branch_labels: Union[str, Sequence[str], None] = None
|
|
||||||
depends_on: Union[str, Sequence[str], None] = None
|
|
||||||
|
|
||||||
|
|
||||||
def upgrade() -> None:
|
|
||||||
"""Upgrade schema."""
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
with op.batch_alter_table('music', schema=None) as batch_op:
|
|
||||||
batch_op.add_column(sa.Column('file_format', sa.String(), nullable=True))
|
|
||||||
batch_op.add_column(sa.Column('file_location', sa.String(), nullable=True))
|
|
||||||
batch_op.add_column(sa.Column('file_exists', sa.Boolean(), nullable=True))
|
|
||||||
batch_op.add_column(sa.Column('last_scanned_at', sa.DateTime(), nullable=True))
|
|
||||||
|
|
||||||
# Set default value for existing records
|
|
||||||
op.execute("UPDATE music SET file_exists = 1 WHERE file_exists IS NULL")
|
|
||||||
# ### end Alembic commands ###
|
|
||||||
|
|
||||||
|
|
||||||
def downgrade() -> None:
|
|
||||||
"""Downgrade schema."""
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
with op.batch_alter_table('music', schema=None) as batch_op:
|
|
||||||
batch_op.drop_column('last_scanned_at')
|
|
||||||
batch_op.drop_column('file_exists')
|
|
||||||
batch_op.drop_column('file_location')
|
|
||||||
batch_op.drop_column('file_format')
|
|
||||||
|
|
||||||
# ### end Alembic commands ###
|
|
||||||
@@ -29,5 +29,12 @@ async def get_db():
|
|||||||
|
|
||||||
|
|
||||||
async def init_db():
|
async def init_db():
|
||||||
|
"""Initialize database connection pool
|
||||||
|
|
||||||
|
Note: Table creation is handled by Alembic migrations.
|
||||||
|
This function just ensures the connection pool is ready.
|
||||||
|
"""
|
||||||
|
# Just test the connection
|
||||||
async with engine.begin() as conn:
|
async with engine.begin() as conn:
|
||||||
await conn.run_sync(Base.metadata.create_all)
|
# Connection pool is ready
|
||||||
|
pass
|
||||||
|
|||||||
+2
-3
@@ -80,9 +80,8 @@ async def lifespan(app: FastAPI):
|
|||||||
os.makedirs(settings.LOCAL_MUSIC_DIR, exist_ok=True)
|
os.makedirs(settings.LOCAL_MUSIC_DIR, exist_ok=True)
|
||||||
print(f"✅ LOCAL_MUSIC_DIR created: {settings.LOCAL_MUSIC_DIR}")
|
print(f"✅ LOCAL_MUSIC_DIR created: {settings.LOCAL_MUSIC_DIR}")
|
||||||
|
|
||||||
# Run database migrations
|
# Note: Database migrations are run by start.sh before uvicorn starts
|
||||||
await run_migrations()
|
# We just initialize the connection pool here
|
||||||
|
|
||||||
await init_db()
|
await init_db()
|
||||||
|
|
||||||
# Start scheduler
|
# Start scheduler
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ services:
|
|||||||
- "8000:8000"
|
- "8000:8000"
|
||||||
volumes:
|
volumes:
|
||||||
- ./data:/app/data
|
- ./data:/app/data
|
||||||
|
- /Users/junv/Music/网易云音乐:/app/data/local-music
|
||||||
environment:
|
environment:
|
||||||
- PYTHONUNBUFFERED=1
|
- PYTHONUNBUFFERED=1
|
||||||
- PYTHONPATH=/app/backend
|
- PYTHONPATH=/app/backend
|
||||||
|
|||||||
Reference in New Issue
Block a user