mirror of
https://github.com/KRTirtho/spotube.git
synced 2025-09-12 15:35:17 +00:00
optimized search for both youtube track & synched subtitle
flutter_distributor .deb build support
This commit is contained in:
parent
ce6e4dc677
commit
cea6fd9797
@ -24,4 +24,18 @@ releases:
|
||||
target: appimage
|
||||
build_args:
|
||||
dart-define:
|
||||
APP_ENV: dev
|
||||
APP_ENV: dev
|
||||
- name: release-dev-windows-exe
|
||||
package:
|
||||
platform: windows
|
||||
target: exe
|
||||
build_args:
|
||||
dart-define:
|
||||
APP_ENV: dev
|
||||
- name: release-dev-macos-dmg
|
||||
package:
|
||||
platform: macos
|
||||
target: dmg
|
||||
build_args:
|
||||
dart-define:
|
||||
APP_ENV: dev
|
||||
|
@ -12,7 +12,6 @@ import 'package:spotube/components/Category/CategoryCard.dart';
|
||||
import 'package:spotube/components/Home/Sidebar.dart';
|
||||
import 'package:spotube/components/Home/SpotubeNavigationBar.dart';
|
||||
import 'package:spotube/components/Lyrics/SyncedLyrics.dart';
|
||||
import 'package:spotube/components/Lyrics.dart';
|
||||
import 'package:spotube/components/Search/Search.dart';
|
||||
import 'package:spotube/components/Shared/PageWindowTitleBar.dart';
|
||||
import 'package:spotube/components/Player/Player.dart';
|
||||
|
@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:spotify/spotify.dart';
|
||||
import 'package:spotube/components/Lyrics.dart';
|
||||
import 'package:spotube/components/Lyrics/Lyrics.dart';
|
||||
import 'package:spotube/components/Shared/SpotubeMarqueeText.dart';
|
||||
import 'package:spotube/helpers/artist-to-string.dart';
|
||||
import 'package:spotube/helpers/timed-lyrics.dart';
|
||||
@ -26,9 +26,10 @@ class SyncedLyrics extends HookConsumerWidget {
|
||||
if (playback.currentTrack == null ||
|
||||
playback.currentTrack is! SpotubeTrack) return null;
|
||||
try {
|
||||
if (failed.value) failed.value = false;
|
||||
final lyrics =
|
||||
await getTimedLyrics(playback.currentTrack as SpotubeTrack);
|
||||
if (failed.value) failed.value = false;
|
||||
if (lyrics == null) failed.value = true;
|
||||
return lyrics;
|
||||
} catch (e) {
|
||||
if (e == "Subtitle lookup failed") {
|
||||
@ -52,13 +53,42 @@ class SyncedLyrics extends HookConsumerWidget {
|
||||
final textTheme = Theme.of(context).textTheme;
|
||||
|
||||
useEffect(() {
|
||||
controller.scrollToIndex(
|
||||
0,
|
||||
preferPosition: AutoScrollPosition.middle,
|
||||
);
|
||||
controller.scrollToIndex(0);
|
||||
return null;
|
||||
}, [playback.currentTrack]);
|
||||
|
||||
useEffect(() {
|
||||
if (lyricsSnapshot.data != null && lyricsSnapshot.data!.rating <= 2) {
|
||||
Future.delayed(const Duration(seconds: 5), () {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return AlertDialog(
|
||||
actions: [
|
||||
TextButton(
|
||||
child: const Text("No"),
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
),
|
||||
TextButton(
|
||||
child: const Text("Yes"),
|
||||
onPressed: () {
|
||||
failed.value = true;
|
||||
Navigator.pop(context);
|
||||
},
|
||||
),
|
||||
],
|
||||
content: const Text(
|
||||
"The found lyrics might not be properly synced. Do you want to default to static (genius.com) lyrics?"),
|
||||
);
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
return null;
|
||||
}, [lyricsSnapshot.data]);
|
||||
|
||||
// when synced lyrics not found, fallback to GeniusLyrics
|
||||
if (failed.value) return const Lyrics();
|
||||
|
||||
|
6
lib/helpers/contains-text-in-bracket.dart
Normal file
6
lib/helpers/contains-text-in-bracket.dart
Normal file
@ -0,0 +1,6 @@
|
||||
bool containsTextInBracket(String matcher, String text) {
|
||||
return RegExp(r"(?<=\().+?(?=\))")
|
||||
.allMatches(matcher)
|
||||
.map((e) => e.group(0))
|
||||
.every((match) => match?.contains(text) ?? false);
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
import 'dart:io';
|
||||
import 'package:spotify/spotify.dart';
|
||||
import 'package:spotube/helpers/contains-text-in-bracket.dart';
|
||||
import 'package:spotube/helpers/getLyrics.dart';
|
||||
import 'package:spotube/models/Logger.dart';
|
||||
import 'package:spotube/models/SpotubeTrack.dart';
|
||||
@ -36,15 +37,40 @@ Future<SpotubeTrack> toSpotubeTrack(
|
||||
// the find should be lazy thus everything case insensitive
|
||||
final ytTitle = video.title.toLowerCase();
|
||||
final bool hasTitle = ytTitle.contains(title);
|
||||
final bool hasYtTitle = title.contains(ytTitle);
|
||||
final bool hasAllArtists = track.artists?.every(
|
||||
(artist) => ytTitle.contains(artist.name!.toLowerCase()),
|
||||
) ??
|
||||
false;
|
||||
final bool authorIsArtist = track.artists
|
||||
?.any((artist) => artist.name?.toLowerCase() == video.author) ??
|
||||
final bool authorIsArtist = track.artists?.any((artist) {
|
||||
return artist.name?.toLowerCase() == video.author.toLowerCase();
|
||||
}) ??
|
||||
false;
|
||||
|
||||
final bool hasNoLive = !containsTextInBracket(ytTitle, "live");
|
||||
final bool hasOfficialVideo = [
|
||||
"(official video)",
|
||||
"[official video]",
|
||||
"(official music video)",
|
||||
"[official music video]"
|
||||
].any((v) => ytTitle.contains(v));
|
||||
|
||||
final bool hasOfficialAudio = [
|
||||
"[official audio]",
|
||||
"(official audio)",
|
||||
].any((v) => ytTitle.contains(v));
|
||||
|
||||
int rate = 0;
|
||||
for (final el in [hasTitle, hasAllArtists, authorIsArtist]) {
|
||||
for (final el in [
|
||||
hasTitle,
|
||||
hasYtTitle,
|
||||
hasAllArtists,
|
||||
authorIsArtist,
|
||||
hasNoLive,
|
||||
!video.isLive,
|
||||
hasOfficialAudio,
|
||||
hasOfficialVideo,
|
||||
]) {
|
||||
if (el) rate++;
|
||||
}
|
||||
return {
|
||||
|
@ -2,6 +2,7 @@ import 'package:html/dom.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:html/parser.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:spotube/helpers/contains-text-in-bracket.dart';
|
||||
import 'package:spotube/helpers/getLyrics.dart';
|
||||
import 'package:spotube/models/Logger.dart';
|
||||
import 'package:spotube/models/SpotubeTrack.dart';
|
||||
@ -12,10 +13,12 @@ class SubtitleSimple {
|
||||
Uri uri;
|
||||
String name;
|
||||
List<LyricSlice> lyrics;
|
||||
int rating;
|
||||
SubtitleSimple({
|
||||
required this.uri,
|
||||
required this.name,
|
||||
required this.lyrics,
|
||||
required this.rating,
|
||||
});
|
||||
}
|
||||
|
||||
@ -60,9 +63,10 @@ Future<SubtitleSimple?> getTimedLyrics(SpotubeTrack track) async {
|
||||
.every((artist) => title.contains(artist.toLowerCase())) ??
|
||||
false;
|
||||
final hasTrackName = title.contains(track.name!.toLowerCase());
|
||||
final isNotLive = !containsTextInBracket(title, "live");
|
||||
final exactYtMatch = title == track.ytTrack.title.toLowerCase();
|
||||
if (exactYtMatch) points = 8;
|
||||
for (final criteria in [hasTrackName, hasAllArtists]) {
|
||||
if (exactYtMatch) points = 7;
|
||||
for (final criteria in [hasTrackName, hasAllArtists, isNotLive]) {
|
||||
if (criteria) points++;
|
||||
}
|
||||
return {"result": result, "points": points};
|
||||
@ -111,6 +115,7 @@ Future<SubtitleSimple?> getTimedLyrics(SpotubeTrack track) async {
|
||||
name: topResult.text.trim(),
|
||||
uri: subtitleUri,
|
||||
lyrics: lrcList,
|
||||
rating: rateSortedResults.first["points"] as int,
|
||||
);
|
||||
|
||||
return subtitle;
|
||||
|
27
linux/packaging/deb/make_config.yaml
Normal file
27
linux/packaging/deb/make_config.yaml
Normal file
@ -0,0 +1,27 @@
|
||||
display_name: Spotube
|
||||
package_name: spotube
|
||||
|
||||
maintainer:
|
||||
name: Kingkor Roy Tirtho
|
||||
email: krtirtho@gmail.com
|
||||
|
||||
priority: optional
|
||||
section: x11
|
||||
installed_size: 24400
|
||||
|
||||
dependencies:
|
||||
- libkeybinder-3.0-0 (>= 0.3.2)
|
||||
|
||||
essential: false
|
||||
icon: assets/spotube-logo.png
|
||||
|
||||
keywords:
|
||||
- Music
|
||||
- Spotify
|
||||
- Media
|
||||
- Streaming
|
||||
- YouTube
|
||||
|
||||
generic_name: Music Streaming Application
|
||||
categories:
|
||||
- Music
|
Loading…
Reference in New Issue
Block a user