mirror of
https://github.com/KRTirtho/spotube.git
synced 2025-12-05 23:19:42 +00:00
feat: add plugin audio source models and api service
This commit is contained in:
parent
88699e9a3b
commit
439de5d7f7
84
lib/models/metadata/audio_source.dart
Normal file
84
lib/models/metadata/audio_source.dart
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
part of 'metadata.dart';
|
||||||
|
|
||||||
|
enum SpotubeMediaCompressionType {
|
||||||
|
lossy,
|
||||||
|
lossless,
|
||||||
|
}
|
||||||
|
|
||||||
|
@Freezed(unionKey: 'type')
|
||||||
|
class SpotubeAudioSourceContainerPreset
|
||||||
|
with _$SpotubeAudioSourceContainerPreset {
|
||||||
|
@FreezedUnionValue("lossy")
|
||||||
|
factory SpotubeAudioSourceContainerPreset.lossy({
|
||||||
|
required SpotubeMediaCompressionType type,
|
||||||
|
required String name,
|
||||||
|
required List<SpotubeAudioLossyContainerQuality> qualities,
|
||||||
|
}) = SpotubeAudioSourceContainerPresetLossy;
|
||||||
|
|
||||||
|
@FreezedUnionValue("lossless")
|
||||||
|
factory SpotubeAudioSourceContainerPreset.lossless({
|
||||||
|
required SpotubeMediaCompressionType type,
|
||||||
|
required String name,
|
||||||
|
required List<SpotubeAudioLosslessContainerQuality> qualities,
|
||||||
|
}) = SpotubeAudioSourceContainerPresetLossless;
|
||||||
|
|
||||||
|
factory SpotubeAudioSourceContainerPreset.fromJson(
|
||||||
|
Map<String, dynamic> json) =>
|
||||||
|
_$SpotubeAudioSourceContainerPresetFromJson(json);
|
||||||
|
}
|
||||||
|
|
||||||
|
@freezed
|
||||||
|
class SpotubeAudioLossyContainerQuality
|
||||||
|
with _$SpotubeAudioLossyContainerQuality {
|
||||||
|
factory SpotubeAudioLossyContainerQuality({
|
||||||
|
required double bitrate,
|
||||||
|
}) = _SpotubeAudioLossyContainerQuality;
|
||||||
|
|
||||||
|
factory SpotubeAudioLossyContainerQuality.fromJson(
|
||||||
|
Map<String, dynamic> json) =>
|
||||||
|
_$SpotubeAudioLossyContainerQualityFromJson(json);
|
||||||
|
}
|
||||||
|
|
||||||
|
@freezed
|
||||||
|
class SpotubeAudioLosslessContainerQuality
|
||||||
|
with _$SpotubeAudioLosslessContainerQuality {
|
||||||
|
factory SpotubeAudioLosslessContainerQuality({
|
||||||
|
required int bitDepth,
|
||||||
|
required double sampleRate,
|
||||||
|
}) = _SpotubeAudioLosslessContainerQuality;
|
||||||
|
|
||||||
|
factory SpotubeAudioLosslessContainerQuality.fromJson(
|
||||||
|
Map<String, dynamic> json) =>
|
||||||
|
_$SpotubeAudioLosslessContainerQualityFromJson(json);
|
||||||
|
}
|
||||||
|
|
||||||
|
@freezed
|
||||||
|
class SpotubeAudioSourceMatchObject with _$SpotubeAudioSourceMatchObject {
|
||||||
|
factory SpotubeAudioSourceMatchObject({
|
||||||
|
required String id,
|
||||||
|
required String title,
|
||||||
|
required List<String> artists,
|
||||||
|
required Duration duration,
|
||||||
|
String? thumbnail,
|
||||||
|
required String externalUri,
|
||||||
|
}) = _SpotubeAudioSourceMatchObject;
|
||||||
|
|
||||||
|
factory SpotubeAudioSourceMatchObject.fromJson(Map<String, dynamic> json) =>
|
||||||
|
_$SpotubeAudioSourceMatchObjectFromJson(json);
|
||||||
|
}
|
||||||
|
|
||||||
|
@freezed
|
||||||
|
class SpotubeAudioSourceStreamObject with _$SpotubeAudioSourceStreamObject {
|
||||||
|
factory SpotubeAudioSourceStreamObject({
|
||||||
|
required String url,
|
||||||
|
required String container,
|
||||||
|
required SpotubeMediaCompressionType type,
|
||||||
|
String? codec,
|
||||||
|
double? bitrate,
|
||||||
|
int? bitDepth,
|
||||||
|
double? sampleRate,
|
||||||
|
}) = _SpotubeAudioSourceStreamObject;
|
||||||
|
|
||||||
|
factory SpotubeAudioSourceStreamObject.fromJson(Map<String, dynamic> json) =>
|
||||||
|
_$SpotubeAudioSourceStreamObjectFromJson(json);
|
||||||
|
}
|
||||||
@ -15,6 +15,7 @@ import 'package:spotube/utils/primitive_utils.dart';
|
|||||||
part 'metadata.g.dart';
|
part 'metadata.g.dart';
|
||||||
part 'metadata.freezed.dart';
|
part 'metadata.freezed.dart';
|
||||||
|
|
||||||
|
part 'audio_source.dart';
|
||||||
part 'album.dart';
|
part 'album.dart';
|
||||||
part 'artist.dart';
|
part 'artist.dart';
|
||||||
part 'browse.dart';
|
part 'browse.dart';
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -6,6 +6,123 @@ part of 'metadata.dart';
|
|||||||
// JsonSerializableGenerator
|
// JsonSerializableGenerator
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
|
_$SpotubeAudioSourceContainerPresetLossyImpl
|
||||||
|
_$$SpotubeAudioSourceContainerPresetLossyImplFromJson(Map json) =>
|
||||||
|
_$SpotubeAudioSourceContainerPresetLossyImpl(
|
||||||
|
type: $enumDecode(_$SpotubeMediaCompressionTypeEnumMap, json['type']),
|
||||||
|
name: json['name'] as String,
|
||||||
|
qualities: (json['qualities'] as List<dynamic>)
|
||||||
|
.map((e) => SpotubeAudioLossyContainerQuality.fromJson(
|
||||||
|
Map<String, dynamic>.from(e as Map)))
|
||||||
|
.toList(),
|
||||||
|
);
|
||||||
|
|
||||||
|
Map<String, dynamic> _$$SpotubeAudioSourceContainerPresetLossyImplToJson(
|
||||||
|
_$SpotubeAudioSourceContainerPresetLossyImpl instance) =>
|
||||||
|
<String, dynamic>{
|
||||||
|
'type': _$SpotubeMediaCompressionTypeEnumMap[instance.type]!,
|
||||||
|
'name': instance.name,
|
||||||
|
'qualities': instance.qualities.map((e) => e.toJson()).toList(),
|
||||||
|
};
|
||||||
|
|
||||||
|
const _$SpotubeMediaCompressionTypeEnumMap = {
|
||||||
|
SpotubeMediaCompressionType.lossy: 'lossy',
|
||||||
|
SpotubeMediaCompressionType.lossless: 'lossless',
|
||||||
|
};
|
||||||
|
|
||||||
|
_$SpotubeAudioSourceContainerPresetLosslessImpl
|
||||||
|
_$$SpotubeAudioSourceContainerPresetLosslessImplFromJson(Map json) =>
|
||||||
|
_$SpotubeAudioSourceContainerPresetLosslessImpl(
|
||||||
|
type: $enumDecode(_$SpotubeMediaCompressionTypeEnumMap, json['type']),
|
||||||
|
name: json['name'] as String,
|
||||||
|
qualities: (json['qualities'] as List<dynamic>)
|
||||||
|
.map((e) => SpotubeAudioLosslessContainerQuality.fromJson(
|
||||||
|
Map<String, dynamic>.from(e as Map)))
|
||||||
|
.toList(),
|
||||||
|
);
|
||||||
|
|
||||||
|
Map<String, dynamic> _$$SpotubeAudioSourceContainerPresetLosslessImplToJson(
|
||||||
|
_$SpotubeAudioSourceContainerPresetLosslessImpl instance) =>
|
||||||
|
<String, dynamic>{
|
||||||
|
'type': _$SpotubeMediaCompressionTypeEnumMap[instance.type]!,
|
||||||
|
'name': instance.name,
|
||||||
|
'qualities': instance.qualities.map((e) => e.toJson()).toList(),
|
||||||
|
};
|
||||||
|
|
||||||
|
_$SpotubeAudioLossyContainerQualityImpl
|
||||||
|
_$$SpotubeAudioLossyContainerQualityImplFromJson(Map json) =>
|
||||||
|
_$SpotubeAudioLossyContainerQualityImpl(
|
||||||
|
bitrate: (json['bitrate'] as num).toDouble(),
|
||||||
|
);
|
||||||
|
|
||||||
|
Map<String, dynamic> _$$SpotubeAudioLossyContainerQualityImplToJson(
|
||||||
|
_$SpotubeAudioLossyContainerQualityImpl instance) =>
|
||||||
|
<String, dynamic>{
|
||||||
|
'bitrate': instance.bitrate,
|
||||||
|
};
|
||||||
|
|
||||||
|
_$SpotubeAudioLosslessContainerQualityImpl
|
||||||
|
_$$SpotubeAudioLosslessContainerQualityImplFromJson(Map json) =>
|
||||||
|
_$SpotubeAudioLosslessContainerQualityImpl(
|
||||||
|
bitDepth: (json['bitDepth'] as num).toInt(),
|
||||||
|
sampleRate: (json['sampleRate'] as num).toDouble(),
|
||||||
|
);
|
||||||
|
|
||||||
|
Map<String, dynamic> _$$SpotubeAudioLosslessContainerQualityImplToJson(
|
||||||
|
_$SpotubeAudioLosslessContainerQualityImpl instance) =>
|
||||||
|
<String, dynamic>{
|
||||||
|
'bitDepth': instance.bitDepth,
|
||||||
|
'sampleRate': instance.sampleRate,
|
||||||
|
};
|
||||||
|
|
||||||
|
_$SpotubeAudioSourceMatchObjectImpl
|
||||||
|
_$$SpotubeAudioSourceMatchObjectImplFromJson(Map json) =>
|
||||||
|
_$SpotubeAudioSourceMatchObjectImpl(
|
||||||
|
id: json['id'] as String,
|
||||||
|
title: json['title'] as String,
|
||||||
|
artists: (json['artists'] as List<dynamic>)
|
||||||
|
.map((e) => e as String)
|
||||||
|
.toList(),
|
||||||
|
duration: Duration(microseconds: (json['duration'] as num).toInt()),
|
||||||
|
thumbnail: json['thumbnail'] as String?,
|
||||||
|
externalUri: json['externalUri'] as String,
|
||||||
|
);
|
||||||
|
|
||||||
|
Map<String, dynamic> _$$SpotubeAudioSourceMatchObjectImplToJson(
|
||||||
|
_$SpotubeAudioSourceMatchObjectImpl instance) =>
|
||||||
|
<String, dynamic>{
|
||||||
|
'id': instance.id,
|
||||||
|
'title': instance.title,
|
||||||
|
'artists': instance.artists,
|
||||||
|
'duration': instance.duration.inMicroseconds,
|
||||||
|
'thumbnail': instance.thumbnail,
|
||||||
|
'externalUri': instance.externalUri,
|
||||||
|
};
|
||||||
|
|
||||||
|
_$SpotubeAudioSourceStreamObjectImpl
|
||||||
|
_$$SpotubeAudioSourceStreamObjectImplFromJson(Map json) =>
|
||||||
|
_$SpotubeAudioSourceStreamObjectImpl(
|
||||||
|
url: json['url'] as String,
|
||||||
|
container: json['container'] as String,
|
||||||
|
type: $enumDecode(_$SpotubeMediaCompressionTypeEnumMap, json['type']),
|
||||||
|
codec: json['codec'] as String?,
|
||||||
|
bitrate: (json['bitrate'] as num?)?.toDouble(),
|
||||||
|
bitDepth: (json['bitDepth'] as num?)?.toInt(),
|
||||||
|
sampleRate: (json['sampleRate'] as num?)?.toDouble(),
|
||||||
|
);
|
||||||
|
|
||||||
|
Map<String, dynamic> _$$SpotubeAudioSourceStreamObjectImplToJson(
|
||||||
|
_$SpotubeAudioSourceStreamObjectImpl instance) =>
|
||||||
|
<String, dynamic>{
|
||||||
|
'url': instance.url,
|
||||||
|
'container': instance.container,
|
||||||
|
'type': _$SpotubeMediaCompressionTypeEnumMap[instance.type]!,
|
||||||
|
'codec': instance.codec,
|
||||||
|
'bitrate': instance.bitrate,
|
||||||
|
'bitDepth': instance.bitDepth,
|
||||||
|
'sampleRate': instance.sampleRate,
|
||||||
|
};
|
||||||
|
|
||||||
_$SpotubeFullAlbumObjectImpl _$$SpotubeFullAlbumObjectImplFromJson(Map json) =>
|
_$SpotubeFullAlbumObjectImpl _$$SpotubeFullAlbumObjectImplFromJson(Map json) =>
|
||||||
_$SpotubeFullAlbumObjectImpl(
|
_$SpotubeFullAlbumObjectImpl(
|
||||||
id: json['id'] as String,
|
id: json['id'] as String,
|
||||||
@ -419,7 +536,6 @@ Map<String, dynamic> _$$SpotubeUserObjectImplToJson(
|
|||||||
|
|
||||||
_$PluginConfigurationImpl _$$PluginConfigurationImplFromJson(Map json) =>
|
_$PluginConfigurationImpl _$$PluginConfigurationImplFromJson(Map json) =>
|
||||||
_$PluginConfigurationImpl(
|
_$PluginConfigurationImpl(
|
||||||
type: $enumDecode(_$PluginTypeEnumMap, json['type']),
|
|
||||||
name: json['name'] as String,
|
name: json['name'] as String,
|
||||||
description: json['description'] as String,
|
description: json['description'] as String,
|
||||||
version: json['version'] as String,
|
version: json['version'] as String,
|
||||||
@ -440,7 +556,6 @@ _$PluginConfigurationImpl _$$PluginConfigurationImplFromJson(Map json) =>
|
|||||||
Map<String, dynamic> _$$PluginConfigurationImplToJson(
|
Map<String, dynamic> _$$PluginConfigurationImplToJson(
|
||||||
_$PluginConfigurationImpl instance) =>
|
_$PluginConfigurationImpl instance) =>
|
||||||
<String, dynamic>{
|
<String, dynamic>{
|
||||||
'type': _$PluginTypeEnumMap[instance.type]!,
|
|
||||||
'name': instance.name,
|
'name': instance.name,
|
||||||
'description': instance.description,
|
'description': instance.description,
|
||||||
'version': instance.version,
|
'version': instance.version,
|
||||||
@ -453,10 +568,6 @@ Map<String, dynamic> _$$PluginConfigurationImplToJson(
|
|||||||
'repository': instance.repository,
|
'repository': instance.repository,
|
||||||
};
|
};
|
||||||
|
|
||||||
const _$PluginTypeEnumMap = {
|
|
||||||
PluginType.metadata: 'metadata',
|
|
||||||
};
|
|
||||||
|
|
||||||
const _$PluginApisEnumMap = {
|
const _$PluginApisEnumMap = {
|
||||||
PluginApis.webview: 'webview',
|
PluginApis.webview: 'webview',
|
||||||
PluginApis.localstorage: 'localstorage',
|
PluginApis.localstorage: 'localstorage',
|
||||||
@ -466,6 +577,8 @@ const _$PluginApisEnumMap = {
|
|||||||
const _$PluginAbilitiesEnumMap = {
|
const _$PluginAbilitiesEnumMap = {
|
||||||
PluginAbilities.authentication: 'authentication',
|
PluginAbilities.authentication: 'authentication',
|
||||||
PluginAbilities.scrobbling: 'scrobbling',
|
PluginAbilities.scrobbling: 'scrobbling',
|
||||||
|
PluginAbilities.metadata: 'metadata',
|
||||||
|
PluginAbilities.audioSource: 'audio-source',
|
||||||
};
|
};
|
||||||
|
|
||||||
_$PluginUpdateAvailableImpl _$$PluginUpdateAvailableImplFromJson(Map json) =>
|
_$PluginUpdateAvailableImpl _$$PluginUpdateAvailableImplFromJson(Map json) =>
|
||||||
|
|||||||
@ -1,17 +1,20 @@
|
|||||||
part of 'metadata.dart';
|
part of 'metadata.dart';
|
||||||
|
|
||||||
enum PluginType { metadata }
|
|
||||||
|
|
||||||
enum PluginApis { webview, localstorage, timezone }
|
enum PluginApis { webview, localstorage, timezone }
|
||||||
|
|
||||||
enum PluginAbilities { authentication, scrobbling }
|
enum PluginAbilities {
|
||||||
|
authentication,
|
||||||
|
scrobbling,
|
||||||
|
metadata,
|
||||||
|
@JsonValue('audio-source')
|
||||||
|
audioSource,
|
||||||
|
}
|
||||||
|
|
||||||
@freezed
|
@freezed
|
||||||
class PluginConfiguration with _$PluginConfiguration {
|
class PluginConfiguration with _$PluginConfiguration {
|
||||||
const PluginConfiguration._();
|
const PluginConfiguration._();
|
||||||
|
|
||||||
factory PluginConfiguration({
|
factory PluginConfiguration({
|
||||||
required PluginType type,
|
|
||||||
required String name,
|
required String name,
|
||||||
required String description,
|
required String description,
|
||||||
required String version,
|
required String version,
|
||||||
|
|||||||
@ -10,6 +10,7 @@ import 'package:path_provider/path_provider.dart';
|
|||||||
import 'package:spotube/models/database/database.dart';
|
import 'package:spotube/models/database/database.dart';
|
||||||
import 'package:spotube/models/metadata/metadata.dart';
|
import 'package:spotube/models/metadata/metadata.dart';
|
||||||
import 'package:spotube/provider/database/database.dart';
|
import 'package:spotube/provider/database/database.dart';
|
||||||
|
import 'package:spotube/provider/youtube_engine/youtube_engine.dart';
|
||||||
import 'package:spotube/services/dio/dio.dart';
|
import 'package:spotube/services/dio/dio.dart';
|
||||||
import 'package:spotube/services/logger/logger.dart';
|
import 'package:spotube/services/logger/logger.dart';
|
||||||
import 'package:spotube/services/metadata/errors/exceptions.dart';
|
import 'package:spotube/services/metadata/errors/exceptions.dart';
|
||||||
@ -97,7 +98,6 @@ class MetadataPluginNotifier extends AsyncNotifier<MetadataPluginState> {
|
|||||||
final plugin = plugins[i];
|
final plugin = plugins[i];
|
||||||
|
|
||||||
final pluginConfig = PluginConfiguration(
|
final pluginConfig = PluginConfiguration(
|
||||||
type: PluginType.metadata,
|
|
||||||
name: plugin.name,
|
name: plugin.name,
|
||||||
author: plugin.author,
|
author: plugin.author,
|
||||||
description: plugin.description,
|
description: plugin.description,
|
||||||
@ -447,6 +447,7 @@ final metadataPluginProvider = FutureProvider<MetadataPlugin?>(
|
|||||||
final defaultPlugin = await ref.watch(
|
final defaultPlugin = await ref.watch(
|
||||||
metadataPluginsProvider.selectAsync((data) => data.defaultPluginConfig),
|
metadataPluginsProvider.selectAsync((data) => data.defaultPluginConfig),
|
||||||
);
|
);
|
||||||
|
final youtubeEngine = ref.read(youtubeEngineProvider);
|
||||||
|
|
||||||
if (defaultPlugin == null) {
|
if (defaultPlugin == null) {
|
||||||
return null;
|
return null;
|
||||||
@ -456,6 +457,10 @@ final metadataPluginProvider = FutureProvider<MetadataPlugin?>(
|
|||||||
final pluginByteCode =
|
final pluginByteCode =
|
||||||
await pluginsNotifier.getPluginByteCode(defaultPlugin);
|
await pluginsNotifier.getPluginByteCode(defaultPlugin);
|
||||||
|
|
||||||
return await MetadataPlugin.create(defaultPlugin, pluginByteCode);
|
return await MetadataPlugin.create(
|
||||||
|
youtubeEngine,
|
||||||
|
defaultPlugin,
|
||||||
|
pluginByteCode,
|
||||||
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|||||||
38
lib/services/metadata/endpoints/audio_source.dart
Normal file
38
lib/services/metadata/endpoints/audio_source.dart
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
import 'package:hetu_script/hetu_script.dart';
|
||||||
|
import 'package:hetu_script/values.dart';
|
||||||
|
import 'package:spotube/models/metadata/metadata.dart';
|
||||||
|
|
||||||
|
class MetadataPluginAudioSourceEndpoint {
|
||||||
|
final Hetu hetu;
|
||||||
|
MetadataPluginAudioSourceEndpoint(this.hetu);
|
||||||
|
|
||||||
|
HTInstance get hetuMetadataAudioSource =>
|
||||||
|
(hetu.fetch("metadataPlugin") as HTInstance).memberGet("audioSource")
|
||||||
|
as HTInstance;
|
||||||
|
|
||||||
|
List<SpotubeAudioSourceContainerPreset> get supportedPresets {
|
||||||
|
final raw = hetuMetadataAudioSource.memberGet("supportedPresets") as List;
|
||||||
|
|
||||||
|
return raw
|
||||||
|
.map((e) => SpotubeAudioSourceContainerPreset.fromJson(e))
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<List<SpotubeAudioSourceMatchObject>> matches(
|
||||||
|
SpotubeFullTrackObject track,
|
||||||
|
) async {
|
||||||
|
final raw = await hetuMetadataAudioSource
|
||||||
|
.invoke("matches", positionalArgs: [track]) as List;
|
||||||
|
|
||||||
|
return raw.map((e) => SpotubeAudioSourceMatchObject.fromJson(e)).toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<List<SpotubeAudioSourceStreamObject>> streams(
|
||||||
|
SpotubeAudioSourceMatchObject match,
|
||||||
|
) async {
|
||||||
|
final raw = await hetuMetadataAudioSource
|
||||||
|
.invoke("streams", positionalArgs: [match]) as List;
|
||||||
|
|
||||||
|
return raw.map((e) => SpotubeAudioSourceStreamObject.fromJson(e)).toList();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -3,7 +3,9 @@ import 'dart:typed_data';
|
|||||||
import 'package:auto_route/auto_route.dart';
|
import 'package:auto_route/auto_route.dart';
|
||||||
import 'package:hetu_otp_util/hetu_otp_util.dart';
|
import 'package:hetu_otp_util/hetu_otp_util.dart';
|
||||||
import 'package:hetu_script/hetu_script.dart';
|
import 'package:hetu_script/hetu_script.dart';
|
||||||
import 'package:hetu_spotube_plugin/hetu_spotube_plugin.dart';
|
import 'package:hetu_spotube_plugin/hetu_spotube_plugin.dart' as spotube_plugin;
|
||||||
|
import 'package:hetu_spotube_plugin/hetu_spotube_plugin.dart'
|
||||||
|
hide YouTubeEngine;
|
||||||
import 'package:hetu_std/hetu_std.dart';
|
import 'package:hetu_std/hetu_std.dart';
|
||||||
import 'package:pub_semver/pub_semver.dart';
|
import 'package:pub_semver/pub_semver.dart';
|
||||||
import 'package:shadcn_flutter/shadcn_flutter.dart';
|
import 'package:shadcn_flutter/shadcn_flutter.dart';
|
||||||
@ -15,6 +17,7 @@ import 'package:spotube/models/metadata/metadata.dart';
|
|||||||
import 'package:spotube/services/metadata/apis/localstorage.dart';
|
import 'package:spotube/services/metadata/apis/localstorage.dart';
|
||||||
import 'package:spotube/services/metadata/endpoints/album.dart';
|
import 'package:spotube/services/metadata/endpoints/album.dart';
|
||||||
import 'package:spotube/services/metadata/endpoints/artist.dart';
|
import 'package:spotube/services/metadata/endpoints/artist.dart';
|
||||||
|
import 'package:spotube/services/metadata/endpoints/audio_source.dart';
|
||||||
import 'package:spotube/services/metadata/endpoints/auth.dart';
|
import 'package:spotube/services/metadata/endpoints/auth.dart';
|
||||||
import 'package:spotube/services/metadata/endpoints/browse.dart';
|
import 'package:spotube/services/metadata/endpoints/browse.dart';
|
||||||
import 'package:spotube/services/metadata/endpoints/playlist.dart';
|
import 'package:spotube/services/metadata/endpoints/playlist.dart';
|
||||||
@ -22,13 +25,15 @@ import 'package:spotube/services/metadata/endpoints/search.dart';
|
|||||||
import 'package:spotube/services/metadata/endpoints/track.dart';
|
import 'package:spotube/services/metadata/endpoints/track.dart';
|
||||||
import 'package:spotube/services/metadata/endpoints/core.dart';
|
import 'package:spotube/services/metadata/endpoints/core.dart';
|
||||||
import 'package:spotube/services/metadata/endpoints/user.dart';
|
import 'package:spotube/services/metadata/endpoints/user.dart';
|
||||||
|
import 'package:spotube/services/youtube_engine/youtube_engine.dart';
|
||||||
|
|
||||||
const defaultMetadataLimit = "20";
|
const defaultMetadataLimit = "20";
|
||||||
|
|
||||||
class MetadataPlugin {
|
class MetadataPlugin {
|
||||||
static final pluginApiVersion = Version.parse("1.0.0");
|
static final pluginApiVersion = Version.parse("2.0.0");
|
||||||
|
|
||||||
static Future<MetadataPlugin> create(
|
static Future<MetadataPlugin> create(
|
||||||
|
YouTubeEngine youtubeEngine,
|
||||||
PluginConfiguration config,
|
PluginConfiguration config,
|
||||||
Uint8List byteCode,
|
Uint8List byteCode,
|
||||||
) async {
|
) async {
|
||||||
@ -76,6 +81,58 @@ class MetadataPlugin {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
createYoutubeEngine: () {
|
||||||
|
return spotube_plugin.YouTubeEngine(
|
||||||
|
search: (query) async {
|
||||||
|
final result = await youtubeEngine.searchVideos(query);
|
||||||
|
return result
|
||||||
|
.map((video) => {
|
||||||
|
'id': video.id.value,
|
||||||
|
'title': video.title,
|
||||||
|
'author': video.author,
|
||||||
|
'duration': video.duration?.inSeconds,
|
||||||
|
'description': video.description,
|
||||||
|
'uploadDate': video.uploadDate?.toIso8601String(),
|
||||||
|
'viewCount': video.engagement.viewCount,
|
||||||
|
'likeCount': video.engagement.likeCount,
|
||||||
|
'isLive': video.isLive,
|
||||||
|
})
|
||||||
|
.toList();
|
||||||
|
},
|
||||||
|
getVideo: (videoId) async {
|
||||||
|
final video = await youtubeEngine.getVideo(videoId);
|
||||||
|
return {
|
||||||
|
'id': video.id.value,
|
||||||
|
'title': video.title,
|
||||||
|
'author': video.author,
|
||||||
|
'duration': video.duration?.inSeconds,
|
||||||
|
'description': video.description,
|
||||||
|
'uploadDate': video.uploadDate?.toIso8601String(),
|
||||||
|
'viewCount': video.engagement.viewCount,
|
||||||
|
'likeCount': video.engagement.likeCount,
|
||||||
|
'isLive': video.isLive,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
streamManifest: (videoId) {
|
||||||
|
return youtubeEngine.getStreamManifest(videoId).then(
|
||||||
|
(manifest) {
|
||||||
|
final streams = manifest.audioOnly
|
||||||
|
.map(
|
||||||
|
(stream) => {
|
||||||
|
'url': stream.url.toString(),
|
||||||
|
'quality': stream.qualityLabel,
|
||||||
|
'bitrate': stream.bitrate.bitsPerSecond,
|
||||||
|
'container': stream.container.name,
|
||||||
|
'videoId': stream.videoId,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.toList();
|
||||||
|
return streams;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
await HetuStdLoader.loadBytecodeFlutter(hetu);
|
await HetuStdLoader.loadBytecodeFlutter(hetu);
|
||||||
@ -98,6 +155,7 @@ class MetadataPlugin {
|
|||||||
|
|
||||||
late final MetadataAuthEndpoint auth;
|
late final MetadataAuthEndpoint auth;
|
||||||
|
|
||||||
|
late final MetadataPluginAudioSourceEndpoint audioSource;
|
||||||
late final MetadataPluginAlbumEndpoint album;
|
late final MetadataPluginAlbumEndpoint album;
|
||||||
late final MetadataPluginArtistEndpoint artist;
|
late final MetadataPluginArtistEndpoint artist;
|
||||||
late final MetadataPluginBrowseEndpoint browse;
|
late final MetadataPluginBrowseEndpoint browse;
|
||||||
@ -110,6 +168,7 @@ class MetadataPlugin {
|
|||||||
MetadataPlugin._(this.hetu) {
|
MetadataPlugin._(this.hetu) {
|
||||||
auth = MetadataAuthEndpoint(hetu);
|
auth = MetadataAuthEndpoint(hetu);
|
||||||
|
|
||||||
|
audioSource = MetadataPluginAudioSourceEndpoint(hetu);
|
||||||
artist = MetadataPluginArtistEndpoint(hetu);
|
artist = MetadataPluginArtistEndpoint(hetu);
|
||||||
album = MetadataPluginAlbumEndpoint(hetu);
|
album = MetadataPluginAlbumEndpoint(hetu);
|
||||||
browse = MetadataPluginBrowseEndpoint(hetu);
|
browse = MetadataPluginBrowseEndpoint(hetu);
|
||||||
|
|||||||
13
pubspec.lock
13
pubspec.lock
@ -1230,10 +1230,10 @@ packages:
|
|||||||
description:
|
description:
|
||||||
path: "."
|
path: "."
|
||||||
ref: main
|
ref: main
|
||||||
resolved-ref: "01935a75640092af7947bfb21a497240376f0c83"
|
resolved-ref: "32828156bc111d147709f8d644804227bbdfe8f1"
|
||||||
url: "https://github.com/KRTirtho/hetu_spotube_plugin.git"
|
url: "https://github.com/KRTirtho/hetu_spotube_plugin.git"
|
||||||
source: git
|
source: git
|
||||||
version: "0.0.1"
|
version: "0.0.2"
|
||||||
hetu_std:
|
hetu_std:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -2888,10 +2888,11 @@ packages:
|
|||||||
youtube_explode_dart:
|
youtube_explode_dart:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: youtube_explode_dart
|
path: "."
|
||||||
sha256: "9ff345caf8351c59eb1b7560837f761e08d2beaea3b4187637942715a31a6f58"
|
ref: HEAD
|
||||||
url: "https://pub.dev"
|
resolved-ref: caa3023386dbc10e69c99f49f491148094874671
|
||||||
source: hosted
|
url: "https://github.com/Coronon/youtube_explode_dart"
|
||||||
|
source: git
|
||||||
version: "2.5.2"
|
version: "2.5.2"
|
||||||
yt_dlp_dart:
|
yt_dlp_dart:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
|
|||||||
@ -138,7 +138,8 @@ dependencies:
|
|||||||
wikipedia_api: ^0.1.0
|
wikipedia_api: ^0.1.0
|
||||||
win32_registry: ^1.1.5
|
win32_registry: ^1.1.5
|
||||||
window_manager: ^0.4.3
|
window_manager: ^0.4.3
|
||||||
youtube_explode_dart: ^2.5.1
|
youtube_explode_dart:
|
||||||
|
git: https://github.com/Coronon/youtube_explode_dart
|
||||||
yt_dlp_dart:
|
yt_dlp_dart:
|
||||||
git:
|
git:
|
||||||
url: https://github.com/KRTirtho/yt_dlp_dart.git
|
url: https://github.com/KRTirtho/yt_dlp_dart.git
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user