mirror of
https://github.com/austinried/subtracks.git
synced 2025-12-27 09:09:29 +01:00
refactor artist to use coverArt
fix cover art image caching
This commit is contained in:
parent
42ff02f88e
commit
aaab1d1278
@ -2,32 +2,66 @@
|
|||||||
import { SubsonicClient } from "./util/subsonic.ts";
|
import { SubsonicClient } from "./util/subsonic.ts";
|
||||||
import { sleep } from "./util/util.ts";
|
import { sleep } from "./util/util.ts";
|
||||||
|
|
||||||
|
async function getArtistId(
|
||||||
|
client: SubsonicClient,
|
||||||
|
artist: string,
|
||||||
|
): Promise<string> {
|
||||||
|
const { xml } = await client.get("getArtists");
|
||||||
|
|
||||||
|
return xml.querySelector(
|
||||||
|
`artist[name='${artist.replaceAll("'", "\\'")}']`,
|
||||||
|
)?.id!;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getAlbumId(
|
||||||
|
client: SubsonicClient,
|
||||||
|
album: string,
|
||||||
|
): Promise<string> {
|
||||||
|
const { xml } = await client.get("getAlbumList2", [
|
||||||
|
["type", "newest"],
|
||||||
|
]);
|
||||||
|
|
||||||
|
return xml.querySelector(
|
||||||
|
`album[name='${album.replaceAll("'", "\\'")}']`,
|
||||||
|
)?.id!;
|
||||||
|
}
|
||||||
|
|
||||||
async function getSongId(
|
async function getSongId(
|
||||||
client: SubsonicClient,
|
client: SubsonicClient,
|
||||||
album: string,
|
album: string,
|
||||||
track: number,
|
track: number,
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
const { xml: albumsXml } = await client.get("getAlbumList2", [
|
const albumId = await getAlbumId(client, album);
|
||||||
["type", "newest"],
|
|
||||||
]);
|
|
||||||
const albumId = albumsXml.querySelector(
|
|
||||||
`album[name='${album.replaceAll("'", "\\'")}']`,
|
|
||||||
)?.id;
|
|
||||||
|
|
||||||
const { xml: songsXml } = await client.get("getAlbum", [["id", albumId!]]);
|
const { xml } = await client.get("getAlbum", [["id", albumId!]]);
|
||||||
return songsXml.querySelector(`song[track='${track}']`)?.id!;
|
return xml.querySelector(`song[track='${track}']`)?.id!;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function scrobbleTrack(
|
async function scrobbleTrack(
|
||||||
client: SubsonicClient,
|
client: SubsonicClient,
|
||||||
songId: string,
|
album: string,
|
||||||
|
track: number,
|
||||||
) {
|
) {
|
||||||
|
const songId = await getSongId(client, album, track);
|
||||||
|
|
||||||
await client.get("scrobble", [
|
await client.get("scrobble", [
|
||||||
["id", songId!],
|
["id", songId!],
|
||||||
["submission", "true"],
|
["submission", "true"],
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function starAlbum(client: SubsonicClient, album: string) {
|
||||||
|
const albumId = await getAlbumId(client, album);
|
||||||
|
|
||||||
|
await client.get("star", [["albumId", albumId]]);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function starArtist(client: SubsonicClient, artist: string) {
|
||||||
|
const artistId = await getArtistId(client, artist);
|
||||||
|
|
||||||
|
await client.get("star", [["artistId", artistId]]);
|
||||||
|
}
|
||||||
|
|
||||||
async function createPlaylist(
|
async function createPlaylist(
|
||||||
client: SubsonicClient,
|
client: SubsonicClient,
|
||||||
name: string,
|
name: string,
|
||||||
@ -44,17 +78,11 @@ async function createPlaylist(
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function setupTestData(client: SubsonicClient) {
|
async function setupTestData(client: SubsonicClient) {
|
||||||
await scrobbleTrack(
|
await scrobbleTrack(client, "Retroconnaissance EP", 1);
|
||||||
client,
|
|
||||||
await getSongId(client, "Retroconnaissance EP", 1),
|
|
||||||
);
|
|
||||||
await sleep(1_000);
|
await sleep(1_000);
|
||||||
await scrobbleTrack(
|
await scrobbleTrack(client, "Retroconnaissance EP", 2);
|
||||||
client,
|
|
||||||
await getSongId(client, "Retroconnaissance EP", 2),
|
|
||||||
);
|
|
||||||
await sleep(1_000);
|
await sleep(1_000);
|
||||||
await scrobbleTrack(client, await getSongId(client, "Kosmonaut", 1));
|
await scrobbleTrack(client, "Kosmonaut", 1);
|
||||||
|
|
||||||
await createPlaylist(client, "Playlist 1", [
|
await createPlaylist(client, "Playlist 1", [
|
||||||
{ album: "Retroconnaissance EP", track: 2 },
|
{ album: "Retroconnaissance EP", track: 2 },
|
||||||
@ -65,6 +93,9 @@ async function setupTestData(client: SubsonicClient) {
|
|||||||
{ album: "I Don't Know What I'm Doing", track: 10 },
|
{ album: "I Don't Know What I'm Doing", track: 10 },
|
||||||
{ album: "I Don't Know What I'm Doing", track: 11 },
|
{ album: "I Don't Know What I'm Doing", track: 11 },
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
await starAlbum(client, "Kosmonaut");
|
||||||
|
await starArtist(client, "Ugress");
|
||||||
}
|
}
|
||||||
|
|
||||||
async function setupNavidrome() {
|
async function setupNavidrome() {
|
||||||
|
|||||||
@ -47,9 +47,7 @@ class ArtistListTile extends StatelessWidget {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ListTile(
|
return ListTile(
|
||||||
leading: CircleClip(
|
leading: CircleClip(
|
||||||
child: artist.coverArt != null
|
child: CoverArtImage(coverArt: artist.coverArt),
|
||||||
? CoverArtImage(coverArt: artist.coverArt)
|
|
||||||
: CachedImage(artist.smallImage),
|
|
||||||
),
|
),
|
||||||
title: Text(artist.name),
|
title: Text(artist.name),
|
||||||
subtitle: albumCount != null ? Text('$albumCount albums') : null,
|
subtitle: albumCount != null ? Text('$albumCount albums') : null,
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
|
||||||
import '../../services/sync_services.dart';
|
import '../../services/sync_service.dart';
|
||||||
import 'database.dart';
|
import 'database.dart';
|
||||||
import 'settings.dart';
|
import 'settings.dart';
|
||||||
import 'source.dart';
|
import 'source.dart';
|
||||||
|
|||||||
@ -438,8 +438,6 @@ extension ArtistToDb on models.Artist {
|
|||||||
name: name,
|
name: name,
|
||||||
starred: Value(starred),
|
starred: Value(starred),
|
||||||
coverArt: Value(coverArt),
|
coverArt: Value(coverArt),
|
||||||
smallImage: Value(smallImage),
|
|
||||||
largeImage: Value(largeImage),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -719,34 +719,8 @@ class Artists extends Table with TableInfo<Artists, models.Artist> {
|
|||||||
requiredDuringInsert: false,
|
requiredDuringInsert: false,
|
||||||
$customConstraints: '',
|
$customConstraints: '',
|
||||||
);
|
);
|
||||||
late final GeneratedColumnWithTypeConverter<Uri?, String> smallImage =
|
|
||||||
GeneratedColumn<String>(
|
|
||||||
'small_image',
|
|
||||||
aliasedName,
|
|
||||||
true,
|
|
||||||
type: DriftSqlType.string,
|
|
||||||
requiredDuringInsert: false,
|
|
||||||
$customConstraints: '',
|
|
||||||
).withConverter<Uri?>(Artists.$convertersmallImagen);
|
|
||||||
late final GeneratedColumnWithTypeConverter<Uri?, String> largeImage =
|
|
||||||
GeneratedColumn<String>(
|
|
||||||
'large_image',
|
|
||||||
aliasedName,
|
|
||||||
true,
|
|
||||||
type: DriftSqlType.string,
|
|
||||||
requiredDuringInsert: false,
|
|
||||||
$customConstraints: '',
|
|
||||||
).withConverter<Uri?>(Artists.$converterlargeImagen);
|
|
||||||
@override
|
@override
|
||||||
List<GeneratedColumn> get $columns => [
|
List<GeneratedColumn> get $columns => [sourceId, id, name, starred, coverArt];
|
||||||
sourceId,
|
|
||||||
id,
|
|
||||||
name,
|
|
||||||
starred,
|
|
||||||
coverArt,
|
|
||||||
smallImage,
|
|
||||||
largeImage,
|
|
||||||
];
|
|
||||||
@override
|
@override
|
||||||
String get aliasedName => _alias ?? actualTableName;
|
String get aliasedName => _alias ?? actualTableName;
|
||||||
@override
|
@override
|
||||||
@ -817,18 +791,6 @@ class Artists extends Table with TableInfo<Artists, models.Artist> {
|
|||||||
DriftSqlType.string,
|
DriftSqlType.string,
|
||||||
data['${effectivePrefix}cover_art'],
|
data['${effectivePrefix}cover_art'],
|
||||||
),
|
),
|
||||||
smallImage: Artists.$convertersmallImagen.fromSql(
|
|
||||||
attachedDatabase.typeMapping.read(
|
|
||||||
DriftSqlType.string,
|
|
||||||
data['${effectivePrefix}small_image'],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
largeImage: Artists.$converterlargeImagen.fromSql(
|
|
||||||
attachedDatabase.typeMapping.read(
|
|
||||||
DriftSqlType.string,
|
|
||||||
data['${effectivePrefix}large_image'],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -837,12 +799,6 @@ class Artists extends Table with TableInfo<Artists, models.Artist> {
|
|||||||
return Artists(attachedDatabase, alias);
|
return Artists(attachedDatabase, alias);
|
||||||
}
|
}
|
||||||
|
|
||||||
static TypeConverter<Uri, String> $convertersmallImage = const UriConverter();
|
|
||||||
static TypeConverter<Uri?, String?> $convertersmallImagen =
|
|
||||||
NullAwareTypeConverter.wrap($convertersmallImage);
|
|
||||||
static TypeConverter<Uri, String> $converterlargeImage = const UriConverter();
|
|
||||||
static TypeConverter<Uri?, String?> $converterlargeImagen =
|
|
||||||
NullAwareTypeConverter.wrap($converterlargeImage);
|
|
||||||
@override
|
@override
|
||||||
List<String> get customConstraints => const [
|
List<String> get customConstraints => const [
|
||||||
'PRIMARY KEY(source_id, id)',
|
'PRIMARY KEY(source_id, id)',
|
||||||
@ -858,8 +814,6 @@ class ArtistsCompanion extends UpdateCompanion<models.Artist> {
|
|||||||
final Value<String> name;
|
final Value<String> name;
|
||||||
final Value<DateTime?> starred;
|
final Value<DateTime?> starred;
|
||||||
final Value<String?> coverArt;
|
final Value<String?> coverArt;
|
||||||
final Value<Uri?> smallImage;
|
|
||||||
final Value<Uri?> largeImage;
|
|
||||||
final Value<int> rowid;
|
final Value<int> rowid;
|
||||||
const ArtistsCompanion({
|
const ArtistsCompanion({
|
||||||
this.sourceId = const Value.absent(),
|
this.sourceId = const Value.absent(),
|
||||||
@ -867,8 +821,6 @@ class ArtistsCompanion extends UpdateCompanion<models.Artist> {
|
|||||||
this.name = const Value.absent(),
|
this.name = const Value.absent(),
|
||||||
this.starred = const Value.absent(),
|
this.starred = const Value.absent(),
|
||||||
this.coverArt = const Value.absent(),
|
this.coverArt = const Value.absent(),
|
||||||
this.smallImage = const Value.absent(),
|
|
||||||
this.largeImage = const Value.absent(),
|
|
||||||
this.rowid = const Value.absent(),
|
this.rowid = const Value.absent(),
|
||||||
});
|
});
|
||||||
ArtistsCompanion.insert({
|
ArtistsCompanion.insert({
|
||||||
@ -877,8 +829,6 @@ class ArtistsCompanion extends UpdateCompanion<models.Artist> {
|
|||||||
required String name,
|
required String name,
|
||||||
this.starred = const Value.absent(),
|
this.starred = const Value.absent(),
|
||||||
this.coverArt = const Value.absent(),
|
this.coverArt = const Value.absent(),
|
||||||
this.smallImage = const Value.absent(),
|
|
||||||
this.largeImage = const Value.absent(),
|
|
||||||
this.rowid = const Value.absent(),
|
this.rowid = const Value.absent(),
|
||||||
}) : sourceId = Value(sourceId),
|
}) : sourceId = Value(sourceId),
|
||||||
id = Value(id),
|
id = Value(id),
|
||||||
@ -889,8 +839,6 @@ class ArtistsCompanion extends UpdateCompanion<models.Artist> {
|
|||||||
Expression<String>? name,
|
Expression<String>? name,
|
||||||
Expression<DateTime>? starred,
|
Expression<DateTime>? starred,
|
||||||
Expression<String>? coverArt,
|
Expression<String>? coverArt,
|
||||||
Expression<String>? smallImage,
|
|
||||||
Expression<String>? largeImage,
|
|
||||||
Expression<int>? rowid,
|
Expression<int>? rowid,
|
||||||
}) {
|
}) {
|
||||||
return RawValuesInsertable({
|
return RawValuesInsertable({
|
||||||
@ -899,8 +847,6 @@ class ArtistsCompanion extends UpdateCompanion<models.Artist> {
|
|||||||
if (name != null) 'name': name,
|
if (name != null) 'name': name,
|
||||||
if (starred != null) 'starred': starred,
|
if (starred != null) 'starred': starred,
|
||||||
if (coverArt != null) 'cover_art': coverArt,
|
if (coverArt != null) 'cover_art': coverArt,
|
||||||
if (smallImage != null) 'small_image': smallImage,
|
|
||||||
if (largeImage != null) 'large_image': largeImage,
|
|
||||||
if (rowid != null) 'rowid': rowid,
|
if (rowid != null) 'rowid': rowid,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -911,8 +857,6 @@ class ArtistsCompanion extends UpdateCompanion<models.Artist> {
|
|||||||
Value<String>? name,
|
Value<String>? name,
|
||||||
Value<DateTime?>? starred,
|
Value<DateTime?>? starred,
|
||||||
Value<String?>? coverArt,
|
Value<String?>? coverArt,
|
||||||
Value<Uri?>? smallImage,
|
|
||||||
Value<Uri?>? largeImage,
|
|
||||||
Value<int>? rowid,
|
Value<int>? rowid,
|
||||||
}) {
|
}) {
|
||||||
return ArtistsCompanion(
|
return ArtistsCompanion(
|
||||||
@ -921,8 +865,6 @@ class ArtistsCompanion extends UpdateCompanion<models.Artist> {
|
|||||||
name: name ?? this.name,
|
name: name ?? this.name,
|
||||||
starred: starred ?? this.starred,
|
starred: starred ?? this.starred,
|
||||||
coverArt: coverArt ?? this.coverArt,
|
coverArt: coverArt ?? this.coverArt,
|
||||||
smallImage: smallImage ?? this.smallImage,
|
|
||||||
largeImage: largeImage ?? this.largeImage,
|
|
||||||
rowid: rowid ?? this.rowid,
|
rowid: rowid ?? this.rowid,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -945,16 +887,6 @@ class ArtistsCompanion extends UpdateCompanion<models.Artist> {
|
|||||||
if (coverArt.present) {
|
if (coverArt.present) {
|
||||||
map['cover_art'] = Variable<String>(coverArt.value);
|
map['cover_art'] = Variable<String>(coverArt.value);
|
||||||
}
|
}
|
||||||
if (smallImage.present) {
|
|
||||||
map['small_image'] = Variable<String>(
|
|
||||||
Artists.$convertersmallImagen.toSql(smallImage.value),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (largeImage.present) {
|
|
||||||
map['large_image'] = Variable<String>(
|
|
||||||
Artists.$converterlargeImagen.toSql(largeImage.value),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (rowid.present) {
|
if (rowid.present) {
|
||||||
map['rowid'] = Variable<int>(rowid.value);
|
map['rowid'] = Variable<int>(rowid.value);
|
||||||
}
|
}
|
||||||
@ -969,8 +901,6 @@ class ArtistsCompanion extends UpdateCompanion<models.Artist> {
|
|||||||
..write('name: $name, ')
|
..write('name: $name, ')
|
||||||
..write('starred: $starred, ')
|
..write('starred: $starred, ')
|
||||||
..write('coverArt: $coverArt, ')
|
..write('coverArt: $coverArt, ')
|
||||||
..write('smallImage: $smallImage, ')
|
|
||||||
..write('largeImage: $largeImage, ')
|
|
||||||
..write('rowid: $rowid')
|
..write('rowid: $rowid')
|
||||||
..write(')'))
|
..write(')'))
|
||||||
.toString();
|
.toString();
|
||||||
@ -2967,8 +2897,6 @@ typedef $ArtistsCreateCompanionBuilder =
|
|||||||
required String name,
|
required String name,
|
||||||
Value<DateTime?> starred,
|
Value<DateTime?> starred,
|
||||||
Value<String?> coverArt,
|
Value<String?> coverArt,
|
||||||
Value<Uri?> smallImage,
|
|
||||||
Value<Uri?> largeImage,
|
|
||||||
Value<int> rowid,
|
Value<int> rowid,
|
||||||
});
|
});
|
||||||
typedef $ArtistsUpdateCompanionBuilder =
|
typedef $ArtistsUpdateCompanionBuilder =
|
||||||
@ -2978,8 +2906,6 @@ typedef $ArtistsUpdateCompanionBuilder =
|
|||||||
Value<String> name,
|
Value<String> name,
|
||||||
Value<DateTime?> starred,
|
Value<DateTime?> starred,
|
||||||
Value<String?> coverArt,
|
Value<String?> coverArt,
|
||||||
Value<Uri?> smallImage,
|
|
||||||
Value<Uri?> largeImage,
|
|
||||||
Value<int> rowid,
|
Value<int> rowid,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -3015,18 +2941,6 @@ class $ArtistsFilterComposer extends Composer<_$SubtracksDatabase, Artists> {
|
|||||||
column: $table.coverArt,
|
column: $table.coverArt,
|
||||||
builder: (column) => ColumnFilters(column),
|
builder: (column) => ColumnFilters(column),
|
||||||
);
|
);
|
||||||
|
|
||||||
ColumnWithTypeConverterFilters<Uri?, Uri, String> get smallImage =>
|
|
||||||
$composableBuilder(
|
|
||||||
column: $table.smallImage,
|
|
||||||
builder: (column) => ColumnWithTypeConverterFilters(column),
|
|
||||||
);
|
|
||||||
|
|
||||||
ColumnWithTypeConverterFilters<Uri?, Uri, String> get largeImage =>
|
|
||||||
$composableBuilder(
|
|
||||||
column: $table.largeImage,
|
|
||||||
builder: (column) => ColumnWithTypeConverterFilters(column),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class $ArtistsOrderingComposer extends Composer<_$SubtracksDatabase, Artists> {
|
class $ArtistsOrderingComposer extends Composer<_$SubtracksDatabase, Artists> {
|
||||||
@ -3061,16 +2975,6 @@ class $ArtistsOrderingComposer extends Composer<_$SubtracksDatabase, Artists> {
|
|||||||
column: $table.coverArt,
|
column: $table.coverArt,
|
||||||
builder: (column) => ColumnOrderings(column),
|
builder: (column) => ColumnOrderings(column),
|
||||||
);
|
);
|
||||||
|
|
||||||
ColumnOrderings<String> get smallImage => $composableBuilder(
|
|
||||||
column: $table.smallImage,
|
|
||||||
builder: (column) => ColumnOrderings(column),
|
|
||||||
);
|
|
||||||
|
|
||||||
ColumnOrderings<String> get largeImage => $composableBuilder(
|
|
||||||
column: $table.largeImage,
|
|
||||||
builder: (column) => ColumnOrderings(column),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class $ArtistsAnnotationComposer
|
class $ArtistsAnnotationComposer
|
||||||
@ -3096,18 +3000,6 @@ class $ArtistsAnnotationComposer
|
|||||||
|
|
||||||
GeneratedColumn<String> get coverArt =>
|
GeneratedColumn<String> get coverArt =>
|
||||||
$composableBuilder(column: $table.coverArt, builder: (column) => column);
|
$composableBuilder(column: $table.coverArt, builder: (column) => column);
|
||||||
|
|
||||||
GeneratedColumnWithTypeConverter<Uri?, String> get smallImage =>
|
|
||||||
$composableBuilder(
|
|
||||||
column: $table.smallImage,
|
|
||||||
builder: (column) => column,
|
|
||||||
);
|
|
||||||
|
|
||||||
GeneratedColumnWithTypeConverter<Uri?, String> get largeImage =>
|
|
||||||
$composableBuilder(
|
|
||||||
column: $table.largeImage,
|
|
||||||
builder: (column) => column,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class $ArtistsTableManager
|
class $ArtistsTableManager
|
||||||
@ -3146,8 +3038,6 @@ class $ArtistsTableManager
|
|||||||
Value<String> name = const Value.absent(),
|
Value<String> name = const Value.absent(),
|
||||||
Value<DateTime?> starred = const Value.absent(),
|
Value<DateTime?> starred = const Value.absent(),
|
||||||
Value<String?> coverArt = const Value.absent(),
|
Value<String?> coverArt = const Value.absent(),
|
||||||
Value<Uri?> smallImage = const Value.absent(),
|
|
||||||
Value<Uri?> largeImage = const Value.absent(),
|
|
||||||
Value<int> rowid = const Value.absent(),
|
Value<int> rowid = const Value.absent(),
|
||||||
}) => ArtistsCompanion(
|
}) => ArtistsCompanion(
|
||||||
sourceId: sourceId,
|
sourceId: sourceId,
|
||||||
@ -3155,8 +3045,6 @@ class $ArtistsTableManager
|
|||||||
name: name,
|
name: name,
|
||||||
starred: starred,
|
starred: starred,
|
||||||
coverArt: coverArt,
|
coverArt: coverArt,
|
||||||
smallImage: smallImage,
|
|
||||||
largeImage: largeImage,
|
|
||||||
rowid: rowid,
|
rowid: rowid,
|
||||||
),
|
),
|
||||||
createCompanionCallback:
|
createCompanionCallback:
|
||||||
@ -3166,8 +3054,6 @@ class $ArtistsTableManager
|
|||||||
required String name,
|
required String name,
|
||||||
Value<DateTime?> starred = const Value.absent(),
|
Value<DateTime?> starred = const Value.absent(),
|
||||||
Value<String?> coverArt = const Value.absent(),
|
Value<String?> coverArt = const Value.absent(),
|
||||||
Value<Uri?> smallImage = const Value.absent(),
|
|
||||||
Value<Uri?> largeImage = const Value.absent(),
|
|
||||||
Value<int> rowid = const Value.absent(),
|
Value<int> rowid = const Value.absent(),
|
||||||
}) => ArtistsCompanion.insert(
|
}) => ArtistsCompanion.insert(
|
||||||
sourceId: sourceId,
|
sourceId: sourceId,
|
||||||
@ -3175,8 +3061,6 @@ class $ArtistsTableManager
|
|||||||
name: name,
|
name: name,
|
||||||
starred: starred,
|
starred: starred,
|
||||||
coverArt: coverArt,
|
coverArt: coverArt,
|
||||||
smallImage: smallImage,
|
|
||||||
largeImage: largeImage,
|
|
||||||
rowid: rowid,
|
rowid: rowid,
|
||||||
),
|
),
|
||||||
withReferenceMapper: (p0) => p0
|
withReferenceMapper: (p0) => p0
|
||||||
|
|||||||
@ -66,8 +66,6 @@ CREATE TABLE artists(
|
|||||||
name TEXT NOT NULL COLLATE NOCASE,
|
name TEXT NOT NULL COLLATE NOCASE,
|
||||||
starred DATETIME,
|
starred DATETIME,
|
||||||
cover_art TEXT,
|
cover_art TEXT,
|
||||||
small_image TEXT MAPPED BY `const UriConverter()`,
|
|
||||||
large_image TEXT MAPPED BY `const UriConverter()`,
|
|
||||||
PRIMARY KEY (source_id, id),
|
PRIMARY KEY (source_id, id),
|
||||||
FOREIGN KEY (source_id) REFERENCES sources (id) ON DELETE CASCADE
|
FOREIGN KEY (source_id) REFERENCES sources (id) ON DELETE CASCADE
|
||||||
) WITH Artist;
|
) WITH Artist;
|
||||||
|
|||||||
@ -1,9 +1,7 @@
|
|||||||
import 'package:cached_network_image/cached_network_image.dart';
|
import 'package:cached_network_image/cached_network_image.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:material_symbols_icons/symbols.dart';
|
import 'package:material_symbols_icons/symbols.dart';
|
||||||
import 'package:octo_image/octo_image.dart';
|
|
||||||
|
|
||||||
import '../app/state/settings.dart';
|
import '../app/state/settings.dart';
|
||||||
import '../app/state/source.dart';
|
import '../app/state/source.dart';
|
||||||
@ -23,62 +21,14 @@ class CoverArtImage extends HookConsumerWidget {
|
|||||||
final source = ref.watch(sourceProvider);
|
final source = ref.watch(sourceProvider);
|
||||||
final sourceId = ref.watch(sourceIdProvider);
|
final sourceId = ref.watch(sourceIdProvider);
|
||||||
|
|
||||||
final imageProviderKeys = [source, sourceId, coverArt, thumbnail];
|
final imageUrl = coverArt != null
|
||||||
final buildImageProvider = useCallback(
|
? source.coverArtUri(coverArt!, thumbnail: thumbnail).toString()
|
||||||
() => CachedNetworkImageProvider(
|
: 'https://placehold.net/400x400.png';
|
||||||
coverArt != null
|
|
||||||
? source.coverArtUri(coverArt!, thumbnail: thumbnail).toString()
|
|
||||||
: 'https://placehold.net/400x400.png',
|
|
||||||
cacheKey: '$sourceId$coverArt$thumbnail',
|
|
||||||
),
|
|
||||||
imageProviderKeys,
|
|
||||||
);
|
|
||||||
|
|
||||||
final imageProvider = useState(buildImageProvider());
|
|
||||||
useEffect(
|
|
||||||
() {
|
|
||||||
imageProvider.value = buildImageProvider();
|
|
||||||
return;
|
|
||||||
},
|
|
||||||
imageProviderKeys,
|
|
||||||
);
|
|
||||||
|
|
||||||
return BaseImage(
|
return BaseImage(
|
||||||
image: imageProvider.value,
|
imageUrl: imageUrl,
|
||||||
);
|
// can't use the URL because of token auth, which is a cache-buster
|
||||||
}
|
cacheKey: '$sourceId$coverArt$thumbnail',
|
||||||
}
|
|
||||||
|
|
||||||
class CachedImage extends HookConsumerWidget {
|
|
||||||
const CachedImage(
|
|
||||||
this.uri, {
|
|
||||||
super.key,
|
|
||||||
});
|
|
||||||
|
|
||||||
final Uri? uri;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
|
||||||
final imageProviderKeys = [uri];
|
|
||||||
final buildImageProvider = useCallback(
|
|
||||||
() {
|
|
||||||
final imageUrl = uri?.toString() ?? 'https://placehold.net/400x400.png';
|
|
||||||
return CachedNetworkImageProvider(imageUrl, cacheKey: imageUrl);
|
|
||||||
},
|
|
||||||
imageProviderKeys,
|
|
||||||
);
|
|
||||||
|
|
||||||
final imageProvider = useState(buildImageProvider());
|
|
||||||
useEffect(
|
|
||||||
() {
|
|
||||||
imageProvider.value = buildImageProvider();
|
|
||||||
return;
|
|
||||||
},
|
|
||||||
imageProviderKeys,
|
|
||||||
);
|
|
||||||
|
|
||||||
return BaseImage(
|
|
||||||
image: imageProvider.value,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -86,20 +36,23 @@ class CachedImage extends HookConsumerWidget {
|
|||||||
class BaseImage extends HookConsumerWidget {
|
class BaseImage extends HookConsumerWidget {
|
||||||
const BaseImage({
|
const BaseImage({
|
||||||
super.key,
|
super.key,
|
||||||
required this.image,
|
required this.imageUrl,
|
||||||
|
this.cacheKey,
|
||||||
this.fit = BoxFit.cover,
|
this.fit = BoxFit.cover,
|
||||||
});
|
});
|
||||||
|
|
||||||
final ImageProvider image;
|
final String imageUrl;
|
||||||
|
final String? cacheKey;
|
||||||
final BoxFit fit;
|
final BoxFit fit;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
return OctoImage(
|
return CachedNetworkImage(
|
||||||
image: image,
|
imageUrl: imageUrl,
|
||||||
placeholderBuilder: (context) => Icon(Symbols.cached_rounded),
|
cacheKey: cacheKey,
|
||||||
errorBuilder: (context, error, trace) => Icon(Icons.error),
|
placeholder: (context, url) => Icon(Symbols.cached_rounded),
|
||||||
fit: fit,
|
errorWidget: (context, url, error) => Icon(Icons.error),
|
||||||
|
fit: BoxFit.cover,
|
||||||
fadeOutDuration: Duration(milliseconds: 100),
|
fadeOutDuration: Duration(milliseconds: 100),
|
||||||
fadeInDuration: Duration(milliseconds: 200),
|
fadeInDuration: Duration(milliseconds: 200),
|
||||||
);
|
);
|
||||||
|
|||||||
@ -9,8 +9,6 @@ abstract class Artist with _$Artist {
|
|||||||
required String name,
|
required String name,
|
||||||
DateTime? starred,
|
DateTime? starred,
|
||||||
String? coverArt,
|
String? coverArt,
|
||||||
Uri? smallImage,
|
|
||||||
Uri? largeImage,
|
|
||||||
}) = _Artist;
|
}) = _Artist;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -14,7 +14,7 @@ T _$identity<T>(T value) => value;
|
|||||||
/// @nodoc
|
/// @nodoc
|
||||||
mixin _$Artist {
|
mixin _$Artist {
|
||||||
|
|
||||||
String get id; String get name; DateTime? get starred; String? get coverArt; Uri? get smallImage; Uri? get largeImage;
|
String get id; String get name; DateTime? get starred; String? get coverArt;
|
||||||
/// Create a copy of Artist
|
/// Create a copy of Artist
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
@ -25,16 +25,16 @@ $ArtistCopyWith<Artist> get copyWith => _$ArtistCopyWithImpl<Artist>(this as Art
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) {
|
bool operator ==(Object other) {
|
||||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is Artist&&(identical(other.id, id) || other.id == id)&&(identical(other.name, name) || other.name == name)&&(identical(other.starred, starred) || other.starred == starred)&&(identical(other.coverArt, coverArt) || other.coverArt == coverArt)&&(identical(other.smallImage, smallImage) || other.smallImage == smallImage)&&(identical(other.largeImage, largeImage) || other.largeImage == largeImage));
|
return identical(this, other) || (other.runtimeType == runtimeType&&other is Artist&&(identical(other.id, id) || other.id == id)&&(identical(other.name, name) || other.name == name)&&(identical(other.starred, starred) || other.starred == starred)&&(identical(other.coverArt, coverArt) || other.coverArt == coverArt));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int get hashCode => Object.hash(runtimeType,id,name,starred,coverArt,smallImage,largeImage);
|
int get hashCode => Object.hash(runtimeType,id,name,starred,coverArt);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return 'Artist(id: $id, name: $name, starred: $starred, coverArt: $coverArt, smallImage: $smallImage, largeImage: $largeImage)';
|
return 'Artist(id: $id, name: $name, starred: $starred, coverArt: $coverArt)';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -45,7 +45,7 @@ abstract mixin class $ArtistCopyWith<$Res> {
|
|||||||
factory $ArtistCopyWith(Artist value, $Res Function(Artist) _then) = _$ArtistCopyWithImpl;
|
factory $ArtistCopyWith(Artist value, $Res Function(Artist) _then) = _$ArtistCopyWithImpl;
|
||||||
@useResult
|
@useResult
|
||||||
$Res call({
|
$Res call({
|
||||||
String id, String name, DateTime? starred, String? coverArt, Uri? smallImage, Uri? largeImage
|
String id, String name, DateTime? starred, String? coverArt
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@ -62,15 +62,13 @@ class _$ArtistCopyWithImpl<$Res>
|
|||||||
|
|
||||||
/// Create a copy of Artist
|
/// Create a copy of Artist
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? name = null,Object? starred = freezed,Object? coverArt = freezed,Object? smallImage = freezed,Object? largeImage = freezed,}) {
|
@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? name = null,Object? starred = freezed,Object? coverArt = freezed,}) {
|
||||||
return _then(_self.copyWith(
|
return _then(_self.copyWith(
|
||||||
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
|
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
|
||||||
as String,name: null == name ? _self.name : name // ignore: cast_nullable_to_non_nullable
|
as String,name: null == name ? _self.name : name // ignore: cast_nullable_to_non_nullable
|
||||||
as String,starred: freezed == starred ? _self.starred : starred // ignore: cast_nullable_to_non_nullable
|
as String,starred: freezed == starred ? _self.starred : starred // ignore: cast_nullable_to_non_nullable
|
||||||
as DateTime?,coverArt: freezed == coverArt ? _self.coverArt : coverArt // ignore: cast_nullable_to_non_nullable
|
as DateTime?,coverArt: freezed == coverArt ? _self.coverArt : coverArt // ignore: cast_nullable_to_non_nullable
|
||||||
as String?,smallImage: freezed == smallImage ? _self.smallImage : smallImage // ignore: cast_nullable_to_non_nullable
|
as String?,
|
||||||
as Uri?,largeImage: freezed == largeImage ? _self.largeImage : largeImage // ignore: cast_nullable_to_non_nullable
|
|
||||||
as Uri?,
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,10 +153,10 @@ return $default(_that);case _:
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
|
||||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String id, String name, DateTime? starred, String? coverArt, Uri? smallImage, Uri? largeImage)? $default,{required TResult orElse(),}) {final _that = this;
|
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String id, String name, DateTime? starred, String? coverArt)? $default,{required TResult orElse(),}) {final _that = this;
|
||||||
switch (_that) {
|
switch (_that) {
|
||||||
case _Artist() when $default != null:
|
case _Artist() when $default != null:
|
||||||
return $default(_that.id,_that.name,_that.starred,_that.coverArt,_that.smallImage,_that.largeImage);case _:
|
return $default(_that.id,_that.name,_that.starred,_that.coverArt);case _:
|
||||||
return orElse();
|
return orElse();
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -176,10 +174,10 @@ return $default(_that.id,_that.name,_that.starred,_that.coverArt,_that.smallImag
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
|
||||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String id, String name, DateTime? starred, String? coverArt, Uri? smallImage, Uri? largeImage) $default,) {final _that = this;
|
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String id, String name, DateTime? starred, String? coverArt) $default,) {final _that = this;
|
||||||
switch (_that) {
|
switch (_that) {
|
||||||
case _Artist():
|
case _Artist():
|
||||||
return $default(_that.id,_that.name,_that.starred,_that.coverArt,_that.smallImage,_that.largeImage);case _:
|
return $default(_that.id,_that.name,_that.starred,_that.coverArt);case _:
|
||||||
throw StateError('Unexpected subclass');
|
throw StateError('Unexpected subclass');
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -196,10 +194,10 @@ return $default(_that.id,_that.name,_that.starred,_that.coverArt,_that.smallImag
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
|
||||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String id, String name, DateTime? starred, String? coverArt, Uri? smallImage, Uri? largeImage)? $default,) {final _that = this;
|
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String id, String name, DateTime? starred, String? coverArt)? $default,) {final _that = this;
|
||||||
switch (_that) {
|
switch (_that) {
|
||||||
case _Artist() when $default != null:
|
case _Artist() when $default != null:
|
||||||
return $default(_that.id,_that.name,_that.starred,_that.coverArt,_that.smallImage,_that.largeImage);case _:
|
return $default(_that.id,_that.name,_that.starred,_that.coverArt);case _:
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -211,15 +209,13 @@ return $default(_that.id,_that.name,_that.starred,_that.coverArt,_that.smallImag
|
|||||||
|
|
||||||
|
|
||||||
class _Artist implements Artist {
|
class _Artist implements Artist {
|
||||||
const _Artist({required this.id, required this.name, this.starred, this.coverArt, this.smallImage, this.largeImage});
|
const _Artist({required this.id, required this.name, this.starred, this.coverArt});
|
||||||
|
|
||||||
|
|
||||||
@override final String id;
|
@override final String id;
|
||||||
@override final String name;
|
@override final String name;
|
||||||
@override final DateTime? starred;
|
@override final DateTime? starred;
|
||||||
@override final String? coverArt;
|
@override final String? coverArt;
|
||||||
@override final Uri? smallImage;
|
|
||||||
@override final Uri? largeImage;
|
|
||||||
|
|
||||||
/// Create a copy of Artist
|
/// Create a copy of Artist
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@ -231,16 +227,16 @@ _$ArtistCopyWith<_Artist> get copyWith => __$ArtistCopyWithImpl<_Artist>(this, _
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) {
|
bool operator ==(Object other) {
|
||||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _Artist&&(identical(other.id, id) || other.id == id)&&(identical(other.name, name) || other.name == name)&&(identical(other.starred, starred) || other.starred == starred)&&(identical(other.coverArt, coverArt) || other.coverArt == coverArt)&&(identical(other.smallImage, smallImage) || other.smallImage == smallImage)&&(identical(other.largeImage, largeImage) || other.largeImage == largeImage));
|
return identical(this, other) || (other.runtimeType == runtimeType&&other is _Artist&&(identical(other.id, id) || other.id == id)&&(identical(other.name, name) || other.name == name)&&(identical(other.starred, starred) || other.starred == starred)&&(identical(other.coverArt, coverArt) || other.coverArt == coverArt));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int get hashCode => Object.hash(runtimeType,id,name,starred,coverArt,smallImage,largeImage);
|
int get hashCode => Object.hash(runtimeType,id,name,starred,coverArt);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return 'Artist(id: $id, name: $name, starred: $starred, coverArt: $coverArt, smallImage: $smallImage, largeImage: $largeImage)';
|
return 'Artist(id: $id, name: $name, starred: $starred, coverArt: $coverArt)';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -251,7 +247,7 @@ abstract mixin class _$ArtistCopyWith<$Res> implements $ArtistCopyWith<$Res> {
|
|||||||
factory _$ArtistCopyWith(_Artist value, $Res Function(_Artist) _then) = __$ArtistCopyWithImpl;
|
factory _$ArtistCopyWith(_Artist value, $Res Function(_Artist) _then) = __$ArtistCopyWithImpl;
|
||||||
@override @useResult
|
@override @useResult
|
||||||
$Res call({
|
$Res call({
|
||||||
String id, String name, DateTime? starred, String? coverArt, Uri? smallImage, Uri? largeImage
|
String id, String name, DateTime? starred, String? coverArt
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@ -268,15 +264,13 @@ class __$ArtistCopyWithImpl<$Res>
|
|||||||
|
|
||||||
/// Create a copy of Artist
|
/// Create a copy of Artist
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? name = null,Object? starred = freezed,Object? coverArt = freezed,Object? smallImage = freezed,Object? largeImage = freezed,}) {
|
@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? name = null,Object? starred = freezed,Object? coverArt = freezed,}) {
|
||||||
return _then(_Artist(
|
return _then(_Artist(
|
||||||
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
|
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
|
||||||
as String,name: null == name ? _self.name : name // ignore: cast_nullable_to_non_nullable
|
as String,name: null == name ? _self.name : name // ignore: cast_nullable_to_non_nullable
|
||||||
as String,starred: freezed == starred ? _self.starred : starred // ignore: cast_nullable_to_non_nullable
|
as String,starred: freezed == starred ? _self.starred : starred // ignore: cast_nullable_to_non_nullable
|
||||||
as DateTime?,coverArt: freezed == coverArt ? _self.coverArt : coverArt // ignore: cast_nullable_to_non_nullable
|
as DateTime?,coverArt: freezed == coverArt ? _self.coverArt : coverArt // ignore: cast_nullable_to_non_nullable
|
||||||
as String?,smallImage: freezed == smallImage ? _self.smallImage : smallImage // ignore: cast_nullable_to_non_nullable
|
as String?,
|
||||||
as Uri?,largeImage: freezed == largeImage ? _self.largeImage : largeImage // ignore: cast_nullable_to_non_nullable
|
|
||||||
as Uri?,
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -2,21 +2,11 @@ import 'package:xml/xml.dart';
|
|||||||
|
|
||||||
import '../models.dart';
|
import '../models.dart';
|
||||||
|
|
||||||
Uri? uriOrNullParse(String? value) {
|
Artist mapArtist(XmlElement e) => Artist(
|
||||||
if (value == null || value.trim().isEmpty) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Uri.tryParse(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
Artist mapArtist(XmlElement e, XmlElement? info) => Artist(
|
|
||||||
id: e.getAttribute('id')!,
|
id: e.getAttribute('id')!,
|
||||||
name: e.getAttribute('name')!,
|
name: e.getAttribute('name')!,
|
||||||
starred: DateTime.tryParse(e.getAttribute('starred').toString()),
|
starred: DateTime.tryParse(e.getAttribute('starred').toString()),
|
||||||
coverArt: e.getAttribute('coverArt'),
|
coverArt: e.getAttribute('coverArt'),
|
||||||
smallImage: uriOrNullParse(info?.getElement('smallImageUrl')?.innerText),
|
|
||||||
largeImage: uriOrNullParse(info?.getElement('largeImageUrl')?.innerText),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
Album mapAlbum(
|
Album mapAlbum(
|
||||||
|
|||||||
@ -42,19 +42,13 @@ class SubsonicSource implements MusicSource {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Stream<Artist> allArtists() async* {
|
Stream<Artist> allArtists() async* {
|
||||||
final getArtistsRes = await _pool.withResource(
|
final res = await _pool.withResource(
|
||||||
() => client.get('getArtists'),
|
() => client.get('getArtists'),
|
||||||
);
|
);
|
||||||
|
|
||||||
yield* _pool.forEach(getArtistsRes.xml.findAllElements('artist'), (
|
yield* Stream.fromIterable(
|
||||||
artist,
|
res.xml.findAllElements('artist').map(mapArtist),
|
||||||
) async {
|
);
|
||||||
final res = await client.get('getArtistInfo2', {
|
|
||||||
'id': artist.getAttribute('id')!,
|
|
||||||
});
|
|
||||||
|
|
||||||
return mapArtist(artist, res.xml.getElement('artistInfo2'));
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import 'package:subtracks/database/database.dart';
|
import 'package:subtracks/database/database.dart';
|
||||||
import 'package:subtracks/services/sync_services.dart';
|
import 'package:subtracks/services/sync_service.dart';
|
||||||
import 'package:subtracks/sources/subsonic/source.dart';
|
import 'package:subtracks/sources/subsonic/source.dart';
|
||||||
import 'package:test/test.dart';
|
import 'package:test/test.dart';
|
||||||
|
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import 'package:test/test.dart';
|
|||||||
import '../util/subsonic.dart';
|
import '../util/subsonic.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
groupByTestServer((client) {
|
groupByTestServer((server, client) {
|
||||||
late SubsonicSource source;
|
late SubsonicSource source;
|
||||||
|
|
||||||
setUp(() async {
|
setUp(() async {
|
||||||
@ -29,7 +29,7 @@ void main() {
|
|||||||
expect(kosmo.created.compareTo(DateTime.now()), lessThan(0));
|
expect(kosmo.created.compareTo(DateTime.now()), lessThan(0));
|
||||||
expect(kosmo.coverArt?.length, greaterThan(0));
|
expect(kosmo.coverArt?.length, greaterThan(0));
|
||||||
expect(kosmo.year, equals(2006));
|
expect(kosmo.year, equals(2006));
|
||||||
expect(kosmo.starred, isNull);
|
expect(kosmo.starred?.compareTo(DateTime.now()), lessThan(0));
|
||||||
expect(kosmo.genre, equals('Electronic'));
|
expect(kosmo.genre, equals('Electronic'));
|
||||||
|
|
||||||
final retro = items.firstWhere(
|
final retro = items.firstWhere(
|
||||||
@ -39,6 +39,9 @@ void main() {
|
|||||||
(a) => a.name == "I Don't Know What I'm Doing",
|
(a) => a.name == "I Don't Know What I'm Doing",
|
||||||
);
|
);
|
||||||
|
|
||||||
|
expect(retro.starred, isNull);
|
||||||
|
expect(dunno.starred, isNull);
|
||||||
|
|
||||||
expect(kosmo.recentRank, equals(0));
|
expect(kosmo.recentRank, equals(0));
|
||||||
expect(kosmo.frequentRank, equals(1));
|
expect(kosmo.frequentRank, equals(1));
|
||||||
|
|
||||||
@ -53,6 +56,19 @@ void main() {
|
|||||||
final items = await source.allArtists().toList();
|
final items = await source.allArtists().toList();
|
||||||
|
|
||||||
expect(items.length, equals(2));
|
expect(items.length, equals(2));
|
||||||
|
|
||||||
|
final brad = items.firstWhere((a) => a.name == 'Brad Sucks');
|
||||||
|
|
||||||
|
expect(brad.id.length, greaterThan(0));
|
||||||
|
expect(brad.starred, isNull);
|
||||||
|
|
||||||
|
if (![Servers.gonic].contains(server)) {
|
||||||
|
expect(brad.coverArt?.length, greaterThan(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
final ugress = items.firstWhere((a) => a.name == 'Ugress');
|
||||||
|
|
||||||
|
expect(ugress.starred?.compareTo(DateTime.now()), lessThan(0));
|
||||||
});
|
});
|
||||||
|
|
||||||
test('allSongs', () async {
|
test('allSongs', () async {
|
||||||
|
|||||||
@ -23,12 +23,14 @@ Map<Servers, SubsonicClient> testServerClients() => {
|
|||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
void groupByTestServer(void Function(SubsonicClient client) callback) {
|
void groupByTestServer(
|
||||||
|
void Function(Servers server, SubsonicClient client) callback,
|
||||||
|
) {
|
||||||
final clients = testServerClients();
|
final clients = testServerClients();
|
||||||
|
|
||||||
for (final MapEntry(key: server, value: client) in clients.entries) {
|
for (final MapEntry(key: server, value: client) in clients.entries) {
|
||||||
group(server.name, () {
|
group(server.name, () {
|
||||||
callback(client);
|
callback(server, client);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user