Genius Lyrics works without access tokens

android background playback configuration added
This commit is contained in:
Kingkor Roy Tirtho 2022-03-17 21:34:52 +06:00
parent f483c59915
commit bbfb8f8522
11 changed files with 118 additions and 11 deletions

View File

@ -27,6 +27,8 @@ jobs:
- run: chmod +x /usr/local/bin/appimagetool
- run: pip3 install appimage-builder
- run: make appimage
# Building Android Application
- run: flutter build apk
- uses: actions/upload-artifact@v2
with:
name: Spotube-Linux-Bundle
@ -34,6 +36,7 @@ jobs:
build/Spotube-linux-x86_64.deb
build/Spotube-linux-x86_64.tar.xz
build/Spotube-*-x86_64.AppImage
build/app/outputs/apk/release/app-release.apk
build_windows:
runs-on: windows-latest
steps:

View File

@ -121,9 +121,15 @@ You need a spotify account & a developer app for
- Click on **SHOW CLIENT SECRET** to reveal the **clientSecret**. Then copy the **clientID**, **clientSecret** & paste in the **Spotube's** respective fields
![step-4](https://user-images.githubusercontent.com/61944859/111769501-7fe31e80-88d3-11eb-8fc1-f3655dbd4711.png)
Also, you need a [genius](https://genius.com) account for **lyrics** & a API Client for
**Setup Genius Lyrics (Optional)**
- accessToken
- Signup/Login into [genius](https://genius.com/signup) for **lyrics**
- Go To [Genius Developer Portal](https://genius.com/api-clients/new) for creating an API client
![Step 2](https://user-images.githubusercontent.com/61944859/158823216-b4942731-c4c5-46c8-8b60-82a372b51cc5.png)
- Generate & copy access token
![Step 3](https://user-images.githubusercontent.com/61944859/158822817-f04da060-3094-4a3b-8ace-a936d0cda8db.png)
- Paste the copied access token in Spotube's Settings
![Step 4](https://user-images.githubusercontent.com/61944859/158823984-17f08534-5c92-41bc-918a-23194aad00f5.png)
> **Note!**: No personal data or any kind of sensitive information won't be collected from spotify. Don't believe? See the code for yourself

View File

@ -1,6 +1,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="oss.krtirtho.spotube">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<queries>
<!-- If your app opens https URLs -->
@ -11,7 +13,7 @@
</queries>
<application android:label="Spotube" android:name="${applicationName}" android:icon="@mipmap/ic_launcher" android:usesCleartextTraffic="true">
<activity android:name=".MainActivity" android:exported="true" android:launchMode="singleTop" android:theme="@style/LaunchTheme" android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode" android:hardwareAccelerated="true" android:windowSoftInputMode="adjustResize">
<activity android:name="com.ryanheise.audioservice.AudioServiceActivity" android:exported="true" android:launchMode="singleTop" android:theme="@style/LaunchTheme" android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode" android:hardwareAccelerated="true" android:windowSoftInputMode="adjustResize">
<!-- Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user
while the Flutter UI initializes. After that, this theme continues
@ -23,6 +25,19 @@
</intent-filter>
</activity>
<service android:name="com.ryanheise.audioservice.AudioService">
<intent-filter>
<action android:name="android.media.browse.MediaBrowserService" />
</intent-filter>
</service>
<receiver android:name="com.ryanheise.audioservice.MediaButtonReceiver">
<intent-filter>
<action android:name="android.intent.action.MEDIA_BUTTON" />
</intent-filter>
</receiver>
<!-- Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
<meta-data android:name="flutterEmbedding" android:value="2" />

19
bin/create-secrets.dart Normal file
View File

@ -0,0 +1,19 @@
import 'dart:convert';
import 'dart:io';
import 'package:path/path.dart' as path;
import 'package:dotenv/dotenv.dart';
void main() async {
load();
final bool hasKey = env.containsKey("SECRET");
final val = hasKey ? jsonDecode(env["SECRET"]!) : null;
if (!hasKey || (hasKey && val is! List)) {
throw Exception(
"'SECRET' Environmental Variable isn't configured properly");
}
await File(path.join(
Directory.current.path, "lib/models/generated_secrets.dart"))
.writeAsString("final List<String> secrets = ${env["SECRET"]};");
}

View File

@ -3,8 +3,6 @@ import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:go_router/go_router.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:spotify/spotify.dart';
import 'package:spotube/components/Settings.dart';
import 'package:spotube/components/Shared/SpotubePageRoute.dart';
import 'package:spotube/helpers/artist-to-string.dart';
import 'package:spotube/helpers/getLyrics.dart';
import 'package:spotube/provider/Playback.dart';
@ -39,7 +37,9 @@ class Lyrics extends HookConsumerWidget {
var lyricsSnapshot = useFuture(lyricsFuture);
useEffect(() {
if (lyricsSnapshot.hasData && lyricsSnapshot.data != null) {
if (lyricsSnapshot.hasData &&
lyricsSnapshot.data != null &&
playback.currentTrack != null) {
lyrics.value = {
"lyrics": lyricsSnapshot.data,
"id": playback.currentTrack!.id!

View File

@ -0,0 +1,6 @@
import 'dart:math';
final Random _random = Random();
T getRandomElement<T>(List<T> list) {
return list[_random.nextInt(list.length)];
}

View File

@ -2,6 +2,8 @@ import 'dart:convert';
import 'package:html/parser.dart' as parser;
import 'package:html/dom.dart';
import 'package:http/http.dart' as http;
import 'package:spotube/helpers/get-random-element.dart';
import 'package:spotube/models/generated_secrets.dart';
String getTitle(String title, String artist) {
return "$title $artist"
@ -47,16 +49,17 @@ Future<String?> extractLyrics(Uri url) async {
Future<List?> searchSong(
String title,
String artist, {
String apiKey = "",
String? apiKey,
bool optimizeQuery = false,
bool authHeader = false,
}) async {
try {
if (apiKey == "" || apiKey == null) apiKey = getRandomElement(secrets);
const searchUrl = 'https://api.genius.com/search?q=';
String song = optimizeQuery ? getTitle(title, artist) : "$title $artist";
String reqUrl = "$searchUrl${Uri.encodeComponent(song)}";
Map<String, String> headers = {"Authorization": 'Bearer ' + apiKey};
Map<String, String> headers = {"Authorization": 'Bearer $apiKey'};
var response = await http.get(
Uri.parse(authHeader ? reqUrl : "$reqUrl&access_token=$apiKey"),
headers: authHeader ? headers : null,
@ -100,5 +103,6 @@ Future<String?> getLyrics(
} catch (e, stack) {
print("[getLyrics] $e");
print(stack);
return null;
}
}

View File

@ -12,9 +12,16 @@ import 'package:spotube/models/LocalStorageKeys.dart';
import 'package:spotube/provider/AudioPlayer.dart';
import 'package:spotube/provider/ThemeProvider.dart';
import 'package:spotube/provider/YouTube.dart';
import 'package:just_audio_background/just_audio_background.dart';
void main() async {
if (!Platform.isAndroid && !Platform.isIOS) {
if (Platform.isAndroid || Platform.isIOS) {
await JustAudioBackground.init(
androidNotificationChannelId: 'oss.krtirtho.Spotube',
androidNotificationChannelName: 'Spotube',
androidNotificationOngoing: true,
);
} else {
WidgetsFlutterBinding.ensureInitialized();
await hotKeyManager.unregisterAll();
doWhenWindowReady(() {

View File

@ -4,7 +4,10 @@ import 'package:audio_session/audio_session.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:just_audio/just_audio.dart';
import 'package:just_audio_background/just_audio_background.dart';
import 'package:spotify/spotify.dart';
import 'package:spotube/helpers/artist-to-string.dart';
import 'package:spotube/helpers/image-to-url-string.dart';
import 'package:spotube/helpers/search-youtube.dart';
import 'package:spotube/provider/AudioPlayer.dart';
import 'package:spotube/provider/YouTube.dart';
@ -221,10 +224,17 @@ class Playback extends ChangeNotifier {
track ??= _currentTrack;
if (track != null && await _audioSession?.setActive(true) == true) {
Uri? parsedUri = Uri.tryParse(track.uri ?? "");
final tag = MediaItem(
id: track.id!,
title: track.name!,
album: track.album?.name,
artist: artistsToString(track.artists ?? <ArtistSimple>[]),
artUri: Uri.parse(imageToUrlString(track.album?.images)),
);
if (parsedUri != null && parsedUri.hasAbsolutePath) {
await player
.setAudioSource(
AudioSource.uri(parsedUri),
AudioSource.uri(parsedUri, tag: tag),
preload: true,
)
.then((value) async {
@ -238,7 +248,7 @@ class Playback extends ChangeNotifier {
if (setTrackUriById(track.id!, ytTrack.uri!)) {
await player
.setAudioSource(
AudioSource.uri(Uri.parse(ytTrack.uri!)),
AudioSource.uri(Uri.parse(ytTrack.uri!), tag: tag),
preload: true,
)
.then((value) {

View File

@ -29,6 +29,27 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "2.8.2"
audio_service:
dependency: transitive
description:
name: audio_service
url: "https://pub.dartlang.org"
source: hosted
version: "0.18.4"
audio_service_platform_interface:
dependency: transitive
description:
name: audio_service_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.0"
audio_service_web:
dependency: transitive
description:
name: audio_service_web
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.1"
audio_session:
dependency: "direct main"
description:
@ -148,6 +169,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.4"
dotenv:
dependency: "direct dev"
description:
name: dotenv
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.0"
fake_async:
dependency: transitive
description:
@ -310,6 +338,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "0.9.20"
just_audio_background:
dependency: "direct main"
description:
name: just_audio_background
url: "https://pub.dartlang.org"
source: hosted
version: "0.0.1-beta.5"
just_audio_libwinmedia:
dependency: "direct main"
description:

View File

@ -55,6 +55,7 @@ dependencies:
go_router: ^3.0.4
palette_generator: ^0.3.3
audio_session: ^0.1.6+1
just_audio_background: ^0.0.1-beta.5
dev_dependencies:
flutter_test:
@ -68,6 +69,7 @@ dev_dependencies:
# rules and activating additional ones.
flutter_lints: ^1.0.0
flutter_launcher_icons: ^0.9.2
dotenv: ^3.0.0
# For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec