From a550d21b9aa0c257526b3786cdf491ef02efc29e Mon Sep 17 00:00:00 2001 From: Demizo <73141750+Demizo@users.noreply.github.com> Date: Thu, 1 Sep 2022 21:53:48 -0500 Subject: [PATCH 1/2] [Feature] Add Duration Match Algorithm Added duration matching option to track matching algorithms --- lib/components/Settings/Settings.dart | 6 +++++- lib/models/SpotubeTrack.dart | 2 ++ lib/provider/Playback.dart | 20 +++++++++++++++++++- 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/lib/components/Settings/Settings.dart b/lib/components/Settings/Settings.dart index 278d6ea5..3dd8e411 100644 --- a/lib/components/Settings/Settings.dart +++ b/lib/components/Settings/Settings.dart @@ -278,7 +278,11 @@ class Settings extends HookConsumerWidget { value: SpotubeTrackMatchAlgorithm.popular, ), DropdownMenuItem( - child: Text("YouTube's choice is my choice"), + child: Text("Match Song Duration"), + value: SpotubeTrackMatchAlgorithm.duration, + ), + DropdownMenuItem( + child: Text("YouTube's Top choice"), value: SpotubeTrackMatchAlgorithm.youtube, ), ], diff --git a/lib/models/SpotubeTrack.dart b/lib/models/SpotubeTrack.dart index fcdabcad..49ab716b 100644 --- a/lib/models/SpotubeTrack.dart +++ b/lib/models/SpotubeTrack.dart @@ -10,6 +10,8 @@ enum SpotubeTrackMatchAlgorithm { popular, // selects the most popular one from the author of the track authenticPopular, + // selects song that most closely matches the actual song's duration + duration, } class SpotubeTrack extends Track { diff --git a/lib/provider/Playback.dart b/lib/provider/Playback.dart index 9a2573ff..353774d4 100644 --- a/lib/provider/Playback.dart +++ b/lib/provider/Playback.dart @@ -375,7 +375,25 @@ class Playback extends PersistedChangeNotifier { } else { VideoSearchList videos = await raceMultiple(() => youtube.search.search(queryString)); - if (matchAlgorithm != SpotubeTrackMatchAlgorithm.youtube) { + + if (matchAlgorithm == SpotubeTrackMatchAlgorithm.duration) { + //Actual duration of desired song + int targetDuration = track.duration!.inSeconds; + //start with the first result + Video bestVideoMatch = videos[0]; + int minDurationDifference = + (targetDuration - videos[0].duration!.inSeconds).abs(); + //Check if any other results are closer to the actual song duration and prefer those + for (int i = 1; i < videos.length; i++) { + int durationDifference = + (targetDuration - videos[i].duration!.inSeconds).abs(); + if (durationDifference < minDurationDifference) { + minDurationDifference = durationDifference; + bestVideoMatch = videos[i]; + } + } + ytVideo = bestVideoMatch; + } else if (matchAlgorithm != SpotubeTrackMatchAlgorithm.youtube) { List ratedRankedVideos = videos .map((video) { // the find should be lazy thus everything case insensitive From b2f20d458df61818f16d6be87a411376b0ddbefd Mon Sep 17 00:00:00 2001 From: Demizo <73141750+Demizo@users.noreply.github.com> Date: Sat, 3 Sep 2022 12:29:23 -0500 Subject: [PATCH 2/2] Integrated duration matching into authentic and popular algorithms - Integrated duration matching into authentic and popular algorithms - Removed duration matching option --- lib/components/Settings/Settings.dart | 4 ---- lib/models/SpotubeTrack.dart | 2 -- lib/provider/Playback.dart | 26 +++++++------------------- 3 files changed, 7 insertions(+), 25 deletions(-) diff --git a/lib/components/Settings/Settings.dart b/lib/components/Settings/Settings.dart index cf641116..cf7f45e2 100644 --- a/lib/components/Settings/Settings.dart +++ b/lib/components/Settings/Settings.dart @@ -316,10 +316,6 @@ class Settings extends HookConsumerWidget { ), value: SpotubeTrackMatchAlgorithm.popular, ), - DropdownMenuItem( - child: Text("Match Song Duration"), - value: SpotubeTrackMatchAlgorithm.duration, - ), DropdownMenuItem( child: Text("YouTube's Top choice"), value: SpotubeTrackMatchAlgorithm.youtube, diff --git a/lib/models/SpotubeTrack.dart b/lib/models/SpotubeTrack.dart index 49ab716b..fcdabcad 100644 --- a/lib/models/SpotubeTrack.dart +++ b/lib/models/SpotubeTrack.dart @@ -10,8 +10,6 @@ enum SpotubeTrackMatchAlgorithm { popular, // selects the most popular one from the author of the track authenticPopular, - // selects song that most closely matches the actual song's duration - duration, } class SpotubeTrack extends Track { diff --git a/lib/provider/Playback.dart b/lib/provider/Playback.dart index f1cca746..1f93260d 100644 --- a/lib/provider/Playback.dart +++ b/lib/provider/Playback.dart @@ -382,25 +382,7 @@ class Playback extends PersistedChangeNotifier { } else { VideoSearchList videos = await raceMultiple(() => youtube.search.search(queryString)); - - if (matchAlgorithm == SpotubeTrackMatchAlgorithm.duration) { - //Actual duration of desired song - int targetDuration = track.duration!.inSeconds; - //start with the first result - Video bestVideoMatch = videos[0]; - int minDurationDifference = - (targetDuration - videos[0].duration!.inSeconds).abs(); - //Check if any other results are closer to the actual song duration and prefer those - for (int i = 1; i < videos.length; i++) { - int durationDifference = - (targetDuration - videos[i].duration!.inSeconds).abs(); - if (durationDifference < minDurationDifference) { - minDurationDifference = durationDifference; - bestVideoMatch = videos[i]; - } - } - ytVideo = bestVideoMatch; - } else if (matchAlgorithm != SpotubeTrackMatchAlgorithm.youtube) { + if (matchAlgorithm != SpotubeTrackMatchAlgorithm.youtube) { List ratedRankedVideos = videos .map((video) { // the find should be lazy thus everything case insensitive @@ -416,6 +398,10 @@ class Playback extends PersistedChangeNotifier { final bool hasNoLiveInTitle = !PrimitiveUtils.containsTextInBracket(ytTitle, "live"); + final bool hasCloseDuration = + (track.duration!.inSeconds - video.duration!.inSeconds) + .abs() <= + 10; //Duration matching threshold int rate = 0; for (final el in [ @@ -425,12 +411,14 @@ class Playback extends PersistedChangeNotifier { SpotubeTrackMatchAlgorithm.authenticPopular) authorIsArtist, hasNoLiveInTitle, + hasCloseDuration, !video.isLive, ]) { if (el) rate++; } // can't let pass any non title matching track if (!hasTitle) rate = rate - 2; + return { "video": video, "points": rate,