Fix migration package name mismatch
This commit is contained in:
@@ -0,0 +1,184 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/navidrome/navidrome/log"
|
||||
"github.com/pressly/goose/v3"
|
||||
)
|
||||
|
||||
func init() {
|
||||
goose.AddMigrationContext(Up20200130083147, Down20200130083147)
|
||||
}
|
||||
|
||||
func Up20200130083147(_ context.Context, tx *sql.Tx) error {
|
||||
log.Info("Creating DB Schema")
|
||||
_, err := tx.Exec(`
|
||||
create table if not exists album
|
||||
(
|
||||
id varchar(255) not null
|
||||
primary key,
|
||||
name varchar(255) default '' not null,
|
||||
artist_id varchar(255) default '' not null,
|
||||
cover_art_path varchar(255) default '' not null,
|
||||
cover_art_id varchar(255) default '' not null,
|
||||
artist varchar(255) default '' not null,
|
||||
album_artist varchar(255) default '' not null,
|
||||
year integer default 0 not null,
|
||||
compilation bool default FALSE not null,
|
||||
song_count integer default 0 not null,
|
||||
duration integer default 0 not null,
|
||||
genre varchar(255) default '' not null,
|
||||
created_at datetime,
|
||||
updated_at datetime
|
||||
);
|
||||
|
||||
create index if not exists album_artist
|
||||
on album (artist);
|
||||
|
||||
create index if not exists album_artist_id
|
||||
on album (artist_id);
|
||||
|
||||
create index if not exists album_genre
|
||||
on album (genre);
|
||||
|
||||
create index if not exists album_name
|
||||
on album (name);
|
||||
|
||||
create index if not exists album_year
|
||||
on album (year);
|
||||
|
||||
create table if not exists annotation
|
||||
(
|
||||
ann_id varchar(255) not null
|
||||
primary key,
|
||||
user_id varchar(255) default '' not null,
|
||||
item_id varchar(255) default '' not null,
|
||||
item_type varchar(255) default '' not null,
|
||||
play_count integer,
|
||||
play_date datetime,
|
||||
rating integer,
|
||||
starred bool default FALSE not null,
|
||||
starred_at datetime,
|
||||
unique (user_id, item_id, item_type)
|
||||
);
|
||||
|
||||
create index if not exists annotation_play_count
|
||||
on annotation (play_count);
|
||||
|
||||
create index if not exists annotation_play_date
|
||||
on annotation (play_date);
|
||||
|
||||
create index if not exists annotation_rating
|
||||
on annotation (rating);
|
||||
|
||||
create index if not exists annotation_starred
|
||||
on annotation (starred);
|
||||
|
||||
create table if not exists artist
|
||||
(
|
||||
id varchar(255) not null
|
||||
primary key,
|
||||
name varchar(255) default '' not null,
|
||||
album_count integer default 0 not null
|
||||
);
|
||||
|
||||
create index if not exists artist_name
|
||||
on artist (name);
|
||||
|
||||
create table if not exists media_file
|
||||
(
|
||||
id varchar(255) not null
|
||||
primary key,
|
||||
path varchar(255) default '' not null,
|
||||
title varchar(255) default '' not null,
|
||||
album varchar(255) default '' not null,
|
||||
artist varchar(255) default '' not null,
|
||||
artist_id varchar(255) default '' not null,
|
||||
album_artist varchar(255) default '' not null,
|
||||
album_id varchar(255) default '' not null,
|
||||
has_cover_art bool default FALSE not null,
|
||||
track_number integer default 0 not null,
|
||||
disc_number integer default 0 not null,
|
||||
year integer default 0 not null,
|
||||
size integer default 0 not null,
|
||||
suffix varchar(255) default '' not null,
|
||||
duration integer default 0 not null,
|
||||
bit_rate integer default 0 not null,
|
||||
genre varchar(255) default '' not null,
|
||||
compilation bool default FALSE not null,
|
||||
created_at datetime,
|
||||
updated_at datetime
|
||||
);
|
||||
|
||||
create index if not exists media_file_album_id
|
||||
on media_file (album_id);
|
||||
|
||||
create index if not exists media_file_genre
|
||||
on media_file (genre);
|
||||
|
||||
create index if not exists media_file_path
|
||||
on media_file (path);
|
||||
|
||||
create index if not exists media_file_title
|
||||
on media_file (title);
|
||||
|
||||
create table if not exists playlist
|
||||
(
|
||||
id varchar(255) not null
|
||||
primary key,
|
||||
name varchar(255) default '' not null,
|
||||
comment varchar(255) default '' not null,
|
||||
duration integer default 0 not null,
|
||||
owner varchar(255) default '' not null,
|
||||
public bool default FALSE not null,
|
||||
tracks text not null
|
||||
);
|
||||
|
||||
create index if not exists playlist_name
|
||||
on playlist (name);
|
||||
|
||||
create table if not exists property
|
||||
(
|
||||
id varchar(255) not null
|
||||
primary key,
|
||||
value varchar(255) default '' not null
|
||||
);
|
||||
|
||||
create table if not exists search
|
||||
(
|
||||
id varchar(255) not null
|
||||
primary key,
|
||||
"table" varchar(255) default '' not null,
|
||||
full_text varchar(255) default '' not null
|
||||
);
|
||||
|
||||
create index if not exists search_full_text
|
||||
on search (full_text);
|
||||
|
||||
create index if not exists search_table
|
||||
on search ("table");
|
||||
|
||||
create table if not exists user
|
||||
(
|
||||
id varchar(255) not null
|
||||
primary key,
|
||||
user_name varchar(255) default '' not null
|
||||
unique,
|
||||
name varchar(255) default '' not null,
|
||||
email varchar(255) default '' not null
|
||||
unique,
|
||||
password varchar(255) default '' not null,
|
||||
is_admin bool default FALSE not null,
|
||||
last_login_at datetime,
|
||||
last_access_at datetime,
|
||||
created_at datetime not null,
|
||||
updated_at datetime not null
|
||||
);`)
|
||||
return err
|
||||
}
|
||||
|
||||
func Down20200130083147(_ context.Context, tx *sql.Tx) error {
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/pressly/goose/v3"
|
||||
)
|
||||
|
||||
func init() {
|
||||
goose.AddMigrationContext(Up20200131183653, Down20200131183653)
|
||||
}
|
||||
|
||||
func Up20200131183653(_ context.Context, tx *sql.Tx) error {
|
||||
_, err := tx.Exec(`
|
||||
create table search_dg_tmp
|
||||
(
|
||||
id varchar(255) not null
|
||||
primary key,
|
||||
item_type varchar(255) default '' not null,
|
||||
full_text varchar(255) default '' not null
|
||||
);
|
||||
|
||||
insert into search_dg_tmp(id, item_type, full_text) select id, "table", full_text from search;
|
||||
|
||||
drop table search;
|
||||
|
||||
alter table search_dg_tmp rename to search;
|
||||
|
||||
create index search_full_text
|
||||
on search (full_text);
|
||||
create index search_table
|
||||
on search (item_type);
|
||||
|
||||
update annotation set item_type = 'media_file' where item_type = 'mediaFile';
|
||||
`)
|
||||
return err
|
||||
}
|
||||
|
||||
func Down20200131183653(_ context.Context, tx *sql.Tx) error {
|
||||
_, err := tx.Exec(`
|
||||
create table search_dg_tmp
|
||||
(
|
||||
id varchar(255) not null
|
||||
primary key,
|
||||
"table" varchar(255) default '' not null,
|
||||
full_text varchar(255) default '' not null
|
||||
);
|
||||
|
||||
insert into search_dg_tmp(id, "table", full_text) select id, item_type, full_text from search;
|
||||
|
||||
drop table search;
|
||||
|
||||
alter table search_dg_tmp rename to search;
|
||||
|
||||
create index search_full_text
|
||||
on search (full_text);
|
||||
create index search_table
|
||||
on search ("table");
|
||||
|
||||
update annotation set item_type = 'mediaFile' where item_type = 'media_file';
|
||||
`)
|
||||
return err
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/pressly/goose/v3"
|
||||
)
|
||||
|
||||
func init() {
|
||||
goose.AddMigrationContext(Up20200208222418, Down20200208222418)
|
||||
}
|
||||
|
||||
func Up20200208222418(_ context.Context, tx *sql.Tx) error {
|
||||
_, err := tx.Exec(`
|
||||
update annotation set play_count = 0 where play_count is null;
|
||||
update annotation set rating = 0 where rating is null;
|
||||
create table annotation_dg_tmp
|
||||
(
|
||||
ann_id varchar(255) not null
|
||||
primary key,
|
||||
user_id varchar(255) default '' not null,
|
||||
item_id varchar(255) default '' not null,
|
||||
item_type varchar(255) default '' not null,
|
||||
play_count integer default 0,
|
||||
play_date datetime,
|
||||
rating integer default 0,
|
||||
starred bool default FALSE not null,
|
||||
starred_at datetime,
|
||||
unique (user_id, item_id, item_type)
|
||||
);
|
||||
|
||||
insert into annotation_dg_tmp(ann_id, user_id, item_id, item_type, play_count, play_date, rating, starred, starred_at) select ann_id, user_id, item_id, item_type, play_count, play_date, rating, starred, starred_at from annotation;
|
||||
|
||||
drop table annotation;
|
||||
|
||||
alter table annotation_dg_tmp rename to annotation;
|
||||
|
||||
create index annotation_play_count
|
||||
on annotation (play_count);
|
||||
|
||||
create index annotation_play_date
|
||||
on annotation (play_date);
|
||||
|
||||
create index annotation_rating
|
||||
on annotation (rating);
|
||||
|
||||
create index annotation_starred
|
||||
on annotation (starred);
|
||||
`)
|
||||
return err
|
||||
}
|
||||
|
||||
func Down20200208222418(_ context.Context, tx *sql.Tx) error {
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/pressly/goose/v3"
|
||||
)
|
||||
|
||||
func init() {
|
||||
goose.AddMigrationContext(Up20200220143731, Down20200220143731)
|
||||
}
|
||||
|
||||
func Up20200220143731(_ context.Context, tx *sql.Tx) error {
|
||||
notice(tx, "This migration will force the next scan to be a full rescan!")
|
||||
_, err := tx.Exec(`
|
||||
create table media_file_dg_tmp
|
||||
(
|
||||
id varchar(255) not null
|
||||
primary key,
|
||||
path varchar(255) default '' not null,
|
||||
title varchar(255) default '' not null,
|
||||
album varchar(255) default '' not null,
|
||||
artist varchar(255) default '' not null,
|
||||
artist_id varchar(255) default '' not null,
|
||||
album_artist varchar(255) default '' not null,
|
||||
album_id varchar(255) default '' not null,
|
||||
has_cover_art bool default FALSE not null,
|
||||
track_number integer default 0 not null,
|
||||
disc_number integer default 0 not null,
|
||||
year integer default 0 not null,
|
||||
size integer default 0 not null,
|
||||
suffix varchar(255) default '' not null,
|
||||
duration real default 0 not null,
|
||||
bit_rate integer default 0 not null,
|
||||
genre varchar(255) default '' not null,
|
||||
compilation bool default FALSE not null,
|
||||
created_at datetime,
|
||||
updated_at datetime
|
||||
);
|
||||
|
||||
insert into media_file_dg_tmp(id, path, title, album, artist, artist_id, album_artist, album_id, has_cover_art, track_number, disc_number, year, size, suffix, duration, bit_rate, genre, compilation, created_at, updated_at) select id, path, title, album, artist, artist_id, album_artist, album_id, has_cover_art, track_number, disc_number, year, size, suffix, duration, bit_rate, genre, compilation, created_at, updated_at from media_file;
|
||||
|
||||
drop table media_file;
|
||||
|
||||
alter table media_file_dg_tmp rename to media_file;
|
||||
|
||||
create index media_file_album_id
|
||||
on media_file (album_id);
|
||||
|
||||
create index media_file_genre
|
||||
on media_file (genre);
|
||||
|
||||
create index media_file_path
|
||||
on media_file (path);
|
||||
|
||||
create index media_file_title
|
||||
on media_file (title);
|
||||
|
||||
create table album_dg_tmp
|
||||
(
|
||||
id varchar(255) not null
|
||||
primary key,
|
||||
name varchar(255) default '' not null,
|
||||
artist_id varchar(255) default '' not null,
|
||||
cover_art_path varchar(255) default '' not null,
|
||||
cover_art_id varchar(255) default '' not null,
|
||||
artist varchar(255) default '' not null,
|
||||
album_artist varchar(255) default '' not null,
|
||||
year integer default 0 not null,
|
||||
compilation bool default FALSE not null,
|
||||
song_count integer default 0 not null,
|
||||
duration real default 0 not null,
|
||||
genre varchar(255) default '' not null,
|
||||
created_at datetime,
|
||||
updated_at datetime
|
||||
);
|
||||
|
||||
insert into album_dg_tmp(id, name, artist_id, cover_art_path, cover_art_id, artist, album_artist, year, compilation, song_count, duration, genre, created_at, updated_at) select id, name, artist_id, cover_art_path, cover_art_id, artist, album_artist, year, compilation, song_count, duration, genre, created_at, updated_at from album;
|
||||
|
||||
drop table album;
|
||||
|
||||
alter table album_dg_tmp rename to album;
|
||||
|
||||
create index album_artist
|
||||
on album (artist);
|
||||
|
||||
create index album_artist_id
|
||||
on album (artist_id);
|
||||
|
||||
create index album_genre
|
||||
on album (genre);
|
||||
|
||||
create index album_name
|
||||
on album (name);
|
||||
|
||||
create index album_year
|
||||
on album (year);
|
||||
|
||||
create table playlist_dg_tmp
|
||||
(
|
||||
id varchar(255) not null
|
||||
primary key,
|
||||
name varchar(255) default '' not null,
|
||||
comment varchar(255) default '' not null,
|
||||
duration real default 0 not null,
|
||||
owner varchar(255) default '' not null,
|
||||
public bool default FALSE not null,
|
||||
tracks text not null
|
||||
);
|
||||
|
||||
insert into playlist_dg_tmp(id, name, comment, duration, owner, public, tracks) select id, name, comment, duration, owner, public, tracks from playlist;
|
||||
|
||||
drop table playlist;
|
||||
|
||||
alter table playlist_dg_tmp rename to playlist;
|
||||
|
||||
create index playlist_name
|
||||
on playlist (name);
|
||||
|
||||
-- Force a full rescan
|
||||
delete from property where id like 'LastScan%';
|
||||
update media_file set updated_at = '0001-01-01';
|
||||
`)
|
||||
return err
|
||||
}
|
||||
|
||||
func Down20200220143731(_ context.Context, tx *sql.Tx) error {
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/pressly/goose/v3"
|
||||
)
|
||||
|
||||
func init() {
|
||||
goose.AddMigrationContext(Up20200310171621, Down20200310171621)
|
||||
}
|
||||
|
||||
func Up20200310171621(_ context.Context, tx *sql.Tx) error {
|
||||
notice(tx, "A full rescan will be performed to enable search by Album Artist!")
|
||||
return forceFullRescan(tx)
|
||||
}
|
||||
|
||||
func Down20200310171621(_ context.Context, tx *sql.Tx) error {
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/pressly/goose/v3"
|
||||
)
|
||||
|
||||
func init() {
|
||||
goose.AddMigrationContext(Up20200310181627, Down20200310181627)
|
||||
}
|
||||
|
||||
func Up20200310181627(_ context.Context, tx *sql.Tx) error {
|
||||
_, err := tx.Exec(`
|
||||
create table transcoding
|
||||
(
|
||||
id varchar(255) not null primary key,
|
||||
name varchar(255) not null,
|
||||
target_format varchar(255) not null,
|
||||
command varchar(255) default '' not null,
|
||||
default_bit_rate int default 192,
|
||||
unique (name),
|
||||
unique (target_format)
|
||||
);
|
||||
|
||||
create table player
|
||||
(
|
||||
id varchar(255) not null primary key,
|
||||
name varchar not null,
|
||||
type varchar,
|
||||
user_name varchar not null,
|
||||
client varchar not null,
|
||||
ip_address varchar,
|
||||
last_seen timestamp,
|
||||
max_bit_rate int default 0,
|
||||
transcoding_id varchar,
|
||||
unique (name),
|
||||
foreign key (transcoding_id)
|
||||
references transcoding(id)
|
||||
on update restrict
|
||||
on delete restrict
|
||||
);
|
||||
`)
|
||||
return err
|
||||
}
|
||||
|
||||
func Down20200310181627(_ context.Context, tx *sql.Tx) error {
|
||||
_, err := tx.Exec(`
|
||||
drop table transcoding;
|
||||
drop table player;
|
||||
`)
|
||||
return err
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/pressly/goose/v3"
|
||||
)
|
||||
|
||||
func init() {
|
||||
goose.AddMigrationContext(Up20200319211049, Down20200319211049)
|
||||
}
|
||||
|
||||
func Up20200319211049(_ context.Context, tx *sql.Tx) error {
|
||||
_, err := tx.Exec(`
|
||||
alter table media_file
|
||||
add full_text varchar(255) default '';
|
||||
create index if not exists media_file_full_text
|
||||
on media_file (full_text);
|
||||
|
||||
alter table album
|
||||
add full_text varchar(255) default '';
|
||||
create index if not exists album_full_text
|
||||
on album (full_text);
|
||||
|
||||
alter table artist
|
||||
add full_text varchar(255) default '';
|
||||
create index if not exists artist_full_text
|
||||
on artist (full_text);
|
||||
|
||||
drop table if exists search;
|
||||
`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
notice(tx, "A full rescan will be performed!")
|
||||
return forceFullRescan(tx)
|
||||
}
|
||||
|
||||
func Down20200319211049(_ context.Context, tx *sql.Tx) error {
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/pressly/goose/v3"
|
||||
)
|
||||
|
||||
func init() {
|
||||
goose.AddMigrationContext(Up20200325185135, Down20200325185135)
|
||||
}
|
||||
|
||||
func Up20200325185135(_ context.Context, tx *sql.Tx) error {
|
||||
_, err := tx.Exec(`
|
||||
alter table album
|
||||
add album_artist_id varchar(255) default '';
|
||||
create index album_artist_album_id
|
||||
on album (album_artist_id);
|
||||
|
||||
alter table media_file
|
||||
add album_artist_id varchar(255) default '';
|
||||
create index media_file_artist_album_id
|
||||
on media_file (album_artist_id);
|
||||
`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
notice(tx, "A full rescan will be performed!")
|
||||
return forceFullRescan(tx)
|
||||
}
|
||||
|
||||
func Down20200325185135(_ context.Context, tx *sql.Tx) error {
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/pressly/goose/v3"
|
||||
)
|
||||
|
||||
func init() {
|
||||
goose.AddMigrationContext(Up20200326090707, Down20200326090707)
|
||||
}
|
||||
|
||||
func Up20200326090707(_ context.Context, tx *sql.Tx) error {
|
||||
notice(tx, "A full rescan will be performed!")
|
||||
return forceFullRescan(tx)
|
||||
}
|
||||
|
||||
func Down20200326090707(_ context.Context, tx *sql.Tx) error {
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/pressly/goose/v3"
|
||||
)
|
||||
|
||||
func init() {
|
||||
goose.AddMigrationContext(Up20200327193744, Down20200327193744)
|
||||
}
|
||||
|
||||
func Up20200327193744(_ context.Context, tx *sql.Tx) error {
|
||||
_, err := tx.Exec(`
|
||||
create table album_dg_tmp
|
||||
(
|
||||
id varchar(255) not null
|
||||
primary key,
|
||||
name varchar(255) default '' not null,
|
||||
artist_id varchar(255) default '' not null,
|
||||
cover_art_path varchar(255) default '' not null,
|
||||
cover_art_id varchar(255) default '' not null,
|
||||
artist varchar(255) default '' not null,
|
||||
album_artist varchar(255) default '' not null,
|
||||
min_year int default 0 not null,
|
||||
max_year integer default 0 not null,
|
||||
compilation bool default FALSE not null,
|
||||
song_count integer default 0 not null,
|
||||
duration real default 0 not null,
|
||||
genre varchar(255) default '' not null,
|
||||
created_at datetime,
|
||||
updated_at datetime,
|
||||
full_text varchar(255) default '',
|
||||
album_artist_id varchar(255) default ''
|
||||
);
|
||||
|
||||
insert into album_dg_tmp(id, name, artist_id, cover_art_path, cover_art_id, artist, album_artist, max_year, compilation, song_count, duration, genre, created_at, updated_at, full_text, album_artist_id) select id, name, artist_id, cover_art_path, cover_art_id, artist, album_artist, year, compilation, song_count, duration, genre, created_at, updated_at, full_text, album_artist_id from album;
|
||||
|
||||
drop table album;
|
||||
|
||||
alter table album_dg_tmp rename to album;
|
||||
|
||||
create index album_artist
|
||||
on album (artist);
|
||||
|
||||
create index album_artist_album
|
||||
on album (artist);
|
||||
|
||||
create index album_artist_album_id
|
||||
on album (album_artist_id);
|
||||
|
||||
create index album_artist_id
|
||||
on album (artist_id);
|
||||
|
||||
create index album_full_text
|
||||
on album (full_text);
|
||||
|
||||
create index album_genre
|
||||
on album (genre);
|
||||
|
||||
create index album_name
|
||||
on album (name);
|
||||
|
||||
create index album_min_year
|
||||
on album (min_year);
|
||||
|
||||
create index album_max_year
|
||||
on album (max_year);
|
||||
|
||||
`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
notice(tx, "A full rescan will be performed!")
|
||||
return forceFullRescan(tx)
|
||||
}
|
||||
|
||||
func Down20200327193744(_ context.Context, tx *sql.Tx) error {
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/pressly/goose/v3"
|
||||
)
|
||||
|
||||
func init() {
|
||||
goose.AddMigrationContext(Up20200404214704, Down20200404214704)
|
||||
}
|
||||
|
||||
func Up20200404214704(_ context.Context, tx *sql.Tx) error {
|
||||
_, err := tx.Exec(`
|
||||
create index if not exists media_file_year
|
||||
on media_file (year);
|
||||
|
||||
create index if not exists media_file_duration
|
||||
on media_file (duration);
|
||||
|
||||
create index if not exists media_file_track_number
|
||||
on media_file (disc_number, track_number);
|
||||
`)
|
||||
return err
|
||||
}
|
||||
|
||||
func Down20200404214704(_ context.Context, tx *sql.Tx) error {
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/pressly/goose/v3"
|
||||
)
|
||||
|
||||
func init() {
|
||||
goose.AddMigrationContext(Up20200409002249, Down20200409002249)
|
||||
}
|
||||
|
||||
func Up20200409002249(_ context.Context, tx *sql.Tx) error {
|
||||
notice(tx, "A full rescan will be performed to enable search by individual Artist in an Album!")
|
||||
return forceFullRescan(tx)
|
||||
}
|
||||
|
||||
func Down20200409002249(_ context.Context, tx *sql.Tx) error {
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/pressly/goose/v3"
|
||||
)
|
||||
|
||||
func init() {
|
||||
goose.AddMigrationContext(Up20200411164603, Down20200411164603)
|
||||
}
|
||||
|
||||
func Up20200411164603(_ context.Context, tx *sql.Tx) error {
|
||||
_, err := tx.Exec(`
|
||||
alter table playlist
|
||||
add created_at datetime;
|
||||
alter table playlist
|
||||
add updated_at datetime;
|
||||
update playlist
|
||||
set created_at = datetime('now'), updated_at = datetime('now');
|
||||
`)
|
||||
return err
|
||||
}
|
||||
|
||||
func Down20200411164603(_ context.Context, tx *sql.Tx) error {
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/pressly/goose/v3"
|
||||
)
|
||||
|
||||
func init() {
|
||||
goose.AddMigrationContext(Up20200418110522, Down20200418110522)
|
||||
}
|
||||
|
||||
func Up20200418110522(_ context.Context, tx *sql.Tx) error {
|
||||
notice(tx, "A full rescan will be performed to fix search Albums by year")
|
||||
return forceFullRescan(tx)
|
||||
}
|
||||
|
||||
func Down20200418110522(_ context.Context, tx *sql.Tx) error {
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/pressly/goose/v3"
|
||||
)
|
||||
|
||||
func init() {
|
||||
goose.AddMigrationContext(Up20200419222708, Down20200419222708)
|
||||
}
|
||||
|
||||
func Up20200419222708(_ context.Context, tx *sql.Tx) error {
|
||||
notice(tx, "A full rescan will be performed to change the search behaviour")
|
||||
return forceFullRescan(tx)
|
||||
}
|
||||
|
||||
func Down20200419222708(_ context.Context, tx *sql.Tx) error {
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/pressly/goose/v3"
|
||||
)
|
||||
|
||||
func init() {
|
||||
goose.AddMigrationContext(Up20200423204116, Down20200423204116)
|
||||
}
|
||||
|
||||
func Up20200423204116(_ context.Context, tx *sql.Tx) error {
|
||||
_, err := tx.Exec(`
|
||||
alter table artist
|
||||
add order_artist_name varchar(255) collate nocase;
|
||||
alter table artist
|
||||
add sort_artist_name varchar(255) collate nocase;
|
||||
create index if not exists artist_order_artist_name
|
||||
on artist (order_artist_name);
|
||||
|
||||
alter table album
|
||||
add order_album_name varchar(255) collate nocase;
|
||||
alter table album
|
||||
add order_album_artist_name varchar(255) collate nocase;
|
||||
alter table album
|
||||
add sort_album_name varchar(255) collate nocase;
|
||||
alter table album
|
||||
add sort_artist_name varchar(255) collate nocase;
|
||||
alter table album
|
||||
add sort_album_artist_name varchar(255) collate nocase;
|
||||
create index if not exists album_order_album_name
|
||||
on album (order_album_name);
|
||||
create index if not exists album_order_album_artist_name
|
||||
on album (order_album_artist_name);
|
||||
|
||||
alter table media_file
|
||||
add order_album_name varchar(255) collate nocase;
|
||||
alter table media_file
|
||||
add order_album_artist_name varchar(255) collate nocase;
|
||||
alter table media_file
|
||||
add order_artist_name varchar(255) collate nocase;
|
||||
alter table media_file
|
||||
add sort_album_name varchar(255) collate nocase;
|
||||
alter table media_file
|
||||
add sort_artist_name varchar(255) collate nocase;
|
||||
alter table media_file
|
||||
add sort_album_artist_name varchar(255) collate nocase;
|
||||
alter table media_file
|
||||
add sort_title varchar(255) collate nocase;
|
||||
create index if not exists media_file_order_album_name
|
||||
on media_file (order_album_name);
|
||||
create index if not exists media_file_order_artist_name
|
||||
on media_file (order_artist_name);
|
||||
`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
notice(tx, "A full rescan will be performed to change the search behaviour")
|
||||
return forceFullRescan(tx)
|
||||
}
|
||||
|
||||
func Down20200423204116(_ context.Context, tx *sql.Tx) error {
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/pressly/goose/v3"
|
||||
)
|
||||
|
||||
func init() {
|
||||
goose.AddMigrationContext(Up20200508093059, Down20200508093059)
|
||||
}
|
||||
|
||||
func Up20200508093059(_ context.Context, tx *sql.Tx) error {
|
||||
_, err := tx.Exec(`
|
||||
alter table artist
|
||||
add song_count integer default 0 not null;
|
||||
`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
notice(tx, "A full rescan will be performed to calculate artists' song counts")
|
||||
return forceFullRescan(tx)
|
||||
}
|
||||
|
||||
func Down20200508093059(_ context.Context, tx *sql.Tx) error {
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/pressly/goose/v3"
|
||||
)
|
||||
|
||||
func init() {
|
||||
goose.AddMigrationContext(Up20200512104202, Down20200512104202)
|
||||
}
|
||||
|
||||
func Up20200512104202(_ context.Context, tx *sql.Tx) error {
|
||||
_, err := tx.Exec(`
|
||||
alter table media_file
|
||||
add disc_subtitle varchar(255);
|
||||
`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
notice(tx, "A full rescan will be performed to import disc subtitles")
|
||||
return forceFullRescan(tx)
|
||||
}
|
||||
|
||||
func Down20200512104202(_ context.Context, tx *sql.Tx) error {
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"strings"
|
||||
|
||||
"github.com/navidrome/navidrome/log"
|
||||
"github.com/pressly/goose/v3"
|
||||
)
|
||||
|
||||
func init() {
|
||||
goose.AddMigrationContext(Up20200516140647, Down20200516140647)
|
||||
}
|
||||
|
||||
func Up20200516140647(_ context.Context, tx *sql.Tx) error {
|
||||
_, err := tx.Exec(`
|
||||
create table if not exists playlist_tracks
|
||||
(
|
||||
id integer default 0 not null,
|
||||
playlist_id varchar(255) not null,
|
||||
media_file_id varchar(255) not null
|
||||
);
|
||||
|
||||
create unique index if not exists playlist_tracks_pos
|
||||
on playlist_tracks (playlist_id, id);
|
||||
`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rows, err := tx.Query("select id, tracks from playlist")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer rows.Close()
|
||||
var id, tracks string
|
||||
for rows.Next() {
|
||||
err := rows.Scan(&id, &tracks)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = Up20200516140647UpdatePlaylistTracks(tx, id, tracks)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
err = rows.Err()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = tx.Exec(`
|
||||
create table playlist_dg_tmp
|
||||
(
|
||||
id varchar(255) not null
|
||||
primary key,
|
||||
name varchar(255) default '' not null,
|
||||
comment varchar(255) default '' not null,
|
||||
duration real default 0 not null,
|
||||
song_count integer default 0 not null,
|
||||
owner varchar(255) default '' not null,
|
||||
public bool default FALSE not null,
|
||||
created_at datetime,
|
||||
updated_at datetime
|
||||
);
|
||||
|
||||
insert into playlist_dg_tmp(id, name, comment, duration, owner, public, created_at, updated_at)
|
||||
select id, name, comment, duration, owner, public, created_at, updated_at from playlist;
|
||||
|
||||
drop table playlist;
|
||||
|
||||
alter table playlist_dg_tmp rename to playlist;
|
||||
|
||||
create index playlist_name
|
||||
on playlist (name);
|
||||
|
||||
update playlist set song_count = (select count(*) from playlist_tracks where playlist_id = playlist.id)
|
||||
where id <> ''
|
||||
|
||||
`)
|
||||
return err
|
||||
}
|
||||
|
||||
func Up20200516140647UpdatePlaylistTracks(tx *sql.Tx, id string, tracks string) error {
|
||||
trackList := strings.Split(tracks, ",")
|
||||
stmt, err := tx.Prepare("insert into playlist_tracks (playlist_id, media_file_id, id) values (?, ?, ?)")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for i, trackId := range trackList {
|
||||
_, err := stmt.Exec(id, trackId, i+1)
|
||||
if err != nil {
|
||||
log.Error("Error adding track to playlist", "playlistId", id, "trackId", trackId, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func Down20200516140647(_ context.Context, tx *sql.Tx) error {
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/pressly/goose/v3"
|
||||
)
|
||||
|
||||
func init() {
|
||||
goose.AddMigrationContext(Up20200608153717, Down20200608153717)
|
||||
}
|
||||
|
||||
func Up20200608153717(_ context.Context, tx *sql.Tx) error {
|
||||
// First delete dangling players
|
||||
_, err := tx.Exec(`
|
||||
delete from player where user_name not in (select user_name from user)`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Also delete dangling players
|
||||
_, err = tx.Exec(`
|
||||
delete from playlist where owner not in (select user_name from user)`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Also delete dangling playlist tracks
|
||||
_, err = tx.Exec(`
|
||||
delete from playlist_tracks where playlist_id not in (select id from playlist)`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Add foreign key to player table
|
||||
err = updatePlayer_20200608153717(tx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Add foreign key to playlist table
|
||||
err = updatePlaylist_20200608153717(tx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Add foreign keys to playlist_tracks table
|
||||
return updatePlaylistTracks_20200608153717(tx)
|
||||
}
|
||||
|
||||
func updatePlayer_20200608153717(tx *sql.Tx) error {
|
||||
_, err := tx.Exec(`
|
||||
create table player_dg_tmp
|
||||
(
|
||||
id varchar(255) not null
|
||||
primary key,
|
||||
name varchar not null
|
||||
unique,
|
||||
type varchar,
|
||||
user_name varchar not null
|
||||
references user (user_name)
|
||||
on update cascade on delete cascade,
|
||||
client varchar not null,
|
||||
ip_address varchar,
|
||||
last_seen timestamp,
|
||||
max_bit_rate int default 0,
|
||||
transcoding_id varchar null
|
||||
);
|
||||
|
||||
insert into player_dg_tmp(id, name, type, user_name, client, ip_address, last_seen, max_bit_rate, transcoding_id) select id, name, type, user_name, client, ip_address, last_seen, max_bit_rate, transcoding_id from player;
|
||||
|
||||
drop table player;
|
||||
|
||||
alter table player_dg_tmp rename to player;
|
||||
`)
|
||||
return err
|
||||
}
|
||||
|
||||
func updatePlaylist_20200608153717(tx *sql.Tx) error {
|
||||
_, err := tx.Exec(`
|
||||
create table playlist_dg_tmp
|
||||
(
|
||||
id varchar(255) not null
|
||||
primary key,
|
||||
name varchar(255) default '' not null,
|
||||
comment varchar(255) default '' not null,
|
||||
duration real default 0 not null,
|
||||
song_count integer default 0 not null,
|
||||
owner varchar(255) default '' not null
|
||||
constraint playlist_user_user_name_fk
|
||||
references user (user_name)
|
||||
on update cascade on delete cascade,
|
||||
public bool default FALSE not null,
|
||||
created_at datetime,
|
||||
updated_at datetime
|
||||
);
|
||||
|
||||
insert into playlist_dg_tmp(id, name, comment, duration, song_count, owner, public, created_at, updated_at) select id, name, comment, duration, song_count, owner, public, created_at, updated_at from playlist;
|
||||
|
||||
drop table playlist;
|
||||
|
||||
alter table playlist_dg_tmp rename to playlist;
|
||||
|
||||
create index playlist_name
|
||||
on playlist (name);
|
||||
`)
|
||||
return err
|
||||
}
|
||||
|
||||
func updatePlaylistTracks_20200608153717(tx *sql.Tx) error {
|
||||
_, err := tx.Exec(`
|
||||
create table playlist_tracks_dg_tmp
|
||||
(
|
||||
id integer default 0 not null,
|
||||
playlist_id varchar(255) not null
|
||||
constraint playlist_tracks_playlist_id_fk
|
||||
references playlist
|
||||
on update cascade on delete cascade,
|
||||
media_file_id varchar(255) not null
|
||||
);
|
||||
|
||||
insert into playlist_tracks_dg_tmp(id, playlist_id, media_file_id) select id, playlist_id, media_file_id from playlist_tracks;
|
||||
|
||||
drop table playlist_tracks;
|
||||
|
||||
alter table playlist_tracks_dg_tmp rename to playlist_tracks;
|
||||
|
||||
create unique index playlist_tracks_pos
|
||||
on playlist_tracks (playlist_id, id);
|
||||
|
||||
`)
|
||||
return err
|
||||
}
|
||||
|
||||
func Down20200608153717(_ context.Context, tx *sql.Tx) error {
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/navidrome/navidrome/consts"
|
||||
"github.com/pressly/goose/v3"
|
||||
)
|
||||
|
||||
func init() {
|
||||
goose.AddMigrationContext(upAddDefaultTranscodings, downAddDefaultTranscodings)
|
||||
}
|
||||
|
||||
func upAddDefaultTranscodings(_ context.Context, tx *sql.Tx) error {
|
||||
row := tx.QueryRow("SELECT COUNT(*) FROM transcoding")
|
||||
var count int
|
||||
err := row.Scan(&count)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if count > 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
stmt, err := tx.Prepare("insert into transcoding (id, name, target_format, default_bit_rate, command) values (?, ?, ?, ?, ?)")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, t := range consts.DefaultTranscodings {
|
||||
_, err := stmt.Exec(uuid.NewString(), t.Name, t.TargetFormat, t.DefaultBitRate, t.Command)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func downAddDefaultTranscodings(_ context.Context, tx *sql.Tx) error {
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/pressly/goose/v3"
|
||||
)
|
||||
|
||||
func init() {
|
||||
goose.AddMigrationContext(upAddPlaylistPath, downAddPlaylistPath)
|
||||
}
|
||||
|
||||
func upAddPlaylistPath(_ context.Context, tx *sql.Tx) error {
|
||||
_, err := tx.Exec(`
|
||||
alter table playlist
|
||||
add path string default '' not null;
|
||||
|
||||
alter table playlist
|
||||
add sync bool default false not null;
|
||||
`)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func downAddPlaylistPath(_ context.Context, tx *sql.Tx) error {
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/pressly/goose/v3"
|
||||
)
|
||||
|
||||
func init() {
|
||||
goose.AddMigrationContext(upCreatePlayQueuesTable, downCreatePlayQueuesTable)
|
||||
}
|
||||
|
||||
func upCreatePlayQueuesTable(_ context.Context, tx *sql.Tx) error {
|
||||
_, err := tx.Exec(`
|
||||
create table playqueue
|
||||
(
|
||||
id varchar(255) not null primary key,
|
||||
user_id varchar(255) not null
|
||||
references user (id)
|
||||
on update cascade on delete cascade,
|
||||
comment varchar(255),
|
||||
current varchar(255) not null,
|
||||
position integer,
|
||||
changed_by varchar(255),
|
||||
items varchar(255),
|
||||
created_at datetime,
|
||||
updated_at datetime
|
||||
);
|
||||
`)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func downCreatePlayQueuesTable(_ context.Context, tx *sql.Tx) error {
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/pressly/goose/v3"
|
||||
)
|
||||
|
||||
func init() {
|
||||
goose.AddMigrationContext(upCreateBookmarkTable, downCreateBookmarkTable)
|
||||
}
|
||||
|
||||
func upCreateBookmarkTable(_ context.Context, tx *sql.Tx) error {
|
||||
_, err := tx.Exec(`
|
||||
create table bookmark
|
||||
(
|
||||
user_id varchar(255) not null
|
||||
references user
|
||||
on update cascade on delete cascade,
|
||||
item_id varchar(255) not null,
|
||||
item_type varchar(255) not null,
|
||||
comment varchar(255),
|
||||
position integer,
|
||||
changed_by varchar(255),
|
||||
created_at datetime,
|
||||
updated_at datetime,
|
||||
constraint bookmark_pk
|
||||
unique (user_id, item_id, item_type)
|
||||
);
|
||||
|
||||
create table playqueue_dg_tmp
|
||||
(
|
||||
id varchar(255) not null,
|
||||
user_id varchar(255) not null
|
||||
references user
|
||||
on update cascade on delete cascade,
|
||||
current varchar(255),
|
||||
position real,
|
||||
changed_by varchar(255),
|
||||
items varchar(255),
|
||||
created_at datetime,
|
||||
updated_at datetime
|
||||
);
|
||||
drop table playqueue;
|
||||
alter table playqueue_dg_tmp rename to playqueue;
|
||||
`)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func downCreateBookmarkTable(_ context.Context, tx *sql.Tx) error {
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/pressly/goose/v3"
|
||||
)
|
||||
|
||||
func init() {
|
||||
goose.AddMigrationContext(upDropEmailUniqueConstraint, downDropEmailUniqueConstraint)
|
||||
}
|
||||
|
||||
func upDropEmailUniqueConstraint(_ context.Context, tx *sql.Tx) error {
|
||||
_, err := tx.Exec(`
|
||||
create table user_dg_tmp
|
||||
(
|
||||
id varchar(255) not null
|
||||
primary key,
|
||||
user_name varchar(255) default '' not null
|
||||
unique,
|
||||
name varchar(255) default '' not null,
|
||||
email varchar(255) default '' not null,
|
||||
password varchar(255) default '' not null,
|
||||
is_admin bool default FALSE not null,
|
||||
last_login_at datetime,
|
||||
last_access_at datetime,
|
||||
created_at datetime not null,
|
||||
updated_at datetime not null
|
||||
);
|
||||
|
||||
insert into user_dg_tmp(id, user_name, name, email, password, is_admin, last_login_at, last_access_at, created_at, updated_at) select id, user_name, name, email, password, is_admin, last_login_at, last_access_at, created_at, updated_at from user;
|
||||
|
||||
drop table user;
|
||||
|
||||
alter table user_dg_tmp rename to user;
|
||||
`)
|
||||
return err
|
||||
}
|
||||
|
||||
func downDropEmailUniqueConstraint(_ context.Context, tx *sql.Tx) error {
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/pressly/goose/v3"
|
||||
)
|
||||
|
||||
func init() {
|
||||
goose.AddMigrationContext(Up20201003111749, Down20201003111749)
|
||||
}
|
||||
|
||||
func Up20201003111749(_ context.Context, tx *sql.Tx) error {
|
||||
_, err := tx.Exec(`
|
||||
create index if not exists annotation_starred_at
|
||||
on annotation (starred_at);
|
||||
`)
|
||||
return err
|
||||
}
|
||||
|
||||
func Down20201003111749(_ context.Context, tx *sql.Tx) error {
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/pressly/goose/v3"
|
||||
)
|
||||
|
||||
func init() {
|
||||
goose.AddMigrationContext(Up20201010162350, Down20201010162350)
|
||||
}
|
||||
|
||||
func Up20201010162350(_ context.Context, tx *sql.Tx) error {
|
||||
_, err := tx.Exec(`
|
||||
alter table album
|
||||
add size integer default 0 not null;
|
||||
create index if not exists album_size
|
||||
on album(size);
|
||||
|
||||
update album set size = ifnull((
|
||||
select sum(f.size)
|
||||
from media_file f
|
||||
where f.album_id = album.id
|
||||
), 0)
|
||||
where id not null;`)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func Down20201010162350(_ context.Context, tx *sql.Tx) error {
|
||||
// This code is executed when the migration is rolled back.
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/pressly/goose/v3"
|
||||
)
|
||||
|
||||
func init() {
|
||||
goose.AddMigrationContext(Up20201012210022, Down20201012210022)
|
||||
}
|
||||
|
||||
func Up20201012210022(_ context.Context, tx *sql.Tx) error {
|
||||
_, err := tx.Exec(`
|
||||
alter table artist
|
||||
add size integer default 0 not null;
|
||||
create index if not exists artist_size
|
||||
on artist(size);
|
||||
|
||||
update artist set size = ifnull((
|
||||
select sum(f.size)
|
||||
from album f
|
||||
where f.album_artist_id = artist.id
|
||||
), 0)
|
||||
where id not null;
|
||||
|
||||
alter table playlist
|
||||
add size integer default 0 not null;
|
||||
create index if not exists playlist_size
|
||||
on playlist(size);
|
||||
|
||||
update playlist set size = ifnull((
|
||||
select sum(size)
|
||||
from media_file f
|
||||
left join playlist_tracks pt on f.id = pt.media_file_id
|
||||
where pt.playlist_id = playlist.id
|
||||
), 0);`)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func Down20201012210022(_ context.Context, tx *sql.Tx) error {
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/pressly/goose/v3"
|
||||
)
|
||||
|
||||
func init() {
|
||||
goose.AddMigrationContext(Up20201021085410, Down20201021085410)
|
||||
}
|
||||
|
||||
func Up20201021085410(_ context.Context, tx *sql.Tx) error {
|
||||
_, err := tx.Exec(`
|
||||
alter table media_file
|
||||
add mbz_track_id varchar(255);
|
||||
alter table media_file
|
||||
add mbz_album_id varchar(255);
|
||||
alter table media_file
|
||||
add mbz_artist_id varchar(255);
|
||||
alter table media_file
|
||||
add mbz_album_artist_id varchar(255);
|
||||
alter table media_file
|
||||
add mbz_album_type varchar(255);
|
||||
alter table media_file
|
||||
add mbz_album_comment varchar(255);
|
||||
alter table media_file
|
||||
add catalog_num varchar(255);
|
||||
|
||||
alter table album
|
||||
add mbz_album_id varchar(255);
|
||||
alter table album
|
||||
add mbz_album_artist_id varchar(255);
|
||||
alter table album
|
||||
add mbz_album_type varchar(255);
|
||||
alter table album
|
||||
add mbz_album_comment varchar(255);
|
||||
alter table album
|
||||
add catalog_num varchar(255);
|
||||
|
||||
create index if not exists album_mbz_album_type
|
||||
on album (mbz_album_type);
|
||||
|
||||
alter table artist
|
||||
add mbz_artist_id varchar(255);
|
||||
|
||||
`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
notice(tx, "A full rescan needs to be performed to import more tags")
|
||||
return forceFullRescan(tx)
|
||||
}
|
||||
|
||||
func Down20201021085410(_ context.Context, tx *sql.Tx) error {
|
||||
// This code is executed when the migration is rolled back.
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/pressly/goose/v3"
|
||||
)
|
||||
|
||||
func init() {
|
||||
goose.AddMigrationContext(Up20201021093209, Down20201021093209)
|
||||
}
|
||||
|
||||
func Up20201021093209(_ context.Context, tx *sql.Tx) error {
|
||||
_, err := tx.Exec(`
|
||||
create index if not exists media_file_artist
|
||||
on media_file (artist);
|
||||
create index if not exists media_file_album_artist
|
||||
on media_file (album_artist);
|
||||
create index if not exists media_file_mbz_track_id
|
||||
on media_file (mbz_track_id);
|
||||
`)
|
||||
return err
|
||||
}
|
||||
|
||||
func Down20201021093209(_ context.Context, tx *sql.Tx) error {
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/pressly/goose/v3"
|
||||
)
|
||||
|
||||
func init() {
|
||||
goose.AddMigrationContext(Up20201021135455, Down20201021135455)
|
||||
}
|
||||
|
||||
func Up20201021135455(_ context.Context, tx *sql.Tx) error {
|
||||
_, err := tx.Exec(`
|
||||
create index if not exists media_file_artist_id
|
||||
on media_file (artist_id);
|
||||
`)
|
||||
return err
|
||||
}
|
||||
|
||||
func Down20201021135455(_ context.Context, tx *sql.Tx) error {
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/pressly/goose/v3"
|
||||
)
|
||||
|
||||
func init() {
|
||||
goose.AddMigrationContext(upAddArtistImageUrl, downAddArtistImageUrl)
|
||||
}
|
||||
|
||||
func upAddArtistImageUrl(_ context.Context, tx *sql.Tx) error {
|
||||
_, err := tx.Exec(`
|
||||
alter table artist
|
||||
add biography varchar(255) default '' not null;
|
||||
alter table artist
|
||||
add small_image_url varchar(255) default '' not null;
|
||||
alter table artist
|
||||
add medium_image_url varchar(255) default '' not null;
|
||||
alter table artist
|
||||
add large_image_url varchar(255) default '' not null;
|
||||
alter table artist
|
||||
add similar_artists varchar(255) default '' not null;
|
||||
alter table artist
|
||||
add external_url varchar(255) default '' not null;
|
||||
alter table artist
|
||||
add external_info_updated_at datetime;
|
||||
`)
|
||||
return err
|
||||
}
|
||||
|
||||
func downAddArtistImageUrl(_ context.Context, tx *sql.Tx) error {
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/pressly/goose/v3"
|
||||
)
|
||||
|
||||
func init() {
|
||||
goose.AddMigrationContext(Up20201110205344, Down20201110205344)
|
||||
}
|
||||
|
||||
func Up20201110205344(_ context.Context, tx *sql.Tx) error {
|
||||
_, err := tx.Exec(`
|
||||
alter table media_file
|
||||
add comment varchar;
|
||||
alter table media_file
|
||||
add lyrics varchar;
|
||||
|
||||
alter table album
|
||||
add comment varchar;
|
||||
`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
notice(tx, "A full rescan will be performed to import comments and lyrics")
|
||||
return forceFullRescan(tx)
|
||||
}
|
||||
|
||||
func Down20201110205344(_ context.Context, tx *sql.Tx) error {
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/pressly/goose/v3"
|
||||
)
|
||||
|
||||
func init() {
|
||||
goose.AddMigrationContext(Up20201128100726, Down20201128100726)
|
||||
}
|
||||
|
||||
func Up20201128100726(_ context.Context, tx *sql.Tx) error {
|
||||
_, err := tx.Exec(`
|
||||
alter table player
|
||||
add report_real_path bool default FALSE not null;
|
||||
`)
|
||||
return err
|
||||
}
|
||||
|
||||
func Down20201128100726(_ context.Context, tx *sql.Tx) error {
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/navidrome/navidrome/log"
|
||||
"github.com/navidrome/navidrome/utils"
|
||||
"github.com/pressly/goose/v3"
|
||||
)
|
||||
|
||||
func init() {
|
||||
goose.AddMigrationContext(Up20201213124814, Down20201213124814)
|
||||
}
|
||||
|
||||
func Up20201213124814(_ context.Context, tx *sql.Tx) error {
|
||||
_, err := tx.Exec(`
|
||||
alter table album
|
||||
add all_artist_ids varchar;
|
||||
|
||||
create index if not exists album_all_artist_ids
|
||||
on album (all_artist_ids);
|
||||
`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return updateAlbums20201213124814(tx)
|
||||
}
|
||||
|
||||
func updateAlbums20201213124814(tx *sql.Tx) error {
|
||||
rows, err := tx.Query(`
|
||||
select a.id, a.name, a.artist_id, a.album_artist_id, group_concat(mf.artist_id, ' ')
|
||||
from album a left join media_file mf on a.id = mf.album_id group by a.id
|
||||
`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
stmt, err := tx.Prepare("update album set all_artist_ids = ? where id = ?")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var id, name, artistId, albumArtistId string
|
||||
var songArtistIds sql.NullString
|
||||
for rows.Next() {
|
||||
err = rows.Scan(&id, &name, &artistId, &albumArtistId, &songArtistIds)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
all := utils.SanitizeStrings(artistId, albumArtistId, songArtistIds.String)
|
||||
_, err = stmt.Exec(all, id)
|
||||
if err != nil {
|
||||
log.Error("Error setting album's artist_ids", "album", name, "albumId", id, err)
|
||||
}
|
||||
}
|
||||
return rows.Err()
|
||||
}
|
||||
|
||||
func Down20201213124814(_ context.Context, tx *sql.Tx) error {
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/pressly/goose/v3"
|
||||
)
|
||||
|
||||
func init() {
|
||||
goose.AddMigrationContext(upAddTimestampIndexesGo, downAddTimestampIndexesGo)
|
||||
}
|
||||
|
||||
func upAddTimestampIndexesGo(_ context.Context, tx *sql.Tx) error {
|
||||
_, err := tx.Exec(`
|
||||
create index if not exists album_updated_at
|
||||
on album (updated_at);
|
||||
create index if not exists album_created_at
|
||||
on album (created_at);
|
||||
create index if not exists playlist_updated_at
|
||||
on playlist (updated_at);
|
||||
create index if not exists playlist_created_at
|
||||
on playlist (created_at);
|
||||
create index if not exists media_file_created_at
|
||||
on media_file (created_at);
|
||||
create index if not exists media_file_updated_at
|
||||
on media_file (updated_at);
|
||||
`)
|
||||
return err
|
||||
}
|
||||
|
||||
func downAddTimestampIndexesGo(_ context.Context, tx *sql.Tx) error {
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"strings"
|
||||
|
||||
"github.com/navidrome/navidrome/consts"
|
||||
"github.com/navidrome/navidrome/log"
|
||||
"github.com/pressly/goose/v3"
|
||||
)
|
||||
|
||||
func init() {
|
||||
goose.AddMigrationContext(upFixAlbumComments, downFixAlbumComments)
|
||||
}
|
||||
|
||||
func upFixAlbumComments(_ context.Context, tx *sql.Tx) error {
|
||||
//nolint:gosec
|
||||
rows, err := tx.Query(`
|
||||
SELECT album.id, group_concat(media_file.comment, '` + consts.Zwsp + `') FROM album, media_file WHERE media_file.album_id = album.id GROUP BY album.id;
|
||||
`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
stmt, err := tx.Prepare("UPDATE album SET comment = ? WHERE id = ?")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var id string
|
||||
var comments sql.NullString
|
||||
|
||||
for rows.Next() {
|
||||
err = rows.Scan(&id, &comments)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !comments.Valid {
|
||||
continue
|
||||
}
|
||||
comment := getComment(comments.String, consts.Zwsp)
|
||||
_, err = stmt.Exec(comment, id)
|
||||
|
||||
if err != nil {
|
||||
log.Error("Error setting album's comments", "albumId", id, err)
|
||||
}
|
||||
}
|
||||
return rows.Err()
|
||||
}
|
||||
|
||||
func downFixAlbumComments(_ context.Context, tx *sql.Tx) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func getComment(comments string, separator string) string {
|
||||
cs := strings.Split(comments, separator)
|
||||
if len(cs) == 0 {
|
||||
return ""
|
||||
}
|
||||
first := cs[0]
|
||||
for _, c := range cs[1:] {
|
||||
if first != c {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
return first
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/pressly/goose/v3"
|
||||
)
|
||||
|
||||
func init() {
|
||||
goose.AddMigrationContext(upAddBpmMetadata, downAddBpmMetadata)
|
||||
}
|
||||
|
||||
func upAddBpmMetadata(_ context.Context, tx *sql.Tx) error {
|
||||
_, err := tx.Exec(`
|
||||
alter table media_file
|
||||
add bpm integer;
|
||||
|
||||
create index if not exists media_file_bpm
|
||||
on media_file (bpm);
|
||||
`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
notice(tx, "A full rescan needs to be performed to import more tags")
|
||||
return forceFullRescan(tx)
|
||||
}
|
||||
|
||||
func downAddBpmMetadata(_ context.Context, tx *sql.Tx) error {
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/pressly/goose/v3"
|
||||
)
|
||||
|
||||
func init() {
|
||||
goose.AddMigrationContext(upCreateSharesTable, downCreateSharesTable)
|
||||
}
|
||||
|
||||
func upCreateSharesTable(_ context.Context, tx *sql.Tx) error {
|
||||
_, err := tx.Exec(`
|
||||
create table share
|
||||
(
|
||||
id varchar(255) not null primary key,
|
||||
name varchar(255) not null unique,
|
||||
description varchar(255),
|
||||
expires datetime,
|
||||
created datetime,
|
||||
last_visited datetime,
|
||||
resource_ids varchar not null,
|
||||
resource_type varchar(255) not null,
|
||||
visit_count integer default 0
|
||||
);
|
||||
`)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func downCreateSharesTable(_ context.Context, tx *sql.Tx) error {
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/pressly/goose/v3"
|
||||
)
|
||||
|
||||
func init() {
|
||||
goose.AddMigrationContext(upUpdateShareFieldNames, downUpdateShareFieldNames)
|
||||
}
|
||||
|
||||
func upUpdateShareFieldNames(_ context.Context, tx *sql.Tx) error {
|
||||
_, err := tx.Exec(`
|
||||
alter table share rename column expires to expires_at;
|
||||
alter table share rename column created to created_at;
|
||||
alter table share rename column last_visited to last_visited_at;
|
||||
`)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func downUpdateShareFieldNames(_ context.Context, tx *sql.Tx) error {
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"database/sql"
|
||||
|
||||
"github.com/navidrome/navidrome/consts"
|
||||
"github.com/navidrome/navidrome/log"
|
||||
"github.com/navidrome/navidrome/utils"
|
||||
"github.com/pressly/goose/v3"
|
||||
)
|
||||
|
||||
func init() {
|
||||
goose.AddMigrationContext(upEncodeAllPasswords, downEncodeAllPasswords)
|
||||
}
|
||||
|
||||
func upEncodeAllPasswords(ctx context.Context, tx *sql.Tx) error {
|
||||
rows, err := tx.Query(`SELECT id, user_name, password from user;`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
stmt, err := tx.Prepare("UPDATE user SET password = ? WHERE id = ?")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var id string
|
||||
var username, password string
|
||||
|
||||
data := sha256.Sum256([]byte(consts.DefaultEncryptionKey))
|
||||
encKey := data[0:]
|
||||
|
||||
for rows.Next() {
|
||||
err = rows.Scan(&id, &username, &password)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
password, err = utils.Encrypt(ctx, encKey, password)
|
||||
if err != nil {
|
||||
log.Error("Error encrypting user's password", "id", id, "username", username, err)
|
||||
}
|
||||
|
||||
_, err = stmt.Exec(password, id)
|
||||
if err != nil {
|
||||
log.Error("Error saving user's encrypted password", "id", id, "username", username, err)
|
||||
}
|
||||
}
|
||||
return rows.Err()
|
||||
}
|
||||
|
||||
func downEncodeAllPasswords(_ context.Context, tx *sql.Tx) error {
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/pressly/goose/v3"
|
||||
)
|
||||
|
||||
func init() {
|
||||
goose.AddMigrationContext(upDropPlayerNameUniqueConstraint, downDropPlayerNameUniqueConstraint)
|
||||
}
|
||||
|
||||
func upDropPlayerNameUniqueConstraint(_ context.Context, tx *sql.Tx) error {
|
||||
_, err := tx.Exec(`
|
||||
create table player_dg_tmp
|
||||
(
|
||||
id varchar(255) not null
|
||||
primary key,
|
||||
name varchar not null,
|
||||
user_agent varchar,
|
||||
user_name varchar not null
|
||||
references user (user_name)
|
||||
on update cascade on delete cascade,
|
||||
client varchar not null,
|
||||
ip_address varchar,
|
||||
last_seen timestamp,
|
||||
max_bit_rate int default 0,
|
||||
transcoding_id varchar,
|
||||
report_real_path bool default FALSE not null
|
||||
);
|
||||
|
||||
insert into player_dg_tmp(id, name, user_agent, user_name, client, ip_address, last_seen, max_bit_rate, transcoding_id, report_real_path) select id, name, type, user_name, client, ip_address, last_seen, max_bit_rate, transcoding_id, report_real_path from player;
|
||||
|
||||
drop table player;
|
||||
|
||||
alter table player_dg_tmp rename to player;
|
||||
create index if not exists player_match
|
||||
on player (client, user_agent, user_name);
|
||||
create index if not exists player_name
|
||||
on player (name);
|
||||
`)
|
||||
return err
|
||||
}
|
||||
|
||||
func downDropPlayerNameUniqueConstraint(_ context.Context, tx *sql.Tx) error {
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/pressly/goose/v3"
|
||||
)
|
||||
|
||||
func init() {
|
||||
goose.AddMigrationContext(upAddUserPrefsPlayerScrobblerEnabled, downAddUserPrefsPlayerScrobblerEnabled)
|
||||
}
|
||||
|
||||
func upAddUserPrefsPlayerScrobblerEnabled(_ context.Context, tx *sql.Tx) error {
|
||||
err := upAddUserPrefs(tx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return upPlayerScrobblerEnabled(tx)
|
||||
}
|
||||
|
||||
func upAddUserPrefs(tx *sql.Tx) error {
|
||||
_, err := tx.Exec(`
|
||||
create table user_props
|
||||
(
|
||||
user_id varchar not null,
|
||||
key varchar not null,
|
||||
value varchar,
|
||||
constraint user_props_pk
|
||||
primary key (user_id, key)
|
||||
);
|
||||
`)
|
||||
return err
|
||||
}
|
||||
|
||||
func upPlayerScrobblerEnabled(tx *sql.Tx) error {
|
||||
_, err := tx.Exec(`
|
||||
alter table player add scrobble_enabled bool default true;
|
||||
`)
|
||||
return err
|
||||
}
|
||||
|
||||
func downAddUserPrefsPlayerScrobblerEnabled(_ context.Context, tx *sql.Tx) error {
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/pressly/goose/v3"
|
||||
)
|
||||
|
||||
func init() {
|
||||
goose.AddMigrationContext(upAddReferentialIntegrityToUserProps, downAddReferentialIntegrityToUserProps)
|
||||
}
|
||||
|
||||
func upAddReferentialIntegrityToUserProps(_ context.Context, tx *sql.Tx) error {
|
||||
_, err := tx.Exec(`
|
||||
create table user_props_dg_tmp
|
||||
(
|
||||
user_id varchar not null
|
||||
constraint user_props_user_id_fk
|
||||
references user
|
||||
on update cascade on delete cascade,
|
||||
key varchar not null,
|
||||
value varchar,
|
||||
constraint user_props_pk
|
||||
primary key (user_id, key)
|
||||
);
|
||||
|
||||
insert into user_props_dg_tmp(user_id, key, value) select user_id, key, value from user_props;
|
||||
|
||||
drop table user_props;
|
||||
|
||||
alter table user_props_dg_tmp rename to user_props;
|
||||
`)
|
||||
return err
|
||||
}
|
||||
|
||||
func downAddReferentialIntegrityToUserProps(_ context.Context, tx *sql.Tx) error {
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/pressly/goose/v3"
|
||||
)
|
||||
|
||||
func init() {
|
||||
goose.AddMigrationContext(upAddScrobbleBuffer, downAddScrobbleBuffer)
|
||||
}
|
||||
|
||||
func upAddScrobbleBuffer(_ context.Context, tx *sql.Tx) error {
|
||||
_, err := tx.Exec(`
|
||||
create table if not exists scrobble_buffer
|
||||
(
|
||||
user_id varchar not null
|
||||
constraint scrobble_buffer_user_id_fk
|
||||
references user
|
||||
on update cascade on delete cascade,
|
||||
service varchar not null,
|
||||
media_file_id varchar not null
|
||||
constraint scrobble_buffer_media_file_id_fk
|
||||
references media_file
|
||||
on update cascade on delete cascade,
|
||||
play_time datetime not null,
|
||||
enqueue_time datetime not null default current_timestamp,
|
||||
constraint scrobble_buffer_pk
|
||||
unique (user_id, service, media_file_id, play_time, user_id)
|
||||
);
|
||||
`)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func downAddScrobbleBuffer(_ context.Context, tx *sql.Tx) error {
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/pressly/goose/v3"
|
||||
)
|
||||
|
||||
func init() {
|
||||
goose.AddMigrationContext(upAddGenreTables, downAddGenreTables)
|
||||
}
|
||||
|
||||
func upAddGenreTables(_ context.Context, tx *sql.Tx) error {
|
||||
notice(tx, "A full rescan will be performed to import multiple genres!")
|
||||
_, err := tx.Exec(`
|
||||
create table if not exists genre
|
||||
(
|
||||
id varchar not null primary key,
|
||||
name varchar not null,
|
||||
constraint genre_name_ux
|
||||
unique (name)
|
||||
);
|
||||
|
||||
create table if not exists album_genres
|
||||
(
|
||||
album_id varchar default null not null
|
||||
references album
|
||||
on delete cascade,
|
||||
genre_id varchar default null not null
|
||||
references genre
|
||||
on delete cascade,
|
||||
constraint album_genre_ux
|
||||
unique (album_id, genre_id)
|
||||
);
|
||||
|
||||
create table if not exists media_file_genres
|
||||
(
|
||||
media_file_id varchar default null not null
|
||||
references media_file
|
||||
on delete cascade,
|
||||
genre_id varchar default null not null
|
||||
references genre
|
||||
on delete cascade,
|
||||
constraint media_file_genre_ux
|
||||
unique (media_file_id, genre_id)
|
||||
);
|
||||
|
||||
create table if not exists artist_genres
|
||||
(
|
||||
artist_id varchar default null not null
|
||||
references artist
|
||||
on delete cascade,
|
||||
genre_id varchar default null not null
|
||||
references genre
|
||||
on delete cascade,
|
||||
constraint artist_genre_ux
|
||||
unique (artist_id, genre_id)
|
||||
);
|
||||
`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return forceFullRescan(tx)
|
||||
}
|
||||
|
||||
func downAddGenreTables(_ context.Context, tx *sql.Tx) error {
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/pressly/goose/v3"
|
||||
)
|
||||
|
||||
func init() {
|
||||
goose.AddMigrationContext(upAddMediafileChannels, downAddMediafileChannels)
|
||||
}
|
||||
|
||||
func upAddMediafileChannels(_ context.Context, tx *sql.Tx) error {
|
||||
_, err := tx.Exec(`
|
||||
alter table media_file
|
||||
add channels integer;
|
||||
|
||||
create index if not exists media_file_channels
|
||||
on media_file (channels);
|
||||
`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
notice(tx, "A full rescan needs to be performed to import more tags")
|
||||
return forceFullRescan(tx)
|
||||
}
|
||||
|
||||
func downAddMediafileChannels(_ context.Context, tx *sql.Tx) error {
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/pressly/goose/v3"
|
||||
)
|
||||
|
||||
func init() {
|
||||
goose.AddMigrationContext(upAddSmartPlaylist, downAddSmartPlaylist)
|
||||
}
|
||||
|
||||
func upAddSmartPlaylist(_ context.Context, tx *sql.Tx) error {
|
||||
_, err := tx.Exec(`
|
||||
alter table playlist
|
||||
add column rules varchar null;
|
||||
alter table playlist
|
||||
add column evaluated_at datetime null;
|
||||
create index if not exists playlist_evaluated_at
|
||||
on playlist(evaluated_at);
|
||||
|
||||
create table playlist_fields (
|
||||
field varchar(255) not null,
|
||||
playlist_id varchar(255) not null
|
||||
constraint playlist_fields_playlist_id_fk
|
||||
references playlist
|
||||
on update cascade on delete cascade
|
||||
);
|
||||
create unique index playlist_fields_idx
|
||||
on playlist_fields (field, playlist_id);
|
||||
`)
|
||||
return err
|
||||
}
|
||||
|
||||
func downAddSmartPlaylist(_ context.Context, tx *sql.Tx) error {
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"strings"
|
||||
|
||||
"github.com/deluan/sanitize"
|
||||
"github.com/navidrome/navidrome/log"
|
||||
"github.com/pressly/goose/v3"
|
||||
)
|
||||
|
||||
func init() {
|
||||
goose.AddMigrationContext(upAddOrderTitleToMediaFile, downAddOrderTitleToMediaFile)
|
||||
}
|
||||
|
||||
func upAddOrderTitleToMediaFile(_ context.Context, tx *sql.Tx) error {
|
||||
_, err := tx.Exec(`
|
||||
alter table main.media_file
|
||||
add order_title varchar null collate NOCASE;
|
||||
create index if not exists media_file_order_title
|
||||
on media_file (order_title);
|
||||
`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return upAddOrderTitleToMediaFile_populateOrderTitle(tx)
|
||||
}
|
||||
|
||||
//goland:noinspection GoSnakeCaseUsage
|
||||
func upAddOrderTitleToMediaFile_populateOrderTitle(tx *sql.Tx) error {
|
||||
rows, err := tx.Query(`select id, title from media_file`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
stmt, err := tx.Prepare("update media_file set order_title = ? where id = ?")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var id, title string
|
||||
for rows.Next() {
|
||||
err = rows.Scan(&id, &title)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
orderTitle := strings.TrimSpace(sanitize.Accents(title))
|
||||
_, err = stmt.Exec(orderTitle, id)
|
||||
if err != nil {
|
||||
log.Error("Error setting media_file's order_title", "title", title, "id", id, err)
|
||||
}
|
||||
}
|
||||
return rows.Err()
|
||||
}
|
||||
|
||||
func downAddOrderTitleToMediaFile(_ context.Context, tx *sql.Tx) error {
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/navidrome/navidrome/log"
|
||||
"github.com/navidrome/navidrome/utils"
|
||||
"github.com/pressly/goose/v3"
|
||||
)
|
||||
|
||||
func init() {
|
||||
goose.AddMigrationContext(upUnescapeLyricsAndComments, downUnescapeLyricsAndComments)
|
||||
}
|
||||
|
||||
func upUnescapeLyricsAndComments(_ context.Context, tx *sql.Tx) error {
|
||||
rows, err := tx.Query(`select id, comment, lyrics, title from media_file`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
stmt, err := tx.Prepare("update media_file set comment = ?, lyrics = ? where id = ?")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var id, title string
|
||||
var comment, lyrics sql.NullString
|
||||
for rows.Next() {
|
||||
err = rows.Scan(&id, &comment, &lyrics, &title)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
newComment := utils.SanitizeText(comment.String)
|
||||
newLyrics := utils.SanitizeText(lyrics.String)
|
||||
_, err = stmt.Exec(newComment, newLyrics, id)
|
||||
if err != nil {
|
||||
log.Error("Error unescaping media_file's lyrics and comments", "title", title, "id", id, err)
|
||||
}
|
||||
}
|
||||
return rows.Err()
|
||||
}
|
||||
|
||||
func downUnescapeLyricsAndComments(_ context.Context, tx *sql.Tx) error {
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/pressly/goose/v3"
|
||||
)
|
||||
|
||||
func init() {
|
||||
goose.AddMigrationContext(upAddUseridToPlaylist, downAddUseridToPlaylist)
|
||||
}
|
||||
|
||||
func upAddUseridToPlaylist(_ context.Context, tx *sql.Tx) error {
|
||||
_, err := tx.Exec(`
|
||||
create table playlist_dg_tmp
|
||||
(
|
||||
id varchar(255) not null
|
||||
primary key,
|
||||
name varchar(255) default '' not null,
|
||||
comment varchar(255) default '' not null,
|
||||
duration real default 0 not null,
|
||||
song_count integer default 0 not null,
|
||||
public bool default FALSE not null,
|
||||
created_at datetime,
|
||||
updated_at datetime,
|
||||
path string default '' not null,
|
||||
sync bool default false not null,
|
||||
size integer default 0 not null,
|
||||
rules varchar,
|
||||
evaluated_at datetime,
|
||||
owner_id varchar(255) not null
|
||||
constraint playlist_user_user_id_fk
|
||||
references user
|
||||
on update cascade on delete cascade
|
||||
);
|
||||
|
||||
insert into playlist_dg_tmp(id, name, comment, duration, song_count, public, created_at, updated_at, path, sync, size, rules, evaluated_at, owner_id)
|
||||
select id, name, comment, duration, song_count, public, created_at, updated_at, path, sync, size, rules, evaluated_at,
|
||||
(select id from user where user_name = owner) as user_id from playlist;
|
||||
|
||||
drop table playlist;
|
||||
alter table playlist_dg_tmp rename to playlist;
|
||||
create index playlist_created_at
|
||||
on playlist (created_at);
|
||||
create index playlist_evaluated_at
|
||||
on playlist (evaluated_at);
|
||||
create index playlist_name
|
||||
on playlist (name);
|
||||
create index playlist_size
|
||||
on playlist (size);
|
||||
create index playlist_updated_at
|
||||
on playlist (updated_at);
|
||||
|
||||
`)
|
||||
return err
|
||||
}
|
||||
|
||||
func downAddUseridToPlaylist(_ context.Context, tx *sql.Tx) error {
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/pressly/goose/v3"
|
||||
)
|
||||
|
||||
func init() {
|
||||
goose.AddMigrationContext(upAddAlphabeticalByArtistIndex, downAddAlphabeticalByArtistIndex)
|
||||
}
|
||||
|
||||
func upAddAlphabeticalByArtistIndex(_ context.Context, tx *sql.Tx) error {
|
||||
_, err := tx.Exec(`
|
||||
create index album_alphabetical_by_artist
|
||||
ON album(compilation, order_album_artist_name, order_album_name)
|
||||
`)
|
||||
return err
|
||||
}
|
||||
|
||||
func downAddAlphabeticalByArtistIndex(_ context.Context, tx *sql.Tx) error {
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/pressly/goose/v3"
|
||||
)
|
||||
|
||||
func init() {
|
||||
goose.AddMigrationContext(upRemoveInvalidArtistIds, downRemoveInvalidArtistIds)
|
||||
}
|
||||
|
||||
func upRemoveInvalidArtistIds(_ context.Context, tx *sql.Tx) error {
|
||||
_, err := tx.Exec(`
|
||||
update media_file set artist_id = '' where not exists(select 1 from artist where id = artist_id)
|
||||
`)
|
||||
return err
|
||||
}
|
||||
|
||||
func downRemoveInvalidArtistIds(_ context.Context, tx *sql.Tx) error {
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/pressly/goose/v3"
|
||||
)
|
||||
|
||||
func init() {
|
||||
goose.AddMigrationContext(upAddMusicbrainzReleaseTrackId, downAddMusicbrainzReleaseTrackId)
|
||||
}
|
||||
|
||||
func upAddMusicbrainzReleaseTrackId(_ context.Context, tx *sql.Tx) error {
|
||||
_, err := tx.Exec(`
|
||||
alter table media_file
|
||||
add mbz_release_track_id varchar(255);
|
||||
`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
notice(tx, "A full rescan needs to be performed to import more tags")
|
||||
return forceFullRescan(tx)
|
||||
}
|
||||
|
||||
func downAddMusicbrainzReleaseTrackId(_ context.Context, tx *sql.Tx) error {
|
||||
// This code is executed when the migration is rolled back.
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/pressly/goose/v3"
|
||||
)
|
||||
|
||||
func init() {
|
||||
goose.AddMigrationContext(upAddAlbumImagePaths, downAddAlbumImagePaths)
|
||||
}
|
||||
|
||||
func upAddAlbumImagePaths(_ context.Context, tx *sql.Tx) error {
|
||||
_, err := tx.Exec(`
|
||||
alter table main.album add image_files varchar;
|
||||
`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
notice(tx, "A full rescan needs to be performed to import all album images")
|
||||
return forceFullRescan(tx)
|
||||
}
|
||||
|
||||
func downAddAlbumImagePaths(_ context.Context, tx *sql.Tx) error {
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/pressly/goose/v3"
|
||||
)
|
||||
|
||||
func init() {
|
||||
goose.AddMigrationContext(upRemoveCoverArtId, downRemoveCoverArtId)
|
||||
}
|
||||
|
||||
func upRemoveCoverArtId(_ context.Context, tx *sql.Tx) error {
|
||||
_, err := tx.Exec(`
|
||||
alter table album drop column cover_art_id;
|
||||
alter table album rename column cover_art_path to embed_art_path
|
||||
`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
notice(tx, "A full rescan needs to be performed to import all album images")
|
||||
return forceFullRescan(tx)
|
||||
}
|
||||
|
||||
func downRemoveCoverArtId(_ context.Context, tx *sql.Tx) error {
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/navidrome/navidrome/consts"
|
||||
"github.com/navidrome/navidrome/log"
|
||||
"github.com/pressly/goose/v3"
|
||||
)
|
||||
|
||||
func init() {
|
||||
goose.AddMigrationContext(upAddAlbumPaths, downAddAlbumPaths)
|
||||
}
|
||||
|
||||
func upAddAlbumPaths(_ context.Context, tx *sql.Tx) error {
|
||||
_, err := tx.Exec(`alter table album add paths varchar;`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
//nolint:gosec
|
||||
rows, err := tx.Query(`
|
||||
select album_id, group_concat(path, '` + consts.Zwsp + `') from media_file group by album_id
|
||||
`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
stmt, err := tx.Prepare("update album set paths = ? where id = ?")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var id, filePaths string
|
||||
for rows.Next() {
|
||||
err = rows.Scan(&id, &filePaths)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
paths := upAddAlbumPathsDirs(filePaths)
|
||||
_, err = stmt.Exec(paths, id)
|
||||
if err != nil {
|
||||
log.Error("Error updating album's paths", "paths", paths, "id", id, err)
|
||||
}
|
||||
}
|
||||
return rows.Err()
|
||||
}
|
||||
|
||||
func upAddAlbumPathsDirs(filePaths string) string {
|
||||
allPaths := strings.Split(filePaths, consts.Zwsp)
|
||||
var dirs []string
|
||||
for _, p := range allPaths {
|
||||
dir, _ := filepath.Split(p)
|
||||
dirs = append(dirs, filepath.Clean(dir))
|
||||
}
|
||||
slices.Sort(dirs)
|
||||
dirs = slices.Compact(dirs)
|
||||
return strings.Join(dirs, string(filepath.ListSeparator))
|
||||
}
|
||||
|
||||
func downAddAlbumPaths(_ context.Context, tx *sql.Tx) error {
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/pressly/goose/v3"
|
||||
)
|
||||
|
||||
func init() {
|
||||
goose.AddMigrationContext(upTouchPlaylists, downTouchPlaylists)
|
||||
}
|
||||
|
||||
func upTouchPlaylists(_ context.Context, tx *sql.Tx) error {
|
||||
_, err := tx.Exec(`update playlist set updated_at = datetime('now');`)
|
||||
return err
|
||||
}
|
||||
|
||||
func downTouchPlaylists(_ context.Context, tx *sql.Tx) error {
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/pressly/goose/v3"
|
||||
)
|
||||
|
||||
func init() {
|
||||
goose.AddMigrationContext(upCreateInternetRadio, downCreateInternetRadio)
|
||||
}
|
||||
|
||||
func upCreateInternetRadio(_ context.Context, tx *sql.Tx) error {
|
||||
_, err := tx.Exec(`
|
||||
create table if not exists radio
|
||||
(
|
||||
id varchar(255) not null primary key,
|
||||
name varchar not null unique,
|
||||
stream_url varchar not null,
|
||||
home_page_url varchar default '' not null,
|
||||
created_at datetime,
|
||||
updated_at datetime
|
||||
);
|
||||
`)
|
||||
return err
|
||||
}
|
||||
|
||||
func downCreateInternetRadio(_ context.Context, tx *sql.Tx) error {
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/pressly/goose/v3"
|
||||
)
|
||||
|
||||
func init() {
|
||||
goose.AddMigrationContext(upAddReplaygainMetadata, downAddReplaygainMetadata)
|
||||
}
|
||||
|
||||
func upAddReplaygainMetadata(_ context.Context, tx *sql.Tx) error {
|
||||
_, err := tx.Exec(`
|
||||
alter table media_file add
|
||||
rg_album_gain real;
|
||||
alter table media_file add
|
||||
rg_album_peak real;
|
||||
alter table media_file add
|
||||
rg_track_gain real;
|
||||
alter table media_file add
|
||||
rg_track_peak real;
|
||||
`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
notice(tx, "A full rescan needs to be performed to import more tags")
|
||||
return forceFullRescan(tx)
|
||||
}
|
||||
|
||||
func downAddReplaygainMetadata(_ context.Context, tx *sql.Tx) error {
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/pressly/goose/v3"
|
||||
)
|
||||
|
||||
func init() {
|
||||
goose.AddMigrationContext(upAddAlbumInfo, downAddAlbumInfo)
|
||||
}
|
||||
|
||||
func upAddAlbumInfo(_ context.Context, tx *sql.Tx) error {
|
||||
_, err := tx.Exec(`
|
||||
alter table album
|
||||
add description varchar(255) default '' not null;
|
||||
alter table album
|
||||
add small_image_url varchar(255) default '' not null;
|
||||
alter table album
|
||||
add medium_image_url varchar(255) default '' not null;
|
||||
alter table album
|
||||
add large_image_url varchar(255) default '' not null;
|
||||
alter table album
|
||||
add external_url varchar(255) default '' not null;
|
||||
alter table album
|
||||
add external_info_updated_at datetime;
|
||||
`)
|
||||
return err
|
||||
}
|
||||
|
||||
func downAddAlbumInfo(_ context.Context, tx *sql.Tx) error {
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/pressly/goose/v3"
|
||||
)
|
||||
|
||||
func init() {
|
||||
goose.AddMigrationContext(upAddMissingShareInfo, downAddMissingShareInfo)
|
||||
}
|
||||
|
||||
func upAddMissingShareInfo(_ context.Context, tx *sql.Tx) error {
|
||||
_, err := tx.Exec(`
|
||||
drop table if exists share;
|
||||
create table share
|
||||
(
|
||||
id varchar(255) not null
|
||||
primary key,
|
||||
description varchar(255),
|
||||
expires_at datetime,
|
||||
last_visited_at datetime,
|
||||
resource_ids varchar not null,
|
||||
resource_type varchar(255) not null,
|
||||
contents varchar,
|
||||
format varchar,
|
||||
max_bit_rate integer,
|
||||
visit_count integer default 0,
|
||||
created_at datetime,
|
||||
updated_at datetime,
|
||||
user_id varchar(255) not null
|
||||
constraint share_user_id_fk
|
||||
references user
|
||||
);
|
||||
`)
|
||||
return err
|
||||
}
|
||||
|
||||
func downAddMissingShareInfo(_ context.Context, tx *sql.Tx) error {
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/navidrome/navidrome/consts"
|
||||
"github.com/navidrome/navidrome/log"
|
||||
"github.com/pressly/goose/v3"
|
||||
)
|
||||
|
||||
func init() {
|
||||
goose.AddMigrationContext(upChangePathListSeparator, downChangePathListSeparator)
|
||||
}
|
||||
|
||||
func upChangePathListSeparator(_ context.Context, tx *sql.Tx) error {
|
||||
//nolint:gosec
|
||||
rows, err := tx.Query(`
|
||||
select album_id, group_concat(path, '` + consts.Zwsp + `') from media_file group by album_id
|
||||
`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
stmt, err := tx.Prepare("update album set paths = ? where id = ?")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var id, filePaths string
|
||||
for rows.Next() {
|
||||
err = rows.Scan(&id, &filePaths)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
paths := upChangePathListSeparatorDirs(filePaths)
|
||||
_, err = stmt.Exec(paths, id)
|
||||
if err != nil {
|
||||
log.Error("Error updating album's paths", "paths", paths, "id", id, err)
|
||||
}
|
||||
}
|
||||
return rows.Err()
|
||||
}
|
||||
|
||||
func upChangePathListSeparatorDirs(filePaths string) string {
|
||||
allPaths := strings.Split(filePaths, consts.Zwsp)
|
||||
var dirs []string
|
||||
for _, p := range allPaths {
|
||||
dir, _ := filepath.Split(p)
|
||||
dirs = append(dirs, filepath.Clean(dir))
|
||||
}
|
||||
slices.Sort(dirs)
|
||||
dirs = slices.Compact(dirs)
|
||||
return strings.Join(dirs, consts.Zwsp)
|
||||
}
|
||||
|
||||
func downChangePathListSeparator(_ context.Context, tx *sql.Tx) error {
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/navidrome/navidrome/consts"
|
||||
"github.com/navidrome/navidrome/log"
|
||||
"github.com/pressly/goose/v3"
|
||||
)
|
||||
|
||||
func init() {
|
||||
goose.AddMigrationContext(upChangeImageFilesListSeparator, downChangeImageFilesListSeparator)
|
||||
}
|
||||
|
||||
func upChangeImageFilesListSeparator(_ context.Context, tx *sql.Tx) error {
|
||||
rows, err := tx.Query(`select id, image_files from album`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
stmt, err := tx.Prepare("update album set image_files = ? where id = ?")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var id string
|
||||
var imageFiles sql.NullString
|
||||
for rows.Next() {
|
||||
err = rows.Scan(&id, &imageFiles)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
files := upChangeImageFilesListSeparatorDirs(imageFiles.String)
|
||||
if files == imageFiles.String {
|
||||
continue
|
||||
}
|
||||
_, err = stmt.Exec(files, id)
|
||||
if err != nil {
|
||||
log.Error("Error updating album's image file list", "files", files, "id", id, err)
|
||||
}
|
||||
}
|
||||
return rows.Err()
|
||||
}
|
||||
|
||||
func upChangeImageFilesListSeparatorDirs(filePaths string) string {
|
||||
allPaths := filepath.SplitList(filePaths)
|
||||
slices.Sort(allPaths)
|
||||
allPaths = slices.Compact(allPaths)
|
||||
return strings.Join(allPaths, consts.Zwsp)
|
||||
}
|
||||
|
||||
func downChangeImageFilesListSeparator(_ context.Context, tx *sql.Tx) error {
|
||||
// This code is executed when the migration is rolled back.
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/pressly/goose/v3"
|
||||
)
|
||||
|
||||
func init() {
|
||||
goose.AddMigrationContext(upAddDownloadToShare, downAddDownloadToShare)
|
||||
}
|
||||
|
||||
func upAddDownloadToShare(_ context.Context, tx *sql.Tx) error {
|
||||
_, err := tx.Exec(`
|
||||
alter table share
|
||||
add downloadable bool not null default false;
|
||||
`)
|
||||
return err
|
||||
}
|
||||
|
||||
func downAddDownloadToShare(_ context.Context, tx *sql.Tx) error {
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
-- This file has intentionally no SQL logic. It is here to avoid an error in the linter:
|
||||
-- db/db.go:23:4: invalid go:embed: build system did not supply embed configuration (typecheck)
|
||||
--
|
||||
|
||||
-- +goose Up
|
||||
-- +goose StatementBegin
|
||||
SELECT 'up SQL query';
|
||||
-- +goose StatementEnd
|
||||
|
||||
-- +goose Down
|
||||
-- +goose StatementBegin
|
||||
SELECT 'down SQL query';
|
||||
-- +goose StatementEnd
|
||||
@@ -0,0 +1,50 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/pressly/goose/v3"
|
||||
)
|
||||
|
||||
func init() {
|
||||
goose.AddMigrationContext(upAddRelRecYear, downAddRelRecYear)
|
||||
}
|
||||
|
||||
func upAddRelRecYear(_ context.Context, tx *sql.Tx) error {
|
||||
_, err := tx.Exec(`
|
||||
alter table media_file
|
||||
add date varchar(255) default '' not null;
|
||||
alter table media_file
|
||||
add original_year int default 0 not null;
|
||||
alter table media_file
|
||||
add original_date varchar(255) default '' not null;
|
||||
alter table media_file
|
||||
add release_year int default 0 not null;
|
||||
alter table media_file
|
||||
add release_date varchar(255) default '' not null;
|
||||
|
||||
alter table album
|
||||
add date varchar(255) default '' not null;
|
||||
alter table album
|
||||
add min_original_year int default 0 not null;
|
||||
alter table album
|
||||
add max_original_year int default 0 not null;
|
||||
alter table album
|
||||
add original_date varchar(255) default '' not null;
|
||||
alter table album
|
||||
add release_date varchar(255) default '' not null;
|
||||
alter table album
|
||||
add releases integer default 0 not null;
|
||||
`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
notice(tx, "A full rescan needs to be performed to import more tags")
|
||||
return forceFullRescan(tx)
|
||||
}
|
||||
|
||||
func downAddRelRecYear(_ context.Context, tx *sql.Tx) error {
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/pressly/goose/v3"
|
||||
)
|
||||
|
||||
func init() {
|
||||
goose.AddMigrationContext(upRenameMusicbrainzRecordingId, downRenameMusicbrainzRecordingId)
|
||||
}
|
||||
|
||||
func upRenameMusicbrainzRecordingId(_ context.Context, tx *sql.Tx) error {
|
||||
_, err := tx.Exec(`
|
||||
alter table media_file
|
||||
rename column mbz_track_id to mbz_recording_id;
|
||||
`)
|
||||
return err
|
||||
}
|
||||
|
||||
func downRenameMusicbrainzRecordingId(_ context.Context, tx *sql.Tx) error {
|
||||
_, err := tx.Exec(`
|
||||
alter table media_file
|
||||
rename column mbz_recording_id to mbz_track_id;
|
||||
`)
|
||||
return err
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/pressly/goose/v3"
|
||||
)
|
||||
|
||||
func init() {
|
||||
goose.AddMigrationContext(upAddDiscToAlbum, downAddDiscToAlbum)
|
||||
}
|
||||
|
||||
func upAddDiscToAlbum(ctx context.Context, tx *sql.Tx) error {
|
||||
_, err := tx.ExecContext(ctx, `alter table album add discs JSONB default '{}';`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = tx.ExecContext(ctx, `
|
||||
update album set discs = t.discs
|
||||
from (select album_id, json_group_object(disc_number, disc_subtitle) as discs
|
||||
from (select distinct album_id, disc_number, disc_subtitle
|
||||
from media_file
|
||||
where disc_number > 0
|
||||
order by album_id, disc_number)
|
||||
group by album_id
|
||||
having discs <> '{"1":""}') as t
|
||||
where album.id = t.album_id;
|
||||
`)
|
||||
return err
|
||||
}
|
||||
|
||||
func downAddDiscToAlbum(ctx context.Context, tx *sql.Tx) error {
|
||||
_, err := tx.ExecContext(ctx, `alter table album drop discs;`)
|
||||
return err
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/navidrome/navidrome/model"
|
||||
"github.com/pressly/goose/v3"
|
||||
)
|
||||
|
||||
func init() {
|
||||
goose.AddMigrationContext(upAlterLyricColumn, downAlterLyricColumn)
|
||||
}
|
||||
|
||||
func upAlterLyricColumn(ctx context.Context, tx *sql.Tx) error {
|
||||
_, err := tx.ExecContext(ctx, `alter table media_file rename COLUMN lyrics TO lyrics_old`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = tx.ExecContext(ctx, `alter table media_file add lyrics JSONB default '[]';`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
stmt, err := tx.Prepare(`update media_file SET lyrics = ? where id = ?`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
rows, err := tx.Query(`select id, lyrics_old FROM media_file WHERE lyrics_old <> '';`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var id string
|
||||
var lyrics sql.NullString
|
||||
for rows.Next() {
|
||||
err = rows.Scan(&id, &lyrics)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !lyrics.Valid {
|
||||
continue
|
||||
}
|
||||
|
||||
lyrics, err := model.ToLyrics("xxx", lyrics.String)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
text, err := json.Marshal(model.LyricList{*lyrics})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = stmt.Exec(string(text), id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
err = rows.Err()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = tx.ExecContext(ctx, `ALTER TABLE media_file DROP COLUMN lyrics_old;`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
notice(tx, "A full rescan should be performed to pick up additional lyrics (existing lyrics have been preserved)")
|
||||
return nil
|
||||
}
|
||||
|
||||
func downAlterLyricColumn(ctx context.Context, tx *sql.Tx) error {
|
||||
// This code is executed when the migration is rolled back.
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,563 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/pressly/goose/v3"
|
||||
)
|
||||
|
||||
func init() {
|
||||
goose.AddMigrationContext(Up20240122223340, Down20240122223340)
|
||||
}
|
||||
|
||||
func Up20240122223340(ctx context.Context, tx *sql.Tx) error {
|
||||
_, err := tx.ExecContext(ctx, `
|
||||
drop index if exists album_alphabetical_by_artist;
|
||||
drop index if exists album_order_album_name;
|
||||
drop index if exists album_order_album_artist_name;
|
||||
drop index if exists album_mbz_album_type;
|
||||
|
||||
drop index if exists artist_order_artist_name;
|
||||
|
||||
drop index if exists media_file_order_album_name;
|
||||
drop index if exists media_file_order_artist_name;
|
||||
drop index if exists media_file_order_title;
|
||||
drop index if exists media_file_bpm;
|
||||
drop index if exists media_file_channels;
|
||||
drop index if exists media_file_mbz_track_id;
|
||||
|
||||
alter table album
|
||||
add image_files_new varchar not null default '';
|
||||
update album
|
||||
set image_files_new = image_files
|
||||
where image_files is not null;
|
||||
alter table album
|
||||
drop image_files;
|
||||
alter table album
|
||||
rename image_files_new to image_files;
|
||||
|
||||
alter table album
|
||||
add order_album_name_new varchar not null default '';
|
||||
update album
|
||||
set order_album_name_new = order_album_name
|
||||
where order_album_name is not null;
|
||||
alter table album
|
||||
drop order_album_name;
|
||||
alter table album
|
||||
rename order_album_name_new to order_album_name;
|
||||
|
||||
alter table album
|
||||
add order_album_artist_name_new varchar not null default '';
|
||||
update album
|
||||
set order_album_artist_name_new = order_album_artist_name
|
||||
where order_album_artist_name is not null;
|
||||
alter table album
|
||||
drop order_album_artist_name;
|
||||
alter table album
|
||||
rename order_album_artist_name_new to order_album_artist_name;
|
||||
|
||||
alter table album
|
||||
add sort_album_name_new varchar not null default '';
|
||||
update album
|
||||
set sort_album_name_new = sort_album_name
|
||||
where sort_album_name is not null;
|
||||
alter table album
|
||||
drop sort_album_name;
|
||||
alter table album
|
||||
rename sort_album_name_new to sort_album_name;
|
||||
|
||||
alter table album
|
||||
add sort_artist_name_new varchar not null default '';
|
||||
update album
|
||||
set sort_artist_name_new = sort_artist_name
|
||||
where sort_artist_name is not null;
|
||||
alter table album
|
||||
drop sort_artist_name;
|
||||
alter table album
|
||||
rename sort_artist_name_new to sort_artist_name;
|
||||
|
||||
alter table album
|
||||
add sort_album_artist_name_new varchar not null default '';
|
||||
update album
|
||||
set sort_album_artist_name_new = sort_album_artist_name
|
||||
where sort_album_artist_name is not null;
|
||||
alter table album
|
||||
drop sort_album_artist_name;
|
||||
alter table album
|
||||
rename sort_album_artist_name_new to sort_album_artist_name;
|
||||
|
||||
alter table album
|
||||
add catalog_num_new varchar not null default '';
|
||||
update album
|
||||
set catalog_num_new = catalog_num
|
||||
where catalog_num is not null;
|
||||
alter table album
|
||||
drop catalog_num;
|
||||
alter table album
|
||||
rename catalog_num_new to catalog_num;
|
||||
|
||||
alter table album
|
||||
add comment_new varchar not null default '';
|
||||
update album
|
||||
set comment_new = comment
|
||||
where comment is not null;
|
||||
alter table album
|
||||
drop comment;
|
||||
alter table album
|
||||
rename comment_new to comment;
|
||||
|
||||
alter table album
|
||||
add paths_new varchar not null default '';
|
||||
update album
|
||||
set paths_new = paths
|
||||
where paths is not null;
|
||||
alter table album
|
||||
drop paths;
|
||||
alter table album
|
||||
rename paths_new to paths;
|
||||
|
||||
alter table album
|
||||
add mbz_album_id_new varchar not null default '';
|
||||
update album
|
||||
set mbz_album_id_new = mbz_album_id
|
||||
where mbz_album_id is not null;
|
||||
alter table album
|
||||
drop mbz_album_id;
|
||||
alter table album
|
||||
rename mbz_album_id_new to mbz_album_id;
|
||||
|
||||
alter table album
|
||||
add mbz_album_artist_id_new varchar not null default '';
|
||||
update album
|
||||
set mbz_album_artist_id_new = mbz_album_artist_id
|
||||
where mbz_album_artist_id is not null;
|
||||
alter table album
|
||||
drop mbz_album_artist_id;
|
||||
alter table album
|
||||
rename mbz_album_artist_id_new to mbz_album_artist_id;
|
||||
|
||||
alter table album
|
||||
add mbz_album_type_new varchar not null default '';
|
||||
update album
|
||||
set mbz_album_type_new = mbz_album_type
|
||||
where mbz_album_type is not null;
|
||||
alter table album
|
||||
drop mbz_album_type;
|
||||
alter table album
|
||||
rename mbz_album_type_new to mbz_album_type;
|
||||
|
||||
alter table album
|
||||
add mbz_album_comment_new varchar not null default '';
|
||||
update album
|
||||
set mbz_album_comment_new = mbz_album_comment
|
||||
where mbz_album_comment is not null;
|
||||
alter table album
|
||||
drop mbz_album_comment;
|
||||
alter table album
|
||||
rename mbz_album_comment_new to mbz_album_comment;
|
||||
|
||||
alter table album
|
||||
add discs_new jsonb not null default '{}';
|
||||
update album
|
||||
set discs_new = discs
|
||||
where discs is not null;
|
||||
alter table album
|
||||
drop discs;
|
||||
alter table album
|
||||
rename discs_new to discs;
|
||||
|
||||
-- ARTIST
|
||||
alter table artist
|
||||
add order_artist_name_new varchar not null default '';
|
||||
update artist
|
||||
set order_artist_name_new = order_artist_name
|
||||
where order_artist_name is not null;
|
||||
alter table artist
|
||||
drop order_artist_name;
|
||||
alter table artist
|
||||
rename order_artist_name_new to order_artist_name;
|
||||
|
||||
alter table artist
|
||||
add sort_artist_name_new varchar not null default '';
|
||||
update artist
|
||||
set sort_artist_name_new = sort_artist_name
|
||||
where sort_artist_name is not null;
|
||||
alter table artist
|
||||
drop sort_artist_name;
|
||||
alter table artist
|
||||
rename sort_artist_name_new to sort_artist_name;
|
||||
|
||||
alter table artist
|
||||
add mbz_artist_id_new varchar not null default '';
|
||||
update artist
|
||||
set mbz_artist_id_new = mbz_artist_id
|
||||
where mbz_artist_id is not null;
|
||||
alter table artist
|
||||
drop mbz_artist_id;
|
||||
alter table artist
|
||||
rename mbz_artist_id_new to mbz_artist_id;
|
||||
|
||||
-- MEDIA_FILE
|
||||
alter table media_file
|
||||
add order_album_name_new varchar not null default '';
|
||||
update media_file
|
||||
set order_album_name_new = order_album_name
|
||||
where order_album_name is not null;
|
||||
alter table media_file
|
||||
drop order_album_name;
|
||||
alter table media_file
|
||||
rename order_album_name_new to order_album_name;
|
||||
|
||||
alter table media_file
|
||||
add order_album_artist_name_new varchar not null default '';
|
||||
update media_file
|
||||
set order_album_artist_name_new = order_album_artist_name
|
||||
where order_album_artist_name is not null;
|
||||
alter table media_file
|
||||
drop order_album_artist_name;
|
||||
alter table media_file
|
||||
rename order_album_artist_name_new to order_album_artist_name;
|
||||
|
||||
alter table media_file
|
||||
add order_artist_name_new varchar not null default '';
|
||||
update media_file
|
||||
set order_artist_name_new = order_artist_name
|
||||
where order_artist_name is not null;
|
||||
alter table media_file
|
||||
drop order_artist_name;
|
||||
alter table media_file
|
||||
rename order_artist_name_new to order_artist_name;
|
||||
|
||||
alter table media_file
|
||||
add sort_album_name_new varchar not null default '';
|
||||
update media_file
|
||||
set sort_album_name_new = sort_album_name
|
||||
where sort_album_name is not null;
|
||||
alter table media_file
|
||||
drop sort_album_name;
|
||||
alter table media_file
|
||||
rename sort_album_name_new to sort_album_name;
|
||||
|
||||
alter table media_file
|
||||
add sort_artist_name_new varchar not null default '';
|
||||
update media_file
|
||||
set sort_artist_name_new = sort_artist_name
|
||||
where sort_artist_name is not null;
|
||||
alter table media_file
|
||||
drop sort_artist_name;
|
||||
alter table media_file
|
||||
rename sort_artist_name_new to sort_artist_name;
|
||||
|
||||
alter table media_file
|
||||
add sort_album_artist_name_new varchar not null default '';
|
||||
update media_file
|
||||
set sort_album_artist_name_new = sort_album_artist_name
|
||||
where sort_album_artist_name is not null;
|
||||
alter table media_file
|
||||
drop sort_album_artist_name;
|
||||
alter table media_file
|
||||
rename sort_album_artist_name_new to sort_album_artist_name;
|
||||
|
||||
alter table media_file
|
||||
add sort_title_new varchar not null default '';
|
||||
update media_file
|
||||
set sort_title_new = sort_title
|
||||
where sort_title is not null;
|
||||
alter table media_file
|
||||
drop sort_title;
|
||||
alter table media_file
|
||||
rename sort_title_new to sort_title;
|
||||
|
||||
alter table media_file
|
||||
add disc_subtitle_new varchar not null default '';
|
||||
update media_file
|
||||
set disc_subtitle_new = disc_subtitle
|
||||
where disc_subtitle is not null;
|
||||
alter table media_file
|
||||
drop disc_subtitle;
|
||||
alter table media_file
|
||||
rename disc_subtitle_new to disc_subtitle;
|
||||
|
||||
alter table media_file
|
||||
add catalog_num_new varchar not null default '';
|
||||
update media_file
|
||||
set catalog_num_new = catalog_num
|
||||
where catalog_num is not null;
|
||||
alter table media_file
|
||||
drop catalog_num;
|
||||
alter table media_file
|
||||
rename catalog_num_new to catalog_num;
|
||||
|
||||
alter table media_file
|
||||
add comment_new varchar not null default '';
|
||||
update media_file
|
||||
set comment_new = comment
|
||||
where comment is not null;
|
||||
alter table media_file
|
||||
drop comment;
|
||||
alter table media_file
|
||||
rename comment_new to comment;
|
||||
|
||||
alter table media_file
|
||||
add order_title_new varchar not null default '';
|
||||
update media_file
|
||||
set order_title_new = order_title
|
||||
where order_title is not null;
|
||||
alter table media_file
|
||||
drop order_title;
|
||||
alter table media_file
|
||||
rename order_title_new to order_title;
|
||||
|
||||
alter table media_file
|
||||
add mbz_recording_id_new varchar not null default '';
|
||||
update media_file
|
||||
set mbz_recording_id_new = mbz_recording_id
|
||||
where mbz_recording_id is not null;
|
||||
alter table media_file
|
||||
drop mbz_recording_id;
|
||||
alter table media_file
|
||||
rename mbz_recording_id_new to mbz_recording_id;
|
||||
|
||||
alter table media_file
|
||||
add mbz_album_id_new varchar not null default '';
|
||||
update media_file
|
||||
set mbz_album_id_new = mbz_album_id
|
||||
where mbz_album_id is not null;
|
||||
alter table media_file
|
||||
drop mbz_album_id;
|
||||
alter table media_file
|
||||
rename mbz_album_id_new to mbz_album_id;
|
||||
|
||||
alter table media_file
|
||||
add mbz_artist_id_new varchar not null default '';
|
||||
update media_file
|
||||
set mbz_artist_id_new = mbz_artist_id
|
||||
where mbz_artist_id is not null;
|
||||
alter table media_file
|
||||
drop mbz_artist_id;
|
||||
alter table media_file
|
||||
rename mbz_artist_id_new to mbz_artist_id;
|
||||
|
||||
alter table media_file
|
||||
add mbz_artist_id_new varchar not null default '';
|
||||
update media_file
|
||||
set mbz_artist_id_new = mbz_artist_id
|
||||
where mbz_artist_id is not null;
|
||||
alter table media_file
|
||||
drop mbz_artist_id;
|
||||
alter table media_file
|
||||
rename mbz_artist_id_new to mbz_artist_id;
|
||||
|
||||
alter table media_file
|
||||
add mbz_album_artist_id_new varchar not null default '';
|
||||
update media_file
|
||||
set mbz_album_artist_id_new = mbz_album_artist_id
|
||||
where mbz_album_artist_id is not null;
|
||||
alter table media_file
|
||||
drop mbz_album_artist_id;
|
||||
alter table media_file
|
||||
rename mbz_album_artist_id_new to mbz_album_artist_id;
|
||||
|
||||
alter table media_file
|
||||
add mbz_album_type_new varchar not null default '';
|
||||
update media_file
|
||||
set mbz_album_type_new = mbz_album_type
|
||||
where mbz_album_type is not null;
|
||||
alter table media_file
|
||||
drop mbz_album_type;
|
||||
alter table media_file
|
||||
rename mbz_album_type_new to mbz_album_type;
|
||||
|
||||
alter table media_file
|
||||
add mbz_album_comment_new varchar not null default '';
|
||||
update media_file
|
||||
set mbz_album_comment_new = mbz_album_comment
|
||||
where mbz_album_comment is not null;
|
||||
alter table media_file
|
||||
drop mbz_album_comment;
|
||||
alter table media_file
|
||||
rename mbz_album_comment_new to mbz_album_comment;
|
||||
|
||||
alter table media_file
|
||||
add mbz_release_track_id_new varchar not null default '';
|
||||
update media_file
|
||||
set mbz_release_track_id_new = mbz_release_track_id
|
||||
where mbz_release_track_id is not null;
|
||||
alter table media_file
|
||||
drop mbz_release_track_id;
|
||||
alter table media_file
|
||||
rename mbz_release_track_id_new to mbz_release_track_id;
|
||||
|
||||
alter table media_file
|
||||
add bpm_new integer not null default 0;
|
||||
update media_file
|
||||
set bpm_new = bpm
|
||||
where bpm is not null;
|
||||
alter table media_file
|
||||
drop bpm;
|
||||
alter table media_file
|
||||
rename bpm_new to bpm;
|
||||
|
||||
alter table media_file
|
||||
add channels_new integer not null default 0;
|
||||
update media_file
|
||||
set channels_new = channels
|
||||
where channels is not null;
|
||||
alter table media_file
|
||||
drop channels;
|
||||
alter table media_file
|
||||
rename channels_new to channels;
|
||||
|
||||
alter table media_file
|
||||
add rg_album_gain_new real not null default 0;
|
||||
update media_file
|
||||
set rg_album_gain_new = rg_album_gain
|
||||
where rg_album_gain is not null;
|
||||
alter table media_file
|
||||
drop rg_album_gain;
|
||||
alter table media_file
|
||||
rename rg_album_gain_new to rg_album_gain;
|
||||
|
||||
alter table media_file
|
||||
add rg_album_peak_new real not null default 0;
|
||||
update media_file
|
||||
set rg_album_peak_new = rg_album_peak
|
||||
where rg_album_peak is not null;
|
||||
alter table media_file
|
||||
drop rg_album_peak;
|
||||
alter table media_file
|
||||
rename rg_album_peak_new to rg_album_peak;
|
||||
|
||||
alter table media_file
|
||||
add rg_track_gain_new real not null default 0;
|
||||
update media_file
|
||||
set rg_track_gain_new = rg_track_gain
|
||||
where rg_track_gain is not null;
|
||||
alter table media_file
|
||||
drop rg_track_gain;
|
||||
alter table media_file
|
||||
rename rg_track_gain_new to rg_track_gain;
|
||||
|
||||
alter table media_file
|
||||
add rg_track_peak_new real not null default 0;
|
||||
update media_file
|
||||
set rg_track_peak_new = rg_track_peak
|
||||
where rg_track_peak is not null;
|
||||
alter table media_file
|
||||
drop rg_track_peak;
|
||||
alter table media_file
|
||||
rename rg_track_peak_new to rg_track_peak;
|
||||
|
||||
alter table media_file
|
||||
add lyrics_new jsonb not null default '[]';
|
||||
update media_file
|
||||
set lyrics_new = lyrics
|
||||
where lyrics is not null;
|
||||
alter table media_file
|
||||
drop lyrics;
|
||||
alter table media_file
|
||||
rename lyrics_new to lyrics;
|
||||
|
||||
-- SHARE
|
||||
alter table share
|
||||
add description_new varchar not null default '';
|
||||
update share
|
||||
set description_new = description
|
||||
where description is not null;
|
||||
alter table share
|
||||
drop description;
|
||||
alter table share
|
||||
rename description_new to description;
|
||||
|
||||
alter table share
|
||||
add resource_type_new varchar not null default '';
|
||||
update share
|
||||
set resource_type_new = resource_type
|
||||
where resource_type is not null;
|
||||
alter table share
|
||||
drop resource_type;
|
||||
alter table share
|
||||
rename resource_type_new to resource_type;
|
||||
|
||||
alter table share
|
||||
add contents_new varchar not null default '';
|
||||
update share
|
||||
set contents_new = contents
|
||||
where contents is not null;
|
||||
alter table share
|
||||
drop contents;
|
||||
alter table share
|
||||
rename contents_new to contents;
|
||||
|
||||
alter table share
|
||||
add format_new varchar not null default '';
|
||||
update share
|
||||
set format_new = format
|
||||
where format is not null;
|
||||
alter table share
|
||||
drop format;
|
||||
alter table share
|
||||
rename format_new to format;
|
||||
|
||||
alter table share
|
||||
add max_bit_rate_new integer not null default 0;
|
||||
update share
|
||||
set max_bit_rate_new = max_bit_rate
|
||||
where max_bit_rate is not null;
|
||||
alter table share
|
||||
drop max_bit_rate;
|
||||
alter table share
|
||||
rename max_bit_rate_new to max_bit_rate;
|
||||
|
||||
alter table share
|
||||
add visit_count_new integer not null default 0;
|
||||
update share
|
||||
set visit_count_new = visit_count
|
||||
where visit_count is not null;
|
||||
alter table share
|
||||
drop visit_count;
|
||||
alter table share
|
||||
rename visit_count_new to visit_count;
|
||||
|
||||
-- INDEX
|
||||
create index album_alphabetical_by_artist
|
||||
on album (compilation, order_album_artist_name, order_album_name);
|
||||
|
||||
create index album_order_album_name
|
||||
on album (order_album_name);
|
||||
|
||||
create index album_order_album_artist_name
|
||||
on album (order_album_artist_name);
|
||||
|
||||
create index album_mbz_album_type
|
||||
on album (mbz_album_type);
|
||||
|
||||
create index artist_order_artist_name
|
||||
on artist (order_artist_name);
|
||||
|
||||
create index media_file_order_album_name
|
||||
on media_file (order_album_name);
|
||||
|
||||
create index media_file_order_artist_name
|
||||
on media_file (order_artist_name);
|
||||
|
||||
create index media_file_order_title
|
||||
on media_file (order_title);
|
||||
|
||||
create index media_file_bpm
|
||||
on media_file (bpm);
|
||||
|
||||
create index media_file_channels
|
||||
on media_file (channels);
|
||||
|
||||
create index media_file_mbz_track_id
|
||||
on media_file (mbz_recording_id);
|
||||
|
||||
`)
|
||||
return err
|
||||
}
|
||||
|
||||
func Down20240122223340(context.Context, *sql.Tx) error {
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/pressly/goose/v3"
|
||||
)
|
||||
|
||||
func init() {
|
||||
goose.AddMigrationContext(upAddIdToScrobbleBuffer, downAddIdToScrobbleBuffer)
|
||||
}
|
||||
|
||||
func upAddIdToScrobbleBuffer(ctx context.Context, tx *sql.Tx) error {
|
||||
_, err := tx.ExecContext(ctx, `
|
||||
delete from scrobble_buffer where user_id <> '';
|
||||
alter table scrobble_buffer add id varchar not null default '';
|
||||
create unique index scrobble_buffer_id_ix
|
||||
on scrobble_buffer (id);
|
||||
`)
|
||||
return err
|
||||
}
|
||||
|
||||
func downAddIdToScrobbleBuffer(ctx context.Context, tx *sql.Tx) error {
|
||||
_, err := tx.ExecContext(ctx, `
|
||||
drop index scrobble_buffer_id_ix;
|
||||
alter table scrobble_buffer drop id;
|
||||
`)
|
||||
return err
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/navidrome/navidrome/consts"
|
||||
)
|
||||
|
||||
// Use this in migrations that need to communicate something important (breaking changes, forced reindexes, etc...)
|
||||
func notice(tx *sql.Tx, msg string) {
|
||||
if isDBInitialized(tx) {
|
||||
fmt.Printf(`
|
||||
*************************************************************************************
|
||||
NOTICE: %s
|
||||
*************************************************************************************
|
||||
|
||||
`, msg)
|
||||
}
|
||||
}
|
||||
|
||||
// Call this in migrations that requires a full rescan
|
||||
func forceFullRescan(tx *sql.Tx) error {
|
||||
_, err := tx.Exec(`
|
||||
delete from property where id like 'LastScan%';
|
||||
update media_file set updated_at = '0001-01-01';
|
||||
`)
|
||||
return err
|
||||
}
|
||||
|
||||
var (
|
||||
once sync.Once
|
||||
initialized bool
|
||||
)
|
||||
|
||||
func isDBInitialized(tx *sql.Tx) bool {
|
||||
once.Do(func() {
|
||||
rows, err := tx.Query("select count(*) from property where id=?", consts.InitialSetupFlagKey)
|
||||
checkErr(err)
|
||||
initialized = checkCount(rows) > 0
|
||||
})
|
||||
return initialized
|
||||
}
|
||||
|
||||
func checkCount(rows *sql.Rows) (count int) {
|
||||
for rows.Next() {
|
||||
err := rows.Scan(&count)
|
||||
checkErr(err)
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
||||
func checkErr(err error) {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user