Skip to content

Commit

Permalink
core: properly extract & use embedded rating/moods along with app-spe…
Browse files Browse the repository at this point in the history
…cific rating/moods

and allow editing
- editing app-related stats now edits the tags too. and vice versa
ref: #294
  • Loading branch information
MSOB7YY committed Aug 17, 2024
1 parent c00c162 commit f7cc288
Show file tree
Hide file tree
Showing 15 changed files with 945 additions and 722 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,7 @@ public class FAudioTagger : FlutterPlugin, MethodCallHandler {
metadata["artworkLength"] = artworkBytes.size
} catch (_: Exception) {}
} else {
metadata["arwork"] = artworkBytes
metadata["artwork"] = artworkBytes
metadata["artworkLength"] = artworkBytes.size
}
}
Expand Down
21 changes: 19 additions & 2 deletions lib/class/faudiomodel.dart
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ class FTags {
final String? country;
final String? recordLabel;

final double? ratingPercentage;

const FTags({
required this.path,
required this.artwork,
Expand Down Expand Up @@ -96,6 +98,7 @@ class FTags {
this.tempo,
this.country,
this.recordLabel,
this.ratingPercentage,
});

static String? _listToString(List? list) {
Expand All @@ -104,6 +107,17 @@ class FTags {
return list.join('; ');
}

static double? ratingUnsignedIntToPercentage(String? rating) {
if (rating == null) return null;
final unsignedInt = int.tryParse(rating);
if (unsignedInt == null) return null;
return unsignedInt / 255;
}

static int ratingPercentageToUnsignedInt(double ratingPercentage) {
return (ratingPercentage * 255).round();
}

// -- upper cased are the ones extracted manually.
factory FTags.fromMap(Map<String, dynamic> map) {
var lyricsList = map["lyrics"] as List?;
Expand All @@ -115,6 +129,8 @@ class FTags {
];
}

final ratingString = map["rating"] ?? map["RATING"];

return FTags(
path: map["path"],
artwork: FArtwork.fromMap(map),
Expand All @@ -136,12 +152,13 @@ class FTags {
djmixer: _listToString(map["djmixer"]) ?? map["DJMIXER"],
mixer: _listToString(map["mixer"]) ?? map["MIXER"],
mood: _listToString(map["mood"]) ?? map["MOOD"],
rating: map["rating"] ?? map["RATING"],
rating: ratingString,
remixer: _listToString(map["remixer"]) ?? map["REMIXER"],
tags: _listToString(map["tags"]) ?? map["TAGS"],
tempo: _listToString(map["tempo"]) ?? map["TEMPO"],
country: _listToString(map["country"]) ?? map["COUNTRY"],
recordLabel: _listToString(map["recordLabel"]) ?? map["RECORDLABEL"] ?? map["label"] ?? map["LABEL"],
ratingPercentage: ratingUnsignedIntToPercentage(ratingString),
);
}

Expand All @@ -166,7 +183,7 @@ class FTags {
"djmixer": djmixer,
"mixer": mixer,
"mood": mood,
"rating": rating,
"rating": ratingPercentage != null ? "${ratingPercentageToUnsignedInt(ratingPercentage!)}" : rating,
"remixer": remixer,
"tags": tags,
"tempo": tempo,
Expand Down
47 changes: 46 additions & 1 deletion lib/class/track.dart
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,9 @@ class TrackExtended {
final String language;
final String lyrics;
final String label;
final double rating;
final String? originalTags;
final List<String> tagsList;

const TrackExtended({
required this.title,
Expand Down Expand Up @@ -222,6 +225,9 @@ class TrackExtended {
required this.language,
required this.lyrics,
required this.label,
required this.rating,
required this.originalTags,
required this.tagsList,
});

static String _padInt(int val) => val.toString().padLeft(2, '0');
Expand Down Expand Up @@ -280,6 +286,12 @@ class TrackExtended {
language: json['language'] ?? '',
lyrics: json['lyrics'] ?? '',
label: json['label'] ?? '',
rating: json['rating'] ?? 0.0,
originalTags: json['originalTags'],
tagsList: Indexer.splitGeneral(
json['originalTags'],
config: genresSplitConfig,
),
);
}

Expand Down Expand Up @@ -308,6 +320,8 @@ class TrackExtended {
'language': language,
'lyrics': lyrics,
'label': label,
'rating': rating,
'originalTags': originalTags,
};
}

Expand Down Expand Up @@ -399,6 +413,9 @@ extension TrackExtUtils on TrackExtended {
language: tag.language ?? language,
lyrics: tag.lyrics ?? lyrics,
label: tag.recordLabel ?? label,
rating: tag.ratingPercentage ?? rating,
originalTags: tag.tags ?? originalTags,
tagsList: tag.tags != null ? [tag.tags!] : tagsList,

// -- uneditable fields
bitrate: bitrate,
Expand Down Expand Up @@ -440,6 +457,9 @@ extension TrackExtUtils on TrackExtended {
String? language,
String? lyrics,
String? label,
double? rating,
String? originalTags,
List<String>? tagsList,
}) {
return TrackExtended(
title: title ?? this.title,
Expand Down Expand Up @@ -468,6 +488,9 @@ extension TrackExtUtils on TrackExtended {
language: language ?? this.language,
lyrics: lyrics ?? this.lyrics,
label: label ?? this.label,
rating: rating ?? this.rating,
originalTags: originalTags ?? this.originalTags,
tagsList: tagsList ?? this.tagsList,
);
}
}
Expand Down Expand Up @@ -511,7 +534,29 @@ extension TrackUtils on Track {
String get language => toTrackExt().language;
String get lyrics => toTrackExt().lyrics;
String get label => toTrackExt().label;
TrackStats get stats => Indexer.inst.trackStatsMap[this] ?? TrackStats(kDummyTrack, 0, [], [], 0);

int? get lastPlayedPositionInMs => _stats?.lastPositionInMs;
TrackStats? get _stats => Indexer.inst.trackStatsMap[this];
int get effectiveRating {
int? r = _stats?.rating;
if (r != null && r > 0) return r;
var percentageRatingEmbedded = toTrackExt().rating;
return (percentageRatingEmbedded * 100).round();
}

List<String> get effectiveMoods {
List<String>? m = _stats?.moods;
if (m != null && m.isNotEmpty) return m;
var moodsEmbedded = toTrackExt().moodList;
return moodsEmbedded;
}

List<String> get effectiveTags {
List<String>? s = _stats?.tags;
if (s != null && s.isNotEmpty) return s;
var tagsEmbedded = toTrackExt().tagsList;
return tagsEmbedded;
}

String get filename => path.getFilename;
String get filenameWOExt => path.getFilenameWOExt;
Expand Down
6 changes: 6 additions & 0 deletions lib/controller/ffmpeg_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,10 @@ class FFMPEGTagField {
static const String recordLabel = 'LABEL';
static const String country = 'Country';

// -- NOT TESTED
static const String rating = 'rating';
static const String tags = 'tags';

static const List<String> values = <String>[
title,
artist,
Expand All @@ -446,6 +450,8 @@ class FFMPEGTagField {
language,
recordLabel,
country,
rating,
tags,
];
}

Expand Down
51 changes: 43 additions & 8 deletions lib/controller/indexer_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -465,6 +465,9 @@ class Indexer {
language: '',
lyrics: '',
label: '',
rating: 0.0,
originalTags: null,
tagsList: [],
);
if (!trackInfo.hasError) {
int durationInSeconds = trackInfo.length ?? 0;
Expand Down Expand Up @@ -495,6 +498,10 @@ class Indexer {
config: splittersConfigs.generalConfig,
);

// -- Split Tags
final tagsEmbedded = splitGeneral(
tags.tags,
config: splittersConfigs.generalConfig,
);

String? trimOrNull(String? value) => value == null ? value : value.trimAll();
Expand Down Expand Up @@ -523,6 +530,9 @@ class Indexer {
discNo: tags.discNumber.getIntValue(),
language: tags.language,
lyrics: tags.lyrics,
label: tags.recordLabel,
rating: tags.ratingPercentage,
tagsList: tagsEmbedded,
);

// ----- if the title || artist weren't found in the tag fields
Expand Down Expand Up @@ -941,22 +951,38 @@ class Indexer {
}
}

static List<String> splitByCommaList(String listText) {
final moodsFinalLookup = <String, bool>{};
final moodsPre = listText.split(',');
moodsPre.loop((m) {
if (m.isNotEmpty && m != ' ') {
final cleaned = m.trimAll();
moodsFinalLookup[cleaned] ??= true;
}
});
return moodsFinalLookup.keys.toList();
}

/// Returns new [TrackStats].
Future<TrackStats> updateTrackStats(
Track track, {
int? rating,
List<String>? tags,
List<String>? moods,
String? ratingString,
String? tagsString,
String? moodsString,
int? lastPositionInMs,
}) async {
if (rating != null || tags != null || moods != null) {
if (ratingString != null || tagsString != null || moodsString != null) {
TrackTileManager.onTrackItemPropChange();
}

rating ??= track.stats.rating;
tags ??= track.stats.tags;
moods ??= track.stats.moods;
lastPositionInMs ??= track.stats.lastPositionInMs;
final rating = ratingString != null
? ratingString.isEmpty
? 0
: int.tryParse(ratingString) ?? track.effectiveRating
: track.effectiveRating;
final tags = tagsString != null ? splitByCommaList(tagsString) : track.effectiveTags;
final moods = moodsString != null ? splitByCommaList(moodsString) : track.effectiveMoods;
lastPositionInMs ??= track.lastPlayedPositionInMs ?? 0;
final newStats = TrackStats(track, rating.clamp(0, 100), tags, moods, lastPositionInMs);
trackStatsMap[track] = newStats;

Expand Down Expand Up @@ -1222,6 +1248,12 @@ class Indexer {
mood,
config: generalSplitConfig,
);
final tag = map['tag'] ?? map['tags'];
final tags = tag == null
? <String>[]
: Indexer.splitGeneral(
tag,
config: generalSplitConfig,
);
final bitrate = map['bitrate'] as int?;
final disc = map['disc_number'] as int?;
Expand Down Expand Up @@ -1253,6 +1285,9 @@ class Indexer {
language: '',
lyrics: '',
label: '',
rating: 0.0,
originalTags: tag,
tagsList: tags,
);
tracks.add((trext, e.id));
_backupMediaStoreIDS[trext.pathToImage] = (trext.toTrack(), e.id);
Expand Down
4 changes: 2 additions & 2 deletions lib/controller/search_sort_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ class SearchSortController {
SortType.duration: (e) => e.duration,
SortType.sampleRate: (e) => e.sampleRate,
SortType.size: (e) => e.size,
SortType.rating: (e) => e.stats.rating,
SortType.rating: (e) => e.effectiveRating,
SortType.mostPlayed: (e) => HistoryController.inst.topTracksMapListens[e]?.length ?? 0,
SortType.latestPlayed: (e) => HistoryController.inst.topTracksMapListens[e]?.lastOrNull ?? 0,
};
Expand Down Expand Up @@ -714,7 +714,7 @@ class SearchSortController {
sortThis((e) => e.size);
break;
case SortType.rating:
sortThis((e) => e.stats.rating);
sortThis((e) => e.effectiveRating);
break;
case SortType.shuffle:
list.shuffle();
Expand Down
Loading

0 comments on commit f7cc288

Please sign in to comment.