refactor(audio-metadata): migrate from dart audio tagging library to rust based in-house solution

* fix(home): android bottom-bar abnormal empty top space for unknown reason
* chore: bump deps and use pub.dev version of spotify package
This commit is contained in:
Kingkor Roy Tirtho 2022-09-05 00:09:05 +06:00
parent 2ab1fba3d6
commit d841b06882
15 changed files with 137 additions and 423 deletions

View File

@ -111,6 +111,10 @@ class Home extends HookConsumerWidget {
}, [backgroundColor]);
return Scaffold(
bottomNavigationBar: SpotubeNavigationBar(
selectedIndex: _selectedIndex.value,
onSelectedIndexChanged: _onSelectedIndexChanged,
),
body: Column(
children: [
if (_selectedIndex.value != 3)
@ -178,10 +182,6 @@ class Home extends HookConsumerWidget {
),
// player itself
Player(),
SpotubeNavigationBar(
selectedIndex: _selectedIndex.value,
onSelectedIndexChanged: _onSelectedIndexChanged,
),
],
),
);

View File

@ -1,6 +1,5 @@
import 'package:badges/badges.dart';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:spotube/components/Home/Sidebar.dart';
import 'package:spotube/hooks/useBreakpoints.dart';
@ -24,7 +23,7 @@ class SpotubeNavigationBar extends HookConsumerWidget {
);
final breakpoint = useBreakpoints();
if (breakpoint.isMoreThan(Breakpoints.sm)) return Container();
if (breakpoint.isMoreThan(Breakpoints.sm)) return const SizedBox();
return NavigationBar(
destinations: [
...sidebarTileList.map(

View File

@ -1,12 +1,10 @@
import 'dart:convert';
import 'dart:io';
import 'package:dart_tags/dart_tags.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:metadata_god/bridge_generated.dart';
import 'package:metadata_god/metadata_god.dart';
import 'package:mime/mime.dart';
import 'package:mp3_info/mp3_info.dart';
import 'package:path/path.dart';
import 'package:path_provider/path_provider.dart';
import 'package:spotify/spotify.dart';
@ -18,14 +16,12 @@ import 'package:spotube/provider/Playback.dart';
import 'package:spotube/provider/UserPreferences.dart';
import 'package:spotube/utils/primitive_utils.dart';
import 'package:spotube/utils/type_conversion_utils.dart';
import 'package:id3/id3.dart';
final tagProcessor = TagProcessor();
const supportedAudioTypes = [
"audio/webm",
"audio/ogg",
"audio/mpeg",
"audio/mp4",
"audio/opus",
"audio/wav",
"audio/aac",
@ -56,69 +52,38 @@ final localTracksProvider = FutureProvider<List<Track>>((ref) async {
}).map(
(f) async {
try {
final bytes = f.readAsBytes();
final mp3Instance = MP3Instance(await bytes);
final metadata = await MetadataGod.getMetadata(f);
bool isParsed = false;
try {
isParsed = mp3Instance.parseTagsSync();
} catch (e, stack) {
getLogger(MP3Instance).e("[parseTagsSync]", e, stack);
}
final imageFile = isParsed
? File(join(
(await getTemporaryDirectory()).path,
"spotube",
basenameWithoutExtension(f.path) +
imgMimeToExt[mp3Instance.metaTags["APIC"]?["mime"] ??
"image/jpeg"]!,
))
: null;
if (imageFile != null &&
!await imageFile.exists() &&
mp3Instance.metaTags["APIC"]?["base64"] != null) {
final imageFile = File(join(
(await getTemporaryDirectory()).path,
"spotube",
basenameWithoutExtension(f.path) +
imgMimeToExt[metadata?.picture?.mimeType ?? "image/jpeg"]!,
));
if (!await imageFile.exists() && metadata?.picture != null) {
await imageFile.create(recursive: true);
await imageFile.writeAsBytes(
base64Decode(
mp3Instance.metaTags["APIC"]["base64"],
),
metadata?.picture?.data ?? [],
mode: FileMode.writeOnly,
);
}
Duration duration;
try {
duration = MP3Processor.fromBytes(await bytes).duration;
} catch (e, stack) {
getLogger(MP3Processor).e("[Parsing Mp3]", e, stack);
duration = Duration.zero;
}
final metadata = await tagProcessor.getTagsFromByteArray(bytes);
return {
"metadata": metadata,
"file": f,
"art": imageFile?.path,
"duration": duration,
};
return {"metadata": metadata, "file": f, "art": imageFile.path};
} catch (e, stack) {
getLogger(FutureProvider).e("[Fetching metadata]", e, stack);
return {
"metadata": <Tag>[],
"file": f,
"duration": Duration.zero,
};
return {};
}
},
),
));
))
.where((e) => e.isNotEmpty)
.toList();
final tracks = filesWithMetadata
.map(
(fileWithMetadata) => TypeConversionUtils.localTrack_X_Track(
fileWithMetadata["metadata"] as List<Tag>,
fileWithMetadata["metadata"] as Metadata,
fileWithMetadata["file"] as File,
fileWithMetadata["duration"] as Duration,
fileWithMetadata["art"] as String?,
),
)

View File

@ -36,7 +36,7 @@ class DownloadTrackButton extends HookConsumerWidget {
useEffect(() {
(() async {
outputFile.value =
File(path.join(preferences.downloadLocation, "$fileName.mp3"));
File(path.join(preferences.downloadLocation, "$fileName.m4a"));
}());
return null;
}, [fileName, track, preferences.downloadLocation]);

View File

@ -12,6 +12,7 @@ extension VideoFromCacheTrackExtension on Video {
cacheTrack.uploadDate != null
? DateTime.tryParse(cacheTrack.uploadDate!)
: null,
cacheTrack.uploadDate,
cacheTrack.publishDate != null
? DateTime.tryParse(cacheTrack.publishDate!)
: null,
@ -69,6 +70,7 @@ extension VideoToJson on Video {
map["author"],
ChannelId(map["channelId"]),
DateTime.tryParse(map["uploadDate"]),
map["uploadDate"],
DateTime.tryParse(map["publishDate"]),
map["description"],
parseDuration(map["duration"]),

View File

@ -1,157 +0,0 @@
import 'package:dart_tags/dart_tags.dart';
class Id3Tags {
Id3Tags({
this.tsse,
this.title,
this.album,
this.tpe2,
this.comment,
this.tcop,
this.tdrc,
this.genre,
this.picture,
});
String? tsse;
String? title;
String? album;
String? tpe2;
Comment? comment;
String? tcop;
String? tdrc;
String? genre;
AttachedPicture? picture;
factory Id3Tags.fromJson(Map<String, dynamic> json) => Id3Tags(
tsse: json["TSSE"],
title: json["title"],
album: json["album"],
tpe2: json["TPE2"],
comment: json["comment"]?["eng:"] is Comment
? json["comment"]["eng:"]
: CommentJson.fromJson(Map.from(
json["comment"]?["eng:"] ?? {},
)),
tcop: json["TCOP"],
tdrc: json["TDRC"],
genre: json["genre"],
picture: json["picture"]?["Cover (front)"] is AttachedPicture
? json["picture"]["Cover (front)"]
: AttachedPictureJson.fromJson(Map.from(
json["picture"]?["Cover (front)"] ?? {},
)),
);
factory Id3Tags.fromId3v1Tags(Id3v1Tags v1tags) => Id3Tags(
album: v1tags.album,
comment: Comment("", "", v1tags.comment ?? ""),
genre: v1tags.genre,
title: v1tags.title,
tcop: v1tags.year,
tdrc: v1tags.year,
tpe2: v1tags.artist,
);
Map<String, dynamic> toJson() => {
"TSSE": tsse,
"title": title,
"album": album,
"TPE2": tpe2,
"comment": comment,
"TCOP": tcop,
"TDRC": tdrc,
"genre": genre,
"picture": picture,
};
String? get artist => tpe2;
String? get year => tdrc;
Map<String, String> toAndroidJson(String artwork) {
return {
"title": title ?? "Unknown",
"artist": artist ?? "Unknown",
"album": album ?? "Unknown",
"genre": genre ?? "Unknown",
"artwork": artwork,
"year": year ?? "Unknown",
};
}
}
extension CommentJson on Comment {
static fromJson(Map<String, dynamic> json) => Comment(
json["lang"] ?? "",
json["description"] ?? "",
json["comment"] ?? "",
);
Map<String, dynamic> toJson() => {
"comment": comment,
"description": description,
"key": key,
"lang": lang,
};
}
extension AttachedPictureJson on AttachedPicture {
static fromJson(Map<String, dynamic> json) => AttachedPicture(
json["mime"] ?? "",
json["imageTypeCode"] ?? 0,
json["description"] ?? "",
List<int>.from(json["imageData"] ?? []),
);
Map<String, dynamic> toJson() => {
"description": description,
"imageData": imageData,
"imageData64": imageData64,
"imageType": imageType,
"imageTypeCode": imageTypeCode,
"key": key,
"mime": mime,
};
}
class Id3v1Tags {
String? title;
String? artist;
String? album;
String? year;
String? comment;
String? track;
String? genre;
Id3v1Tags({
this.title,
this.artist,
this.album,
this.year,
this.comment,
this.track,
this.genre,
});
Id3v1Tags.fromJson(Map<String, dynamic> json) {
title = json['title'];
artist = json['artist'];
album = json['album'];
year = json['year'];
comment = json['comment'];
track = json['track'];
genre = json['genre'];
}
Map<String, dynamic> toJson() {
return {
'title': title,
'artist': artist,
'album': album,
'year': year,
'comment': comment,
'track': track,
'genre': genre,
};
}
}

View File

@ -1,22 +1,19 @@
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:dart_tags/dart_tags.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter/widgets.dart' hide Image;
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:http/http.dart';
import 'package:metadata_god/bridge_generated.dart';
import 'package:metadata_god/metadata_god.dart';
import 'package:queue/queue.dart';
import 'package:path/path.dart' as path;
import 'package:spotify/spotify.dart';
import 'package:spotube/components/Library/UserLocalTracks.dart';
import 'package:spotube/models/Id3Tags.dart';
import 'package:spotify/spotify.dart' hide Image;
import 'package:spotube/models/Logger.dart';
import 'package:spotube/models/SpotubeTrack.dart';
import 'package:spotube/provider/Playback.dart';
import 'package:spotube/provider/UserPreferences.dart';
import 'package:spotube/provider/YouTube.dart';
import 'package:spotube/utils/platform.dart';
import 'package:spotube/utils/type_conversion_utils.dart';
import 'package:youtube_explode_dart/youtube_explode_dart.dart' hide Comment;
@ -63,7 +60,7 @@ class Downloader with ChangeNotifier {
RegExp(r'[/\\?%*:|"<>]'),
"",
);
final filename = '$cleanTitle.mp3';
final filename = '$cleanTitle.m4a';
final file = File(path.join(downloadPath, filename));
try {
logger.v("[addToQueue] Download starting for ${file.path}");
@ -97,9 +94,9 @@ class Downloader with ChangeNotifier {
"[addToQueue] Download of ${file.path} is done successfully",
);
// Tagging isn't supported in Android currently
if (kIsAndroid) return;
logger.v(
"[addToQueue] Writing metadata to ${file.path}",
);
final imageUri = TypeConversionUtils.image_X_UrlString(
track.album?.images ?? [],
);
@ -108,43 +105,30 @@ class Downloader with ChangeNotifier {
imageUri,
),
);
final picture = AttachedPicture.base64(
response.headers["Content-Type"] ?? "image/jpeg",
3,
track.name!,
base64Encode(response.bodyBytes),
);
// write id3 metadata
final tag = Id3Tags(
album: track.album?.name,
picture: picture,
title: track.name,
genre: "Spotube",
tcop: track.ytTrack.uploadDate?.year.toString(),
tdrc: track.ytTrack.uploadDate?.year.toString(),
tpe2: TypeConversionUtils.artists_X_String<Artist>(
track.artists ?? [],
),
tsse: "",
comment: Comment(
"eng",
track.ytTrack.description,
track.ytTrack.title,
await MetadataGod.writeMetadata(
file,
Metadata(
title: track.name,
artist: track.artists?.map((a) => a.name).join(", "),
album: track.album?.name,
albumArtist: track.artists?.map((a) => a.name).join(", "),
year: track.album?.releaseDate != null
? int.tryParse(track.album!.releaseDate!)
: null,
trackNumber: track.trackNumber,
discNumber: track.discNumber,
durationMs: track.durationMs?.toDouble(),
fileSize: file.lengthSync(),
trackTotal: track.album?.tracks?.length,
picture: response.headers['content-type'] != null
? Image(
data: response.bodyBytes,
mimeType: response.headers['content-type']!,
)
: null,
),
);
logger.v("[addToQueue] Writing metadata to ${file.path}");
final taggedMp3 = await tagProcessor.putTagsToByteArray(
file.readAsBytes(),
[
Tag()
..type = "ID3"
..version = "2.4.0"
..tags = tag.toJson()
],
);
await file.writeAsBytes(taggedMp3);
logger.v(
"[addToQueue] Writing metadata to ${file.path} is successful",
);

View File

@ -2,15 +2,13 @@
import 'dart:io';
import 'package:dart_tags/dart_tags.dart';
import 'package:flutter/widgets.dart' hide Image;
import 'package:metadata_god/bridge_generated.dart' hide Image;
import 'package:path/path.dart';
import 'package:spotube/components/Shared/LinkText.dart';
import 'package:spotify/spotify.dart';
import 'package:spotube/models/Id3Tags.dart';
import 'package:spotube/models/SpotubeTrack.dart';
import 'package:spotube/utils/primitive_utils.dart';
import 'package:collection/collection.dart';
import 'package:youtube_explode_dart/youtube_explode_dart.dart';
abstract class TypeConversionUtils {
@ -91,30 +89,23 @@ abstract class TypeConversionUtils {
}
static SpotubeTrack localTrack_X_Track(
List<Tag> metadatas,
Metadata metadata,
File file,
Duration duration,
String? art,
) {
final v2Tags =
metadatas.firstWhereOrNull((s) => s.version == "2.4.0")?.tags;
final v1Tags =
metadatas.firstWhereOrNull((s) => s.version != "2.4.0")?.tags;
final metadata = v2Tags != null
? Id3Tags.fromJson(v2Tags)
: Id3Tags.fromId3v1Tags(Id3v1Tags.fromJson(v1Tags ?? {}));
final track = SpotubeTrack(
Video(
VideoId("dQw4w9WgXcQ"),
basenameWithoutExtension(file.path),
metadata.tpe2 ?? "",
metadata.artist ?? "",
ChannelId(
"https://www.youtube.com/channel/UCuAXFkgsw1L7xaCfnd5JJOw",
),
DateTime.now(),
"",
DateTime.now(),
"",
duration,
Duration(milliseconds: metadata.durationMs?.toInt() ?? 0),
ThumbnailSet(metadata.title ?? ""),
[],
const Engagement(0, 0, 0),
@ -129,22 +120,23 @@ abstract class TypeConversionUtils {
..genres = [if (metadata.genre != null) metadata.genre!]
..artists = [
Artist()
..name = metadata.tpe2 ?? "Spotube"
..id = metadata.tpe2 ?? "Spotube"
..name = metadata.albumArtist ?? "Spotube"
..id = metadata.albumArtist ?? "Spotube"
..type = "artist",
]
..id = metadata.album;
..id = metadata.album
..releaseDate = metadata.year?.toString();
track.artists = [
Artist()
..name = metadata.tpe2 ?? "Spotube"
..id = metadata.tpe2 ?? "Spotube"
..name = metadata.artist ?? "Spotube"
..id = metadata.artist ?? "Spotube"
];
track.id = metadata.title ?? basenameWithoutExtension(file.path);
track.name = metadata.title ?? basenameWithoutExtension(file.path);
track.type = "track";
track.uri = file.path;
track.durationMs = duration.inMilliseconds;
track.durationMs = metadata.durationMs?.toInt();
return track;
}

View File

@ -8,6 +8,7 @@
#include <audioplayers_linux/audioplayers_linux_plugin.h>
#include <bitsdojo_window_linux/bitsdojo_window_plugin.h>
#include <metadata_god/metadata_god_plugin.h>
#include <url_launcher_linux/url_launcher_plugin.h>
void fl_register_plugins(FlPluginRegistry* registry) {
@ -17,6 +18,9 @@ void fl_register_plugins(FlPluginRegistry* registry) {
g_autoptr(FlPluginRegistrar) bitsdojo_window_linux_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "BitsdojoWindowPlugin");
bitsdojo_window_plugin_register_with_registrar(bitsdojo_window_linux_registrar);
g_autoptr(FlPluginRegistrar) metadata_god_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "MetadataGodPlugin");
metadata_god_plugin_register_with_registrar(metadata_god_registrar);
g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin");
url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar);

View File

@ -5,6 +5,7 @@
list(APPEND FLUTTER_PLUGIN_LIST
audioplayers_linux
bitsdojo_window_linux
metadata_god
url_launcher_linux
)

View File

@ -9,6 +9,7 @@ import audio_service
import audio_session
import audioplayers_darwin
import bitsdojo_window_macos
import metadata_god
import package_info_plus_macos
import path_provider_macos
import shared_preferences_macos
@ -20,6 +21,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
AudioSessionPlugin.register(with: registry.registrar(forPlugin: "AudioSessionPlugin"))
AudioplayersDarwinPlugin.register(with: registry.registrar(forPlugin: "AudioplayersDarwinPlugin"))
BitsdojoWindowPlugin.register(with: registry.registrar(forPlugin: "BitsdojoWindowPlugin"))
MetadataGodPlugin.register(with: registry.registrar(forPlugin: "MetadataGodPlugin"))
FLTPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FLTPackageInfoPlusPlugin"))
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))

View File

@ -78,48 +78,6 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "0.0.9"
app_package_parser:
dependency: transitive
description:
name: app_package_parser
url: "https://pub.dartlang.org"
source: hosted
version: "0.0.7"
app_package_parser_apk:
dependency: transitive
description:
name: app_package_parser_apk
url: "https://pub.dartlang.org"
source: hosted
version: "0.0.7"
app_package_parser_ipa:
dependency: transitive
description:
name: app_package_parser_ipa
url: "https://pub.dartlang.org"
source: hosted
version: "0.0.7"
app_package_publisher:
dependency: transitive
description:
name: app_package_publisher
url: "https://pub.dartlang.org"
source: hosted
version: "0.0.9"
app_package_publisher_fir:
dependency: transitive
description:
name: app_package_publisher_fir
url: "https://pub.dartlang.org"
source: hosted
version: "0.0.9"
app_package_publisher_pgyer:
dependency: transitive
description:
name: app_package_publisher_pgyer
url: "https://pub.dartlang.org"
source: hosted
version: "0.0.9"
archive:
dependency: transitive
description:
@ -238,21 +196,21 @@ packages:
name: bitsdojo_window
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.2"
version: "0.1.4"
bitsdojo_window_linux:
dependency: transitive
description:
name: bitsdojo_window_linux
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.2"
version: "0.1.3"
bitsdojo_window_macos:
dependency: transitive
description:
name: bitsdojo_window_macos
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.2"
version: "0.1.3"
bitsdojo_window_platform_interface:
dependency: transitive
description:
@ -266,7 +224,7 @@ packages:
name: bitsdojo_window_windows
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.2"
version: "0.1.4"
boolean_selector:
dependency: transitive
description:
@ -386,20 +344,6 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.16.0"
colorize:
dependency: transitive
description:
name: colorize
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.0"
console_bars:
dependency: transitive
description:
name: console_bars
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.5"
convert:
dependency: transitive
description:
@ -435,27 +379,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "2.2.3"
dart_tags:
dependency: "direct main"
description:
name: dart_tags
url: "https://pub.dartlang.org"
source: hosted
version: "0.4.0"
dbus:
dependency: "direct main"
description:
name: dbus
url: "https://pub.dartlang.org"
source: hosted
version: "0.7.3"
dio:
dependency: transitive
description:
name: dio
url: "https://pub.dartlang.org"
source: hosted
version: "4.0.6"
version: "0.7.8"
dots_indicator:
dependency: transitive
description:
@ -483,7 +413,7 @@ packages:
name: ffi
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.1"
version: "2.0.1"
file:
dependency: transitive
description:
@ -494,10 +424,12 @@ packages:
file_picker:
dependency: "direct main"
description:
name: file_picker
url: "https://pub.dartlang.org"
source: hosted
version: "4.6.1"
path: "."
ref: HEAD
resolved-ref: f9133f6d5dbf33191fc9b58655aebfd15445045a
url: "https://github.com/KRTirtho/flutter_file_picker.git"
source: git
version: "5.0.1"
fixnum:
dependency: transitive
description:
@ -524,13 +456,6 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "0.0.9"
flutter_app_publisher:
dependency: transitive
description:
name: flutter_app_publisher
url: "https://pub.dartlang.org"
source: hosted
version: "0.0.9"
flutter_blurhash:
dependency: transitive
description:
@ -551,7 +476,7 @@ packages:
name: flutter_distributor
url: "https://pub.dartlang.org"
source: hosted
version: "0.0.9"
version: "0.0.2"
flutter_hooks:
dependency: "direct main"
description:
@ -587,6 +512,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.4"
flutter_rust_bridge:
dependency: transitive
description:
name: flutter_rust_bridge
url: "https://pub.dartlang.org"
source: hosted
version: "1.42.0"
flutter_test:
dependency: "direct dev"
description: flutter
@ -603,7 +535,7 @@ packages:
name: freezed_annotation
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0"
version: "2.1.0"
frontend_server_client:
dependency: transitive
description:
@ -695,20 +627,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "4.0.1"
id3:
dependency: "direct main"
description:
name: id3
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.2"
image:
dependency: transitive
description:
name: image
url: "https://pub.dartlang.org"
source: hosted
version: "3.1.3"
version: "3.2.0"
infinite_scroll_pagination:
dependency: transitive
description:
@ -793,6 +718,15 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.8.0"
metadata_god:
dependency: "direct main"
description:
path: "."
ref: HEAD
resolved-ref: "65e3b973213ab8c7495506d13b8e047ecd9fca88"
url: "https://github.com/KRTirtho/metadata_god.git"
source: git
version: "0.0.1"
mime:
dependency: "direct main"
description:
@ -800,13 +734,6 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.2"
mp3_info:
dependency: "direct main"
description:
name: mp3_info
url: "https://pub.dartlang.org"
source: hosted
version: "0.2.0"
msix:
dependency: "direct dev"
description:
@ -841,7 +768,7 @@ packages:
name: package_info_plus
url: "https://pub.dartlang.org"
source: hosted
version: "1.4.2"
version: "1.4.3+1"
package_info_plus_linux:
dependency: transitive
description:
@ -876,7 +803,7 @@ packages:
name: package_info_plus_windows
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.5"
version: "2.0.0"
palette_generator:
dependency: "direct main"
description:
@ -884,13 +811,6 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "0.3.3"
parse_app_package:
dependency: transitive
description:
name: parse_app_package
url: "https://pub.dartlang.org"
source: hosted
version: "0.0.7"
path:
dependency: "direct main"
description:
@ -925,7 +845,7 @@ packages:
name: path_provider_linux
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.6"
version: "2.1.7"
path_provider_macos:
dependency: transitive
description:
@ -946,7 +866,7 @@ packages:
name: path_provider_windows
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.6"
version: "2.1.3"
pedantic:
dependency: transitive
description:
@ -1186,12 +1106,10 @@ packages:
spotify:
dependency: "direct main"
description:
path: "."
ref: HEAD
resolved-ref: ea313e2d21c38157cd8255d248bcd7897bf51360
url: "https://github.com/KRTirtho/spotify-dart.git"
source: git
version: "0.7.0"
name: spotify
url: "https://pub.dartlang.org"
source: hosted
version: "0.8.0"
sqflite:
dependency: transitive
description:
@ -1332,13 +1250,6 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.1"
utf_convert:
dependency: transitive
description:
name: utf_convert
url: "https://pub.dartlang.org"
source: hosted
version: "0.10.0+1"
uuid:
dependency: transitive
description:
@ -1375,12 +1286,12 @@ packages:
source: hosted
version: "2.2.0"
win32:
dependency: transitive
dependency: "direct overridden"
description:
name: win32
url: "https://pub.dartlang.org"
source: hosted
version: "2.6.1"
version: "3.0.0"
xdg_directories:
dependency: transitive
description:
@ -1394,7 +1305,7 @@ packages:
name: xml
url: "https://pub.dartlang.org"
source: hosted
version: "5.4.1"
version: "6.1.0"
yaml:
dependency: transitive
description:
@ -1408,7 +1319,7 @@ packages:
name: youtube_explode_dart
url: "https://pub.dartlang.org"
source: hosted
version: "1.11.0"
version: "1.12.0"
sdks:
dart: ">=2.17.1 <3.0.0"
flutter: ">=3.0.0"

View File

@ -37,11 +37,10 @@ dependencies:
html: ^0.15.0
http: ^0.13.4
shared_preferences: ^2.0.11
spotify:
git: https://github.com/KRTirtho/spotify-dart.git
spotify: ^0.8.0
url_launcher: ^6.0.17
youtube_explode_dart: ^1.10.8
bitsdojo_window: ^0.1.2
bitsdojo_window: 0.1.4
path: ^1.8.0
path_provider: ^2.0.8
collection: ^1.15.0
@ -54,7 +53,7 @@ dependencies:
permission_handler: ^9.2.0
marquee: ^2.2.1
scroll_to_index: ^2.1.1
package_info_plus: ^1.4.2
package_info_plus: ^1.4.3
version: ^2.0.0
audio_service: ^0.18.4
hookified_infinite_scroll_pagination: ^0.1.0
@ -65,15 +64,23 @@ dependencies:
audioplayers: ^1.0.1
introduction_screen: ^3.0.2
audio_session: ^0.1.9
file_picker: ^4.6.1
# This is temporary until the win32v3 update PR is merged and released
file_picker:
git:
url: https://github.com/KRTirtho/flutter_file_picker.git
popover: ^0.2.6+3
queue: ^3.1.0+1
auto_size_text: ^3.0.0
badges: ^2.0.3
mime: ^1.0.2
dart_tags: ^0.4.0
id3: ^1.0.2
mp3_info: ^0.2.0
metadata_god:
git:
url: https://github.com/KRTirtho/metadata_god.git
# Temporary before [package_info_plus_windows] is updated to support
# win32v3
dependency_overrides:
win32: 3.0.0
dev_dependencies:
flutter_test:

View File

@ -8,6 +8,7 @@
#include <audioplayers_windows/audioplayers_windows_plugin.h>
#include <bitsdojo_window_windows/bitsdojo_window_plugin.h>
#include <metadata_god/metadata_god_plugin_c_api.h>
#include <permission_handler_windows/permission_handler_windows_plugin.h>
#include <url_launcher_windows/url_launcher_windows.h>
@ -16,6 +17,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) {
registry->GetRegistrarForPlugin("AudioplayersWindowsPlugin"));
BitsdojoWindowPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("BitsdojoWindowPlugin"));
MetadataGodPluginCApiRegisterWithRegistrar(
registry->GetRegistrarForPlugin("MetadataGodPluginCApi"));
PermissionHandlerWindowsPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("PermissionHandlerWindowsPlugin"));
UrlLauncherWindowsRegisterWithRegistrar(

View File

@ -5,6 +5,7 @@
list(APPEND FLUTTER_PLUGIN_LIST
audioplayers_windows
bitsdojo_window_windows
metadata_god
permission_handler_windows
url_launcher_windows
)