mirror of
https://github.com/gabehf/Fladder.git
synced 2026-03-07 21:48:14 -08:00
208 lines
7.7 KiB
Dart
208 lines
7.7 KiB
Dart
import 'dart:convert';
|
|
import 'dart:io';
|
|
|
|
import 'package:drift/drift.dart';
|
|
import 'package:drift_flutter/drift_flutter.dart';
|
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
import 'package:path/path.dart' as p;
|
|
import 'package:path_provider/path_provider.dart';
|
|
|
|
import 'package:fladder/models/item_base_model.dart';
|
|
import 'package:fladder/models/items/chapters_model.dart';
|
|
import 'package:fladder/models/items/images_models.dart';
|
|
import 'package:fladder/models/items/item_shared_models.dart';
|
|
import 'package:fladder/models/items/media_segments_model.dart';
|
|
import 'package:fladder/models/items/media_streams_model.dart';
|
|
import 'package:fladder/models/items/trick_play_model.dart';
|
|
import 'package:fladder/models/syncing/sync_item.dart';
|
|
import 'package:fladder/providers/user_provider.dart';
|
|
|
|
part 'database_item.g.dart';
|
|
|
|
const _databseName = 'syncedDatabase';
|
|
|
|
@TableIndex(name: 'database_id', columns: {#userId, #id})
|
|
class DatabaseItems extends Table {
|
|
TextColumn get userId => text().withLength(min: 1)();
|
|
TextColumn get id => text().withLength(min: 1)();
|
|
BoolColumn get syncing => boolean().withDefault(const Constant(false))();
|
|
TextColumn get sortName => text().nullable()();
|
|
TextColumn get parentId => text().nullable()();
|
|
TextColumn get path => text().nullable()();
|
|
IntColumn get fileSize => integer().nullable()();
|
|
TextColumn get videoFileName => text().nullable()();
|
|
TextColumn get trickPlayModel => text().nullable()();
|
|
TextColumn get mediaSegments => text().nullable()();
|
|
TextColumn get images => text().nullable()();
|
|
TextColumn get chapters => text().nullable()();
|
|
TextColumn get subtitles => text().nullable()();
|
|
BoolColumn get unSyncedData => boolean().withDefault(const Constant(false))();
|
|
TextColumn get userData => text().nullable()();
|
|
|
|
@override
|
|
Set<Column<Object>> get primaryKey => {userId, id};
|
|
}
|
|
|
|
@DriftDatabase(tables: [DatabaseItems])
|
|
class AppDatabase extends _$AppDatabase {
|
|
AppDatabase(this.ref, [QueryExecutor? executor]) : super(executor ?? _openConnection());
|
|
|
|
final Ref ref;
|
|
|
|
String get userId => ref.read(userProvider.select((value) => value?.id ?? ""));
|
|
|
|
@override
|
|
int get schemaVersion => 1;
|
|
|
|
Future<void> clearDatabase() async {
|
|
final dbPath = await getApplicationSupportDirectory();
|
|
final dbFile = File(p.join(dbPath.path, '$_databseName.sqlite'));
|
|
|
|
if (await dbFile.exists()) {
|
|
await dbFile.delete(recursive: true);
|
|
}
|
|
}
|
|
|
|
Selectable<SyncedItem> getItem(String id) =>
|
|
(select(databaseItems)..where((tbl) => tbl.id.equals(id) & tbl.userId.equals(userId))).map(databaseConverter);
|
|
|
|
Selectable<SyncedItem> getParent(String id) =>
|
|
(select(databaseItems)..where((tbl) => tbl.parentId.equals(id) & tbl.userId.equals(userId)))
|
|
.map(databaseConverter);
|
|
|
|
Selectable<SyncedItem> get getParentItems =>
|
|
((select(databaseItems)..where((tbl) => (tbl.parentId.isNull() & tbl.userId.equals(userId))))
|
|
..orderBy([(t) => OrderingTerm(expression: t.sortName)]))
|
|
.map(databaseConverter);
|
|
|
|
Selectable<SyncedItem> get getAllItems => ((select(databaseItems)..where((tbl) => tbl.userId.equals(userId)))
|
|
..orderBy([(t) => OrderingTerm(expression: t.sortName)]))
|
|
.map(databaseConverter);
|
|
|
|
Selectable<SyncedItem> getChildren(String parentId) =>
|
|
((select(databaseItems)..where((tbl) => (tbl.parentId.equals(parentId) & tbl.userId.equals(userId))))
|
|
..orderBy([(t) => OrderingTerm(expression: t.sortName)]))
|
|
.map(databaseConverter);
|
|
|
|
Future<int> insertItem(SyncedItem item) async {
|
|
final itemExists = await getItem(item.id).getSingleOrNull();
|
|
if (itemExists != null) {
|
|
return (update(databaseItems)..where((tbl) => tbl.id.equals(item.id) & tbl.userId.equals(userId)))
|
|
.write(toDataBaseItem(item));
|
|
} else {
|
|
return into(databaseItems).insert(toDataBaseItem(item));
|
|
}
|
|
}
|
|
|
|
Future<List<SyncedItem>> getNestedChildren(SyncedItem root) async {
|
|
final itemType = root.createItemModel(ref)?.type;
|
|
|
|
if (itemType == null) return [];
|
|
|
|
final int maxDepth = switch (itemType) {
|
|
FladderItemType.season => 1,
|
|
FladderItemType.series => 2,
|
|
_ => 0,
|
|
};
|
|
|
|
final all = <SyncedItem>[];
|
|
List<SyncedItem> toProcess = [root];
|
|
|
|
if (maxDepth == 0) {
|
|
return [];
|
|
}
|
|
|
|
for (var i = 0; i < maxDepth; i++) {
|
|
final futures = toProcess.map((item) => getChildren(item.id).get());
|
|
final resultsList = await Future.wait(futures);
|
|
|
|
final children = resultsList.expand((r) => r).toList();
|
|
|
|
if (children.isEmpty) break;
|
|
|
|
all.addAll(children);
|
|
toProcess = children;
|
|
}
|
|
|
|
return all;
|
|
}
|
|
|
|
Future<void> insertMultipleEntries(List<SyncedItem> items) async {
|
|
await batch((batch) {
|
|
batch.insertAll(
|
|
databaseItems,
|
|
items.map(toDataBaseItem),
|
|
mode: InsertMode.insertOrReplace,
|
|
);
|
|
});
|
|
}
|
|
|
|
Future<void> deleteAllItems(List<SyncedItem> items) async {
|
|
await batch((batch) {
|
|
batch.deleteWhere(databaseItems, (tbl) => tbl.id.isIn(items.map((e) => e.id)) & tbl.userId.equals(userId));
|
|
});
|
|
}
|
|
|
|
DatabaseItemsCompanion toDataBaseItem(SyncedItem item) {
|
|
return DatabaseItemsCompanion(
|
|
id: Value(item.id),
|
|
parentId: Value(item.parentId),
|
|
syncing: Value(item.syncing),
|
|
userId: Value(userId),
|
|
path: Value(item.path),
|
|
fileSize: Value(item.fileSize),
|
|
sortName: Value(item.sortName),
|
|
videoFileName: Value(item.videoFileName),
|
|
trickPlayModel: Value(item.fTrickPlayModel != null ? jsonEncode(item.fTrickPlayModel?.toJson()) : null),
|
|
mediaSegments: Value(item.mediaSegments != null ? jsonEncode(item.mediaSegments?.toJson()) : null),
|
|
images: Value(item.fImages != null ? jsonEncode(item.fImages?.toJson()) : null),
|
|
chapters: Value(jsonEncode(item.fChapters.map((e) => e.toJson()).toList())),
|
|
subtitles: Value(jsonEncode(item.subtitles.map((e) => e.toJson()).toList())),
|
|
userData: Value(item.userData != null ? jsonEncode(item.userData?.toJson()) : null),
|
|
unSyncedData: Value(item.unSyncedData),
|
|
);
|
|
}
|
|
|
|
SyncedItem databaseConverter(DatabaseItem dataItem) {
|
|
final syncedItem = SyncedItem(
|
|
id: dataItem.id,
|
|
userId: dataItem.userId,
|
|
parentId: dataItem.parentId,
|
|
sortName: dataItem.sortName,
|
|
syncing: dataItem.syncing,
|
|
path: dataItem.path,
|
|
fileSize: dataItem.fileSize,
|
|
videoFileName: dataItem.videoFileName,
|
|
fTrickPlayModel:
|
|
dataItem.trickPlayModel != null ? TrickPlayModel.fromJson(jsonDecode(dataItem.trickPlayModel!)) : null,
|
|
mediaSegments:
|
|
dataItem.mediaSegments != null ? MediaSegmentsModel.fromJson(jsonDecode(dataItem.mediaSegments!)) : null,
|
|
fImages: dataItem.images != null ? ImagesData.fromJson(jsonDecode(dataItem.images!)) : null,
|
|
fChapters: (dataItem.chapters != null && dataItem.chapters!.isNotEmpty)
|
|
? (jsonDecode(dataItem.chapters!) as List).map((e) => Chapter.fromJson(e)).toList()
|
|
: [],
|
|
subtitles: (dataItem.subtitles != null && dataItem.subtitles!.isNotEmpty)
|
|
? (jsonDecode(dataItem.subtitles!) as List).map((e) => SubStreamModel.fromJson(e)).toList()
|
|
: [],
|
|
userData: dataItem.userData != null ? UserData.fromJson(jsonDecode(dataItem.userData!)) : null,
|
|
unSyncedData: dataItem.unSyncedData,
|
|
);
|
|
|
|
return syncedItem.copyWith(
|
|
itemModel: syncedItem.createItemModel(ref),
|
|
);
|
|
}
|
|
|
|
static QueryExecutor _openConnection() {
|
|
return driftDatabase(
|
|
name: _databseName,
|
|
native: const DriftNativeOptions(
|
|
databaseDirectory: getApplicationSupportDirectory,
|
|
),
|
|
web: DriftWebOptions(
|
|
sqlite3Wasm: Uri.parse('sqlite3.wasm'),
|
|
driftWorker: Uri.parse('drift_worker.dart.js'),
|
|
),
|
|
);
|
|
}
|
|
}
|