Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions packages/platform_playlist/lib/platform_playlist.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ export 'src/smart_playlist_evaluator.dart';
export 'src/channel_name_normalizer.dart';
export 'src/canonical_channel_matcher.dart';
export 'src/favorite_channel_remapper.dart';
export 'src/persistence/canonical_channel_database.dart';
export 'src/persistence/canonical_channel_repository.dart';
export 'src/xtream/xtream_client.dart';
export 'src/xtream/xtream_content_source.dart';
export 'src/xtream/xtream_epg_repository.dart';
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import 'dart:io';

import 'package:drift/drift.dart';
import 'package:drift/native.dart';
import 'package:path/path.dart' as p;
import 'package:path_provider/path_provider.dart';

part 'canonical_channel_database.g.dart';

/// Canonical channel identities (CV-017): a normalized, user-facing channel
/// concept that provider aliases point to when confidently matched.
class CanonicalChannels extends Table {
TextColumn get canonicalChannelId => text()();
TextColumn get displayName => text()();
TextColumn get normalizedName => text()();
TextColumn get language => text().nullable()();
TextColumn get country => text().nullable()();
TextColumn get category => text().nullable()();
TextColumn get logoFingerprint => text().nullable()();
DateTimeColumn get createdAt => dateTime()();
DateTimeColumn get updatedAt => dateTime()();

@override
Set<Column> get primaryKey => {canonicalChannelId};
}

/// A single provider's channel entry, optionally pointing at a canonical
/// identity once matched with sufficient confidence (CV-017). Kept separate
/// from [CanonicalChannels] per the issue's "store provider channel aliases
/// separately from user-facing canonical identities" framework rule.
@DataClassName('ProviderChannelAlias')
class ProviderChannelAliases extends Table {
TextColumn get sourceId => text()();
TextColumn get providerChannelId => text()();
TextColumn get canonicalChannelId => text().nullable()();
TextColumn get providerName => text()();
TextColumn get normalizedProviderName => text()();
IntColumn get tvgId => integer().nullable()();
TextColumn get groupTitle => text().nullable()();
TextColumn get streamUrlFingerprint => text()();
TextColumn get resolution => text().nullable()();
BoolColumn get isVod => boolean().withDefault(const Constant(false))();
BoolColumn get isRadio => boolean().withDefault(const Constant(false))();
BoolColumn get isAdult => boolean().withDefault(const Constant(false))();
// Stored as the ChannelMatchConfidence enum's name ('high'/'medium'/
// 'low'/'none'), not a raw double -- keeps the persisted value tied to
// CanonicalChannelMatcher's actual confidence tiers instead of an
// arbitrary score that could drift out of sync with matcher logic.
TextColumn get matchConfidence => text().nullable()();

@override
Set<Column> get primaryKey => {sourceId, providerChannelId};
}

@DriftDatabase(tables: [CanonicalChannels, ProviderChannelAliases])
class CanonicalChannelDatabase extends _$CanonicalChannelDatabase {
CanonicalChannelDatabase(super.executor);

/// Opens the real on-device database file. Not used in tests -- see
/// [CanonicalChannelDatabase.forTesting] for an in-memory instance.
factory CanonicalChannelDatabase.open() {
return CanonicalChannelDatabase(
LazyDatabase(() async {
final dir = await getApplicationSupportDirectory();
final file = File(p.join(dir.path, 'canonical_channels.sqlite'));
return NativeDatabase.createInBackground(file);
}),
);
}

/// An in-memory database for tests -- never touches disk.
factory CanonicalChannelDatabase.forTesting() {
return CanonicalChannelDatabase(NativeDatabase.memory());
}

@override
int get schemaVersion => 1;
}
Loading
Loading