lyrics not working bugfix

Download track feature complete support in Android
Android sudden solid color screen
inno-script updated for permission_handler
gensums updated for support for android apk
updated description of Spotube in every file
changes added to CHANGELOG
This commit is contained in:
Kingkor Roy Tirtho 2022-03-24 13:30:59 +06:00
parent 0cf5bfea50
commit 45f9d08595
24 changed files with 240 additions and 82 deletions

View File

@ -29,6 +29,7 @@ jobs:
- run: make appimage
# Building Android Application
- run: flutter build apk
- run: mv build/app/outputs/apk/release/app-release.apk build/Spotube-android-arm64-v8a.apk
- uses: actions/upload-artifact@v2
with:
name: Spotube-Linux-Bundle
@ -36,7 +37,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/Spotube-android-arm64-v8a.apk
build_windows:
runs-on: windows-latest
steps:

View File

@ -1,3 +1,30 @@
# v2.0.0
### New
- Android Support https://github.com/KRTirtho/spotube/issues/24
- Responsive UI (Mobile, Tablet)
- Anonymous/Guest Account
- Mini floating player
- Full page PlayerView for smaller devices
- Horizontal CategoryCard Scroll & pagination for quicker access to Playlists
- Bottom bar for smaller devices
- Collapsed Sidebar for medium sized devices
- Persists Volume level
- Android NavigationPanel controls (OS media controls of Android)
### Improved
- Search - now scrolls & paginates for Playlists & Albums
- Authentication - allows guest accounts making authentication optional
- Lyrics - can be fetched without requiring GeniusAccessToken. This makes geniusAccessToken optional
- UI snappiness & faster load times
- Simpler logic, faster calculations & better caching (flutter_hooks)
- shared state management - uses riverpod & hooks combination
### Bug fixes
- Can't play any song in macos https://github.com/KRTirtho/spotube/issues/23
- Downloaded tracks can't be played as they're WebAudio (.weba) instead of MP3
- delay while changing Playlist/Single tracks
# v1.2.0
### New

View File

@ -27,7 +27,9 @@ Spotube is a [Flutter](https://flutter.dev) based lightweight spotify client. It
Following are the features that currently spotube offers:
- Open Source
- No telementry, diagnostics or user data collection
- Anonymous/Guest Login
- Cross platform
- No telemetry, diagnostics or user data collection
- Lightweight & resource friendly
- Native performance (Thanks to Flutter+Skia)
- Playback control is on user's machine instead of server based
@ -36,7 +38,7 @@ Following are the features that currently spotube offers:
- Lyrics
- Downloadable track
<a href="https://www.producthunt.com/posts/spotube?utm_source=badge-featured&utm_medium=badge&utm_souce=badge-spotube" target="_blank"><img src="https://api.producthunt.com/widgets/embed-image/v1/featured.svg?post_id=327965&theme=dark" alt="Spotube - A lightweight+free Spotify desktop-client made with flutter | Product Hunt" style="width: 250px; height: 54px;" width="250" height="54" /></a>
<a href="https://www.producthunt.com/posts/spotube?utm_source=badge-featured&utm_medium=badge&utm_souce=badge-spotube" target="_blank"><img src="https://api.producthunt.com/widgets/embed-image/v1/featured.svg?post_id=327965&theme=dark" alt="Spotube - A lightweight+free Spotify crossplatform-client made with flutter | Product Hunt" style="width: 250px; height: 54px;" width="250" height="54" /></a>
# Installation
@ -44,6 +46,10 @@ I'm always releasing newer versions of binary of the software each 2-3 month wit
All the binaries are located in the [releases](https://github.com/krtirtho/spotube/releases), just download
## Android
Download the [Android app](https://github.com/KRTirtho/spotube/releases/latest/download/Spotube-android-arm64-v8a.apk) & install it on your phone/tablet
## Windows
Download the [setup file](https://github.com/KRTirtho/spotube/releases/latest/download/Spotube-windows-x86_64-setup.exe) & follow along the installer
@ -98,30 +104,33 @@ Download the [Mac OS Disk Image (.dmg) file](https://github.com/KRTirtho/spotube
**I'll/try to upload the package binaries to linux debian/arch/ubuntu/snap/flatpack/redhat/chocolatey/homebrew stores or software centers or repositories**
# Configuration
There are some configurations that needs to be done to start using this software
## Optional Configurations
<details>
<summary>Login with <b>Spotify</b></summary>
You need a spotify account & a developer app for
You need a spotify account & a developer app for
- clientId
- clientSecret
- clientId
- clientSecret
**Grab credentials:**
**Grab credentials:**
- Go to https://developer.spotify.com/dashboard/login & login with your spotify account (Skip if you're logged in)
- Go to https://developer.spotify.com/dashboard/login & login with your spotify account (Skip if you're logged in)
![Step 1](https://user-images.githubusercontent.com/61944859/111762106-d1d37680-88ca-11eb-9884-ec7a40c0dd27.png)
- Create an web app for Spotify Public API
- Create an web app for Spotify Public API
![step 2](https://user-images.githubusercontent.com/61944859/111762507-473f4700-88cb-11eb-91f3-d480e9584883.png)
- Give the app a name & description. Then Edit settings & add **http://localhost:4304/auth/spotify/callback** as **Redirect URI** for the app. Its important for authenticating
- Give the app a name & description. Then Edit settings & add **http://localhost:4304/auth/spotify/callback** as **Redirect URI** for the app. Its important for authenticating
![setp-3](https://user-images.githubusercontent.com/61944859/111768971-d308a180-88d2-11eb-9108-3e7444cef049.png)
- Click on **SHOW CLIENT SECRET** to reveal the **clientSecret**. Then copy the **clientID**, **clientSecret** & paste in the **Spotube's** respective fields
- 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)
</details>
**Setup Genius Lyrics (Optional)**
<details>
<summary>Setup <b>Genius Lyrics</b></summary>
- 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
@ -132,6 +141,7 @@ You need a spotify account & a developer app for
![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
</details>
# TODO:
@ -140,6 +150,7 @@ You need a spotify account & a developer app for
- [x] Track download
- [ ] Support for playing/streaming podcasts/shows
- [x] Artist, User & Album pages
- [x] Android Support
# Building from source
@ -179,6 +190,16 @@ Bu why? You can learn about it [here](https://dev.to/krtirtho/choosing-open-sour
- [bitsdojo_window](https://github.com/bitsdojo/bitsdojo_window) - A Flutter package that makes it easy to customize and work with your Flutter desktop app window on Windows, macOS and Linux
- [hotkey_manager](https://github.com/leanflutter/hotkey_manager) - A flutter plugin that allow Flutter desktop apps to defines system/inapp wide hotkey
- [Inno Setup](https://jrsoftware.org/isinfo.php) - Inno Setup is a free installer for Windows programs by Jordan Russell and Martijn Laan
- [collection](https://github.com/dart-lang/collection) - The collection package for Dart contains a number of separate libraries with utility functions and classes that makes working with collections easier
- [flutter_riverpod](https://riverpod.dev/) - A Reactive Caching and Data-binding Framework
- [flutter_hooks](https://github.com/rrousselGit/flutter_hooks) - React hooks for Flutter. Hooks are a new kind of object that manages a Widget life-cycles. They are used to increase code sharing between widgets and as a complete replacement for StatefulWidget
- [hooks_riverpod](https://riverpod.dev/) - Riverpod with hooks
- [go_router](https://github.com/flutter/packages/tree/main/packages/go_router) - A declarative router for Flutter based on Navigation 2 supporting deep linking, data-driven routes and more
- [palette_generator](https://github.com/flutter/packages/tree/main/packages/palette_generator) - Flutter package for generating palette colors from a source image.
- [audio_session](https://github.com/ryanheise/audio_session) - Sets the iOS audio session category and Android audio attributes for your app, and manages your app's audio focus, mixing and ducking behaviour.
- [logger](https://github.com/leisim/logger) - Small, easy to use and extensible logger which prints beautiful logs
- [flutter_launcher_icons](https://github.com/fluttercommunity/flutter_launcher_icons) - A package which simplifies the task of updating your Flutter app's launcher icon.
- [permission_handler](https://github.com/baseflow/flutter-permission-handler) - Permission plugin for Flutter. This plugin provides a cross-platform (iOS, Android) API to request and check permissions.
# Social handlers

View File

@ -26,7 +26,7 @@ apply plugin: 'kotlin-android'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
android {
compileSdkVersion flutter.compileSdkVersion
compileSdkVersion 31
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8

View File

@ -3,6 +3,8 @@
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<queries>
<!-- If your app opens https URLs -->
@ -12,7 +14,7 @@
</intent>
</queries>
<application android:label="Spotube" android:name="${applicationName}" android:icon="@mipmap/ic_launcher" android:usesCleartextTraffic="true">
<application android:label="Spotube" android:name="${applicationName}" android:icon="@mipmap/ic_launcher" android:usesCleartextTraffic="true" android:requestLegacyExternalStorage="true">
<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

View File

@ -1,5 +1,5 @@
pkgbase = spotube-bin
pkgdesc = A lightweight free Spotify desktop-client which handles playback manually, streams music using Youtube & no Spotify premium account is needed
pkgdesc = A lightweight free Spotify crossplatform-client which handles playback manually, streams music using Youtube & no Spotify premium account is needed
pkgver = 1.2.0
pkgrel = 2
url = https://github.com/KRTirtho/spotube/

View File

@ -3,7 +3,7 @@ pkgname=spotube-bin
pkgver=1.2.0
pkgrel=2
epoch=
pkgdesc="A lightweight free Spotify desktop-client which handles playback manually, streams music using Youtube & no Spotify premium account is needed"
pkgdesc="A lightweight free Spotify crossplatform-client which handles playback manually, streams music using Youtube & no Spotify premium account is needed"
arch=(x86_64)
url="https://github.com/KRTirtho/spotube/"
license=('BSD-4-Clause')

View File

@ -22,7 +22,7 @@
<docsUrl>https://github.com/KRTirtho/spotube#readme</docsUrl>
<bugTrackerUrl>https://github.com/KRTirtho/spotube/issues/new</bugTrackerUrl>
<tags>spotube music audio spotify youtube flutter</tags>
<summary>A lightweight free Spotify 🎧 desktop-client 🖥 which handles playback manually, streams music using Youtube &amp; no Spotify premium account is needed 😱</summary>
<summary>A lightweight free Spotify 🎧 crossplatform-client 🖥📱 which handles playback manually, streams music using Youtube &amp; no Spotify premium account is needed 😱</summary>
<description>
Spotube is a Flutter based lightweight spotify client. It utilizes the power
of Spotify &amp; Youtube's public API &amp; creates a hazardless, performant &amp; resource

View File

@ -7,5 +7,5 @@ Essential: no
Installed-Size: 24400
Depends: libkeybinder-3.0-0 (>= 0.3.2)
Maintainer: Kingkor Roy Tirtho <krtirtho@gmail.com>
Description: A lightweight free Spotify desktop-client which handles playback manually, streams music using Youtube & no Spotify premium account is needed
Description: A lightweight free Spotify crossplatform-client which handles playback manually, streams music using Youtube & no Spotify premium account is needed
Homepage: https://github.com/KRTirtho/spotube

View File

@ -15,12 +15,11 @@ class Lyrics extends HookConsumerWidget {
Widget build(BuildContext context, ref) {
Playback playback = ref.watch(playbackProvider);
UserPreferences userPreferences = ref.watch(userPreferencesProvider);
var lyrics = useState({});
final lyrics = useState({});
bool hasToken = userPreferences.geniusAccessToken.isNotEmpty;
var lyricsFuture = useMemoized(() {
final lyricsFuture = useMemoized(() {
if (playback.currentTrack == null ||
!hasToken ||
userPreferences.geniusAccessToken.isEmpty ||
(playback.currentTrack?.id != null &&
playback.currentTrack?.id == lyrics.value["id"])) {
return null;
@ -31,9 +30,9 @@ class Lyrics extends HookConsumerWidget {
apiKey: userPreferences.geniusAccessToken,
optimizeQuery: true,
);
}, [playback.currentTrack]);
}, [playback.currentTrack, userPreferences.geniusAccessToken]);
var lyricsSnapshot = useFuture(lyricsFuture);
final lyricsSnapshot = useFuture(lyricsFuture);
useEffect(() {
if (lyricsSnapshot.hasData &&

View File

@ -1,4 +1,5 @@
import 'dart:async';
import 'dart:io';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
@ -40,9 +41,16 @@ class Player extends HookConsumerWidget {
/// [disposeAllPlayers] method which is throwing
/// [UnimplementedException] in the [PlatformInterface]
/// implementation
if (Platform.isAndroid || Platform.isIOS) {
playback.audioSession
?.setActive(true)
.then((_) => player.setAsset("assets/warmer.mp3"));
.then((_) => player.setAsset("assets/warmer.mp3"))
.catchError((e) {
logger.e("useEffect", e, StackTrace.current);
});
} else {
player.setAsset("assets/warmer.mp3");
}
return null;
}, []);
@ -64,7 +72,7 @@ class Player extends HookConsumerWidget {
final entryRef = useRef<OverlayEntry?>(null);
disposeOverlay() {
void disposeOverlay() {
try {
entryRef.value?.remove();
entryRef.value = null;
@ -76,25 +84,37 @@ class Player extends HookConsumerWidget {
}
useEffect(() {
// clearing the overlay-entry as passing the already available
// entry will result in splashing while resizing the window
if (entryRef.value != null) disposeOverlay();
if (breakpoint.isLessThanOrEqualTo(Breakpoints.md)) {
entryRef.value = OverlayEntry(
opaque: false,
builder: (context) => PlayerOverlay(albumArt: albumArt),
);
// I can't believe useEffect doesn't run Post Frame aka
// after rendering/painting the UI
// `My disappointment is immeasurable and my day is ruined` XD
WidgetsBinding.instance?.addPostFrameCallback((time) {
// clearing the overlay-entry as passing the already available
// entry will result in splashing while resizing the window
if (breakpoint.isLessThanOrEqualTo(Breakpoints.md) &&
entryRef.value == null &&
playback.currentTrack != null) {
entryRef.value = OverlayEntry(
opaque: false,
builder: (context) => PlayerOverlay(albumArt: albumArt),
);
try {
Overlay.of(context)?.insert(entryRef.value!);
} catch (e) {
if (e is AssertionError &&
e.message ==
'The specified entry is already present in the Overlay.') {
disposeOverlay();
Overlay.of(context)?.insert(entryRef.value!);
});
}
}
} else {
disposeOverlay();
}
});
return () {
disposeOverlay();
};
}, [breakpoint]);
}, [breakpoint, playback.currentTrack]);
// returning an empty non spacious Container as the overlay will take
// place in the global overlay stack aka [_entries]

View File

@ -66,14 +66,17 @@ class Settings extends HookConsumerWidget {
? () async {
SharedPreferences localStorage =
await SharedPreferences.getInstance();
if (geniusAccessToken.value != null &&
geniusAccessToken.value!.isNotEmpty) {
preferences.setGeniusAccessToken(
geniusAccessToken.value ?? "");
geniusAccessToken.value!,
);
localStorage.setString(
LocalStorageKeys.geniusAccessToken,
geniusAccessToken.value ?? "");
geniusAccessToken.value!);
}
geniusAccessToken.value = null;
textEditingController.text = "";
}
: null,
@ -141,12 +144,12 @@ class Settings extends HookConsumerWidget {
const SizedBox(height: 10),
if (auth.isAnonymous)
Wrap(
spacing: 20,
runSpacing: 20,
alignment: WrapAlignment.spaceBetween,
runAlignment: WrapAlignment.center,
crossAxisAlignment: WrapCrossAlignment.center,
children: [
const Text("Login with your Spotify account"),
const SizedBox(width: 20),
ElevatedButton(
child: Text("Connect with Spotify".toUpperCase()),
onPressed: () {

View File

@ -1,10 +1,23 @@
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
class AnonymousFallback extends StatelessWidget {
const AnonymousFallback({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return const Center(child: Text("You're not logged in"));
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text("You're not logged in"),
const SizedBox(height: 10),
ElevatedButton(
child: const Text("Login with Spotify"),
onPressed: () => GoRouter.of(context).push("/settings"),
)
],
),
);
}
}

View File

@ -7,6 +7,7 @@ import 'package:spotube/helpers/artist-to-string.dart';
import 'package:youtube_explode_dart/youtube_explode_dart.dart';
import 'package:path_provider/path_provider.dart' as path_provider;
import 'package:path/path.dart' as path;
import 'package:permission_handler/permission_handler.dart';
enum TrackStatus { downloading, idle, done }
@ -21,16 +22,31 @@ class DownloadTrackButton extends HookWidget {
var _downloadTrack = useCallback(() async {
if (track == null) return;
if ((Platform.isAndroid || Platform.isIOS) &&
!await Permission.storage.isGranted &&
!await Permission.storage.isPermanentlyDenied) {
final status = await Permission.storage.request();
if (!status.isGranted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text("Couldn't download track. Not enough permissions"),
),
);
return;
}
}
StreamManifest manifest =
await yt.videos.streamsClient.getManifest(track?.href);
var audioStream = yt.videos.streamsClient.get(
final audioStream = yt.videos.streamsClient
.get(
manifest.audioOnly
.where((audio) => audio.codec.mimeType == "audio/mp4")
.withHighestBitrate(),
);
)
.asBroadcastStream();
var statusCb = audioStream.listen(
final statusCb = audioStream.listen(
(event) {
if (status.value != TrackStatus.downloading) {
status.value = TrackStatus.downloading;
@ -50,7 +66,10 @@ class DownloadTrackButton extends HookWidget {
);
String downloadFolder = path.join(
(await path_provider.getDownloadsDirectory())!.path, "Spotube");
Platform.isAndroid
? "/storage/emulated/0/Download"
: (await path_provider.getDownloadsDirectory())!.path,
"Spotube");
String fileName =
"${track?.name} - ${artistsToString<Artist>(track?.artists ?? [])}.mp3";
File outputFile = File(path.join(downloadFolder, fileName));

View File

@ -88,7 +88,7 @@ Future<List?> searchSong(
Future<String?> getLyrics(
String title,
String artist, {
String apiKey = "",
required String apiKey,
bool optimizeQuery = false,
bool authHeader = false,
}) async {

View File

@ -107,8 +107,15 @@ class Playback extends ChangeNotifier {
_processingStateStreamListener =
player.processingStateStream.listen((event) async {
try {
if (event == ProcessingState.completed && _currentTrack?.id != null) {
if (event != ProcessingState.completed) return;
if (_currentTrack?.id != null) {
movePlaylistPositionBy(1);
} else {
await audioSession?.setActive(false);
_isPlaying = false;
_duration = null;
_callAllDurationListeners(null);
notifyListeners();
}
} catch (e, stack) {
_logger.e("PrecessingStateStreamListener", e, stack);
@ -167,6 +174,7 @@ class Playback extends ChangeNotifier {
_callAllDurationListeners(null);
_currentPlaylist = null;
_currentTrack = null;
_audioSession?.setActive(false);
notifyListeners();
}
@ -196,7 +204,7 @@ class Playback extends ChangeNotifier {
super.dispose();
}
movePlaylistPositionBy(int pos) {
void movePlaylistPositionBy(int pos) {
if (_currentTrack != null && _currentPlaylist != null) {
int index = _currentPlaylist!.trackIds.indexOf(_currentTrack!.id!) + pos;

View File

@ -4,8 +4,10 @@ import 'package:flutter/cupertino.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:hotkey_manager/hotkey_manager.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:spotube/helpers/get-random-element.dart';
import 'package:spotube/models/LocalStorageKeys.dart';
import 'package:spotube/models/Logger.dart';
import 'package:spotube/models/generated_secrets.dart';
class UserPreferences extends ChangeNotifier {
String geniusAccessToken;
@ -33,15 +35,17 @@ class UserPreferences extends ChangeNotifier {
}
return HotKey.fromJson(json);
}
return null;
}
onInit() async {
Future<void> onInit() async {
try {
SharedPreferences localStorage = await SharedPreferences.getInstance();
String? accessToken =
localStorage.getString(LocalStorageKeys.geniusAccessToken);
if (accessToken != null) geniusAccessToken = accessToken;
geniusAccessToken = accessToken != null && accessToken.isNotEmpty
? accessToken
: getRandomElement(lyricsSecrets);
nextTrackHotKey ??= (await _getHotKeyFromLocalStorage(
localStorage,
@ -75,12 +79,12 @@ class UserPreferences extends ChangeNotifier {
}
}
setGeniusAccessToken(String token) {
void setGeniusAccessToken(String token) {
geniusAccessToken = token;
notifyListeners();
}
setNextTrackHotKey(HotKey? value) {
void setNextTrackHotKey(HotKey? value) {
nextTrackHotKey = value;
SharedPreferences.getInstance().then((preferences) {
preferences.setString(
@ -91,7 +95,7 @@ class UserPreferences extends ChangeNotifier {
notifyListeners();
}
setPrevTrackHotKey(HotKey? value) {
void setPrevTrackHotKey(HotKey? value) {
prevTrackHotKey = value;
SharedPreferences.getInstance().then((preferences) {
preferences.setString(
@ -102,7 +106,7 @@ class UserPreferences extends ChangeNotifier {
notifyListeners();
}
setPlayPauseHotKey(HotKey? value) {
void setPlayPauseHotKey(HotKey? value) {
playPauseHotKey = value;
SharedPreferences.getInstance().then((preferences) {
preferences.setString(
@ -114,5 +118,5 @@ class UserPreferences extends ChangeNotifier {
}
}
var userPreferencesProvider =
final userPreferencesProvider =
ChangeNotifierProvider((_) => UserPreferences(geniusAccessToken: ""));

View File

@ -3,7 +3,7 @@
<id>com.github.KRTirtho.Spotube</id>
<name>Spotube</name>
<summary>
A lightweight free Spotify desktop-client which handles playback manually, streams music using Youtube &amp; no Spotify premium account is needed
A lightweight free Spotify crossplatform-client which handles playback manually, streams music using Youtube &amp; no Spotify premium account is needed
</summary>
<metadata_license>CC0-1.0</metadata_license>
<project_license>BSD-4-Clause</project_license>

View File

@ -506,6 +506,41 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.11.1"
permission_handler:
dependency: "direct main"
description:
name: permission_handler
url: "https://pub.dartlang.org"
source: hosted
version: "9.2.0"
permission_handler_android:
dependency: transitive
description:
name: permission_handler_android
url: "https://pub.dartlang.org"
source: hosted
version: "9.0.2+1"
permission_handler_apple:
dependency: transitive
description:
name: permission_handler_apple
url: "https://pub.dartlang.org"
source: hosted
version: "9.0.3"
permission_handler_platform_interface:
dependency: transitive
description:
name: permission_handler_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "3.7.0"
permission_handler_windows:
dependency: transitive
description:
name: permission_handler_windows
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.0"
petitparser:
dependency: transitive
description:

View File

@ -1,5 +1,5 @@
name: spotube
description: A lightweight free Spotify desktop-client which handles playback manually, streams music using Youtube & no Spotify premium account is needed
description: A lightweight free Spotify crossplatform-client which handles playback manually, streams music using Youtube & no Spotify premium account is needed
# The following line prevents the package from being accidentally published to
# pub.dev using `flutter pub publish`. This is preferred for private packages.
@ -56,6 +56,7 @@ dependencies:
audio_session: ^0.1.6+1
just_audio_background: ^0.0.1-beta.5
logger: ^1.1.0
permission_handler: ^9.2.0
dev_dependencies:
flutter_test:

View File

@ -1,4 +1,4 @@
#!/bin/env bash
md5sum build/**/*.{AppImage,deb,tar.xz,dmg,exe,nupkg} >build/RELEASE.md5sum
sha256sum build/**/*.{AppImage,deb,tar.xz,dmg,exe,nupkg} >build/RELEASE.sha256sum
md5sum build/**/*.{AppImage,deb,tar.xz,dmg,exe,nupkg,apk} >build/RELEASE.md5sum
sha256sum build/**/*.{AppImage,deb,tar.xz,dmg,exe,nupkg,apk} >build/RELEASE.sha256sum
sed -i 's|build/Spotube-.*-Bundle/||' build/RELEASE.sha256sum build/RELEASE.md5sum

View File

@ -10,7 +10,7 @@
[Setup]
; NOTE: The value of AppId uniquely identifies this application. Do not use the same AppId value in installers for other applications.
; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
AppId={{80B901C8-D6FE-494E-8AF7-A2BD440E8644}
AppId={80B901C8-D6FE-494E-8AF7-A2BD440E8644}
AppName={#MyAppName}
AppVersion={#MyAppVersion}
;AppVerName={#MyAppName} {#MyAppVersion}
@ -43,6 +43,7 @@ Source: "..\build\windows\runner\Release\flutter_windows.dll"; DestDir: "{app}";
Source: "..\build\windows\runner\Release\hotkey_manager_plugin.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "..\build\windows\runner\Release\libwinmedia.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "..\build\windows\runner\Release\libwinmedia_plugin.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "..\build\windows\runner\Release\permission_handler_plugin.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "..\build\windows\runner\Release\spotube.exp"; DestDir: "{app}"; Flags: ignoreversion
Source: "..\build\windows\runner\Release\spotube.lib"; DestDir: "{app}"; Flags: ignoreversion
Source: "..\build\windows\runner\Release\url_launcher_windows_plugin.dll"; DestDir: "{app}"; Flags: ignoreversion

View File

@ -9,6 +9,7 @@
#include <bitsdojo_window_windows/bitsdojo_window_plugin.h>
#include <hotkey_manager/hotkey_manager_plugin.h>
#include <libwinmedia/libwinmedia_plugin.h>
#include <permission_handler_windows/permission_handler_windows_plugin.h>
#include <url_launcher_windows/url_launcher_windows.h>
void RegisterPlugins(flutter::PluginRegistry* registry) {
@ -18,6 +19,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) {
registry->GetRegistrarForPlugin("HotkeyManagerPlugin"));
LibwinmediaPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("LibwinmediaPlugin"));
PermissionHandlerWindowsPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("PermissionHandlerWindowsPlugin"));
UrlLauncherWindowsRegisterWithRegistrar(
registry->GetRegistrarForPlugin("UrlLauncherWindows"));
}

View File

@ -6,6 +6,7 @@ list(APPEND FLUTTER_PLUGIN_LIST
bitsdojo_window_windows
hotkey_manager
libwinmedia
permission_handler_windows
url_launcher_windows
)