-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: discord rpc for macOS, windows-arm64 and linux-arm64 (#1713)
* feat: add discord rpc support for macos, windows arm64 and linux arm64 * chore: discord rpc not clearing activity after close/setting rpc to false * chore: add migration script to move from files from macos sandbox to non-sandbox directories
- Loading branch information
Showing
17 changed files
with
230 additions
and
136 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,67 +1,76 @@ | ||
import 'package:dart_discord_rpc/dart_discord_rpc.dart'; | ||
import 'package:flutter/foundation.dart'; | ||
import 'dart:async'; | ||
|
||
import 'package:flutter_discord_rpc/flutter_discord_rpc.dart'; | ||
import 'package:hooks_riverpod/hooks_riverpod.dart'; | ||
import 'package:spotify/spotify.dart'; | ||
import 'package:spotube/collections/env.dart'; | ||
import 'package:spotube/extensions/artist_simple.dart'; | ||
import 'package:spotube/provider/audio_player/audio_player.dart'; | ||
import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; | ||
import 'package:spotube/utils/platform.dart'; | ||
|
||
class Discord extends ChangeNotifier { | ||
final DiscordRPC? discordRPC; | ||
final bool isEnabled; | ||
class DiscordNotifier extends AsyncNotifier<void> { | ||
@override | ||
FutureOr<void> build() async { | ||
final enabled = ref.watch( | ||
userPreferencesProvider.select((s) => s.discordPresence && kIsDesktop)); | ||
final playback = ref.read(audioPlayerProvider); | ||
|
||
final subscription = | ||
FlutterDiscordRPC.instance.isConnectedStream.listen((connected) async { | ||
if (connected && playback.activeTrack != null) { | ||
await updatePresence(playback.activeTrack!); | ||
} | ||
}); | ||
|
||
Discord(this.isEnabled) | ||
: discordRPC = (kIsWindows || kIsLinux) && isEnabled | ||
? DiscordRPC(applicationId: Env.discordAppId) | ||
: null { | ||
discordRPC?.start(autoRegister: true); | ||
ref.onDispose(() async { | ||
subscription.cancel(); | ||
await close(); | ||
await FlutterDiscordRPC.instance.dispose(); | ||
}); | ||
|
||
if (!enabled && FlutterDiscordRPC.instance.isConnected) { | ||
await clear(); | ||
await close(); | ||
} else { | ||
await FlutterDiscordRPC.instance.connect(autoRetry: true); | ||
} | ||
} | ||
|
||
void updatePresence(Track track) { | ||
clear(); | ||
Future<void> updatePresence(Track track) async { | ||
await clear(); | ||
final artistNames = track.artists?.asString() ?? ""; | ||
discordRPC?.updatePresence( | ||
DiscordPresence( | ||
details: "Song: ${track.name} by $artistNames", | ||
await FlutterDiscordRPC.instance.setActivity( | ||
activity: RPCActivity( | ||
details: "${track.name} by $artistNames", | ||
state: "Vibing in Music", | ||
startTimeStamp: DateTime.now().millisecondsSinceEpoch, | ||
largeImageKey: "spotube-logo-foreground", | ||
largeImageText: "Spotube", | ||
smallImageKey: "spotube-logo-foreground", | ||
smallImageText: "Spotube", | ||
assets: const RPCAssets( | ||
largeImage: "spotube-logo-foreground", | ||
largeText: "Spotube", | ||
smallImage: "spotube-logo-foreground", | ||
smallText: "Spotube", | ||
), | ||
buttons: [ | ||
RPCButton( | ||
label: "Listen on Spotify", | ||
url: track.externalUrls?.spotify ?? | ||
"https://open.spotify.com/tracks/${track.id}", | ||
), | ||
], | ||
timestamps: RPCTimestamps( | ||
start: DateTime.now().millisecondsSinceEpoch, | ||
), | ||
), | ||
); | ||
} | ||
|
||
void clear() { | ||
discordRPC?.clearPresence(); | ||
Future<void> clear() async { | ||
await FlutterDiscordRPC.instance.clearActivity(); | ||
} | ||
|
||
void shutdown() { | ||
discordRPC?.shutDown(); | ||
} | ||
|
||
@override | ||
void dispose() { | ||
clear(); | ||
shutdown(); | ||
super.dispose(); | ||
Future<void> close() async { | ||
await FlutterDiscordRPC.instance.disconnect(); | ||
} | ||
} | ||
|
||
final discordProvider = ChangeNotifierProvider( | ||
(ref) { | ||
final isEnabled = | ||
ref.watch(userPreferencesProvider.select((s) => s.discordPresence)); | ||
final playback = ref.read(audioPlayerProvider); | ||
final discord = Discord(isEnabled); | ||
|
||
if (playback.activeTrack != null) { | ||
discord.updatePresence(playback.activeTrack!); | ||
} | ||
|
||
return discord; | ||
}, | ||
); | ||
final discordProvider = | ||
AsyncNotifierProvider<DiscordNotifier, void>(() => DiscordNotifier()); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
import 'dart:io'; | ||
|
||
import 'package:path/path.dart'; | ||
import 'package:path_provider/path_provider.dart'; | ||
import 'package:spotube/services/logger/logger.dart'; | ||
import 'package:spotube/utils/platform.dart'; | ||
|
||
/// Migrates sandbox files on macOS to non-sandbox directories | ||
Future<void> migrateMacOsFromSandboxToNoSandbox() async { | ||
if (!kIsMacOS) return; | ||
|
||
try { | ||
final sandboxApplicationSupportDir = Directory( | ||
"/Users/${Platform.environment["USER"]}/Library/Containers/oss.krtirtho.spotube/Data/Library/Application Support/oss.krtirtho.spotube", | ||
); | ||
|
||
if (!await sandboxApplicationSupportDir.exists()) { | ||
stdout.writeln("🔵 Sandbox directory not found, skipping migration"); | ||
return; | ||
} | ||
|
||
const fileExts = [".db", ".lock", ".hive"]; | ||
|
||
final supportDir = await getApplicationSupportDirectory() | ||
..create(recursive: true); | ||
|
||
final supportFiles = await supportDir.list().toList(); | ||
final oldSupportFiles = await sandboxApplicationSupportDir.list().toList(); | ||
|
||
if (oldSupportFiles.isEmpty) { | ||
stdout.writeln( | ||
"🔵 No files found in sandboxed directory, skipping migration", | ||
); | ||
return; | ||
} else if (supportFiles.any( | ||
(file) => file is File && fileExts.contains(extension(file.path)))) { | ||
stdout.writeln( | ||
"🔵 Non-sandbox directory is not empty, skipping migration", | ||
); | ||
return; | ||
} | ||
|
||
for (final oldSupportFile in oldSupportFiles) { | ||
if (oldSupportFile is File && | ||
fileExts.contains(extension(oldSupportFile.path))) { | ||
final newPath = join(supportDir.path, basename(oldSupportFile.path)); | ||
await oldSupportFile.copy(newPath); | ||
} | ||
} | ||
|
||
stdout.writeln("✅ Migrated sandboxed files to non-sandboxed directory"); | ||
} catch (e, stack) { | ||
stdout.writeln( | ||
"❌ Error migrating sandboxed files to non-sandboxed directory", | ||
); | ||
AppLogger.reportError(e, stack); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.