mirror of
https://github.com/twonlyapp/twonly-app.git
synced 2026-07-18 01:14:07 +00:00
222 lines
6.5 KiB
Dart
222 lines
6.5 KiB
Dart
import 'package:drift/drift.dart';
|
|
import 'package:hashlib/random.dart';
|
|
import 'package:twonly/src/database/tables/mediafiles.table.dart';
|
|
import 'package:twonly/src/database/tables/messages.table.dart';
|
|
import 'package:twonly/src/database/twonly.db.dart';
|
|
import 'package:twonly/src/utils/log.dart';
|
|
|
|
part 'mediafiles.dao.g.dart';
|
|
|
|
@DriftAccessor(tables: [MediaFiles, Messages])
|
|
class MediaFilesDao extends DatabaseAccessor<TwonlyDB>
|
|
with _$MediaFilesDaoMixin {
|
|
// this constructor is required so that the main database can create an instance
|
|
// of this object.
|
|
// ignore: matching_super_parameters
|
|
MediaFilesDao(super.db);
|
|
|
|
Future<MediaFile?> insertOrUpdateMedia(MediaFilesCompanion mediaFile) async {
|
|
try {
|
|
var insertMediaFile = mediaFile;
|
|
|
|
if (insertMediaFile.mediaId == const Value.absent()) {
|
|
insertMediaFile = mediaFile.copyWith(
|
|
mediaId: Value(uuid.v7()),
|
|
);
|
|
}
|
|
|
|
await into(mediaFiles).insertOnConflictUpdate(insertMediaFile);
|
|
|
|
final mediaId = insertMediaFile.mediaId.value;
|
|
|
|
return await (select(
|
|
mediaFiles,
|
|
)..where((t) => t.mediaId.equals(mediaId))).getSingle();
|
|
} catch (e) {
|
|
Log.error('Could not insert media file: $e');
|
|
return null;
|
|
}
|
|
}
|
|
|
|
Future<void> deleteMediaFile(String mediaId) async {
|
|
await (delete(mediaFiles)..where(
|
|
(t) => t.mediaId.equals(mediaId),
|
|
))
|
|
.go();
|
|
}
|
|
|
|
Future<void> updateMedia(
|
|
String mediaId,
|
|
MediaFilesCompanion updates,
|
|
) async {
|
|
await (update(
|
|
mediaFiles,
|
|
)..where((c) => c.mediaId.equals(mediaId))).write(updates);
|
|
}
|
|
|
|
Future<void> updateAllMediaFiles(
|
|
MediaFilesCompanion updates,
|
|
) async {
|
|
await update(mediaFiles).write(updates);
|
|
}
|
|
|
|
Future<MediaFile?> getMediaFileById(String mediaId) async {
|
|
return (select(
|
|
mediaFiles,
|
|
)..where((t) => t.mediaId.equals(mediaId))).getSingleOrNull();
|
|
}
|
|
|
|
Future<List<MediaFile>> getMediaFilesByIds(List<String> mediaIds) async {
|
|
return (select(mediaFiles)..where((t) => t.mediaId.isIn(mediaIds))).get();
|
|
}
|
|
|
|
Future<MediaFile?> getDraftMediaFile() async {
|
|
final medias = await (select(
|
|
mediaFiles,
|
|
)..where((t) => t.isDraftMedia.equals(true))).get();
|
|
if (medias.isEmpty) {
|
|
return null;
|
|
}
|
|
return medias.first;
|
|
}
|
|
|
|
Stream<MediaFile?> watchMedia(String mediaId) {
|
|
return (select(
|
|
mediaFiles,
|
|
)..where((t) => t.mediaId.equals(mediaId))).watchSingleOrNull();
|
|
}
|
|
|
|
Future<void> resetPendingDownloadState() async {
|
|
await (update(mediaFiles)..where(
|
|
(c) => c.downloadState.equals(
|
|
DownloadState.downloading.name,
|
|
),
|
|
))
|
|
.write(
|
|
const MediaFilesCompanion(
|
|
downloadState: Value(DownloadState.pending),
|
|
),
|
|
);
|
|
}
|
|
|
|
Future<List<MediaFile>> getAllMediaFilesPendingDownload() async {
|
|
return (select(mediaFiles)..where(
|
|
(t) =>
|
|
t.downloadState.equals(DownloadState.pending.name) |
|
|
t.downloadState.equals(DownloadState.downloading.name),
|
|
))
|
|
.get();
|
|
}
|
|
|
|
Future<List<MediaFile>> getAllMediaFilesReuploadRequested() async {
|
|
return (select(mediaFiles)..where(
|
|
(t) => t.downloadState.equals(DownloadState.reuploadRequested.name),
|
|
))
|
|
.get();
|
|
}
|
|
|
|
Future<List<MediaFile>> getAllMediaFilesPendingMigration() async {
|
|
return (select(mediaFiles)..where(
|
|
(t) =>
|
|
t.stored.equals(true) &
|
|
(t.storedFileHash.isNull() |
|
|
t.hasCropAnalyzed.equals(false) |
|
|
(t.hasThumbnail.equals(false) &
|
|
t.type.equals(MediaType.audio.name).not()) |
|
|
t.sizeInBytes.isNull()),
|
|
))
|
|
.get();
|
|
}
|
|
|
|
Future<List<MediaFile>> getAllMediaFilesPendingUpload() async {
|
|
return (select(mediaFiles)..where(
|
|
(t) =>
|
|
(t.uploadState.equals(UploadState.initialized.name) |
|
|
t.uploadState.equals(UploadState.uploadLimitReached.name) |
|
|
t.uploadState.equals(UploadState.uploading.name) |
|
|
t.uploadState.equals(UploadState.preprocessing.name)),
|
|
))
|
|
.get();
|
|
}
|
|
|
|
Stream<List<MediaFile>> watchAllStoredMediaFiles() {
|
|
final query =
|
|
(select(mediaFiles)..where((t) => t.stored.equals(true))).join([])
|
|
..groupBy([
|
|
const CustomExpression<Object>(
|
|
'COALESCE(stored_file_hash, media_id)',
|
|
),
|
|
]);
|
|
return query.map((row) => row.readTable(mediaFiles)).watch();
|
|
}
|
|
|
|
Stream<List<MediaFile>> watchNewestMediaFiles() {
|
|
return (select(mediaFiles)
|
|
..orderBy([(t) => OrderingTerm.desc(t.createdAt)])
|
|
..limit(100))
|
|
.watch();
|
|
}
|
|
|
|
Stream<List<MediaFile>> watchMediaFilesForGroup(String groupId) {
|
|
final query = select(mediaFiles).join([
|
|
innerJoin(
|
|
db.messages,
|
|
db.messages.mediaId.equalsExp(mediaFiles.mediaId),
|
|
useColumns: false,
|
|
),
|
|
])..where(db.messages.groupId.equals(groupId));
|
|
return query.map((row) => row.readTable(mediaFiles)).watch();
|
|
}
|
|
|
|
Future<void> updateAllRetransmissionUploadingState() async {
|
|
await (update(mediaFiles)..where(
|
|
(t) =>
|
|
t.uploadState.equals(UploadState.uploading.name) &
|
|
t.reuploadRequestedBy.isNotNull(),
|
|
))
|
|
.write(
|
|
const MediaFilesCompanion(
|
|
uploadState: Value(UploadState.preprocessing),
|
|
),
|
|
);
|
|
}
|
|
|
|
Future<List<String>> getMessageIdsByMediaHash(
|
|
Uint8List hash,
|
|
int senderId,
|
|
) async {
|
|
final query =
|
|
select(db.messages).join([
|
|
innerJoin(
|
|
mediaFiles,
|
|
mediaFiles.mediaId.equalsExp(db.messages.mediaId),
|
|
),
|
|
])..where(
|
|
mediaFiles.storedFileHash.equals(hash) &
|
|
db.messages.senderId.equals(senderId) &
|
|
db.messages.openedAt.isNull(),
|
|
);
|
|
|
|
final rows = await query.get();
|
|
return rows.map((row) => row.readTable(db.messages).messageId).toList();
|
|
}
|
|
|
|
Future<List<MediaFile>> getMediaByHash(Uint8List hash) async {
|
|
final query = select(db.mediaFiles)
|
|
..where((t) => t.storedFileHash.equals(hash));
|
|
return query.get();
|
|
}
|
|
|
|
Future<Map<MediaType, int>> getStorageStats() async {
|
|
final rows = await select(mediaFiles).get();
|
|
final stats = <MediaType, int>{};
|
|
|
|
for (final row in rows) {
|
|
final type = row.type;
|
|
final size = row.sizeInBytes ?? 0;
|
|
stats[type] = (stats[type] ?? 0) + size;
|
|
}
|
|
|
|
return stats;
|
|
}
|
|
}
|