mirror of
https://github.com/GopeedLab/gopeed.git
synced 2026-11-07 17:10:29 +00:00
feat: extension store (#1301)
This commit is contained in:
12 files changed
+1791
-425
No files matched your search
@@ -200,10 +200,10 @@ Future<void> putConfig(DownloaderConfig config) async {
|
||||
return _parse(() => _client.dio.put("api/v1/config", data: config), null);
|
||||
}
|
||||
|
||||
Future<void> installExtension(InstallExtension installExtension) async {
|
||||
return _parse(
|
||||
Future<String> installExtension(InstallExtension installExtension) async {
|
||||
return _parse<String>(
|
||||
() => _client.dio.post("api/v1/extensions", data: installExtension),
|
||||
null);
|
||||
(data) => data as String);
|
||||
}
|
||||
|
||||
Future<List<Extension>> getExtensions() async {
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:dio/dio.dart';
|
||||
|
||||
import 'api.dart';
|
||||
import 'model/store_extension.dart';
|
||||
|
||||
class GopeedSiteApi {
|
||||
GopeedSiteApi._();
|
||||
|
||||
static final instance = GopeedSiteApi._();
|
||||
|
||||
static const _host = 'gopeed.com';
|
||||
|
||||
Future<Map<String, dynamic>> getRelease() async {
|
||||
final json = await _getJson('/api/release');
|
||||
return json as Map<String, dynamic>;
|
||||
}
|
||||
|
||||
Future<StoreExtensionPage> getExtensions({
|
||||
int page = 1,
|
||||
int limit = 20,
|
||||
StoreExtensionSort sort = StoreExtensionSort.stars,
|
||||
StoreSortOrder order = StoreSortOrder.desc,
|
||||
String? query,
|
||||
}) async {
|
||||
final json = await _getJson('/api/extensions', queryParameters: {
|
||||
'page': page.toString(),
|
||||
'limit': limit.clamp(1, 100).toString(),
|
||||
'sort': sort.name,
|
||||
'order': order.name,
|
||||
if (query != null && query.trim().isNotEmpty) 'q': query.trim(),
|
||||
});
|
||||
return StoreExtensionPage.fromJson(json as Map<String, dynamic>);
|
||||
}
|
||||
|
||||
Future<void> reportExtensionInstall(String id) async {
|
||||
final uri = Uri.https(_host, '/api/extensions/install');
|
||||
await proxyRequest(
|
||||
uri.toString(),
|
||||
data: {'id': id},
|
||||
options: Options(method: 'POST', contentType: Headers.jsonContentType),
|
||||
);
|
||||
}
|
||||
|
||||
Future<dynamic> _getJson(String path,
|
||||
{Map<String, String>? queryParameters}) async {
|
||||
final uri = Uri.https(_host, path, queryParameters);
|
||||
final Response<String> response = await proxyRequest(uri.toString());
|
||||
if (response.data == null || response.data!.isEmpty) {
|
||||
throw Exception('Empty response from $uri');
|
||||
}
|
||||
return jsonDecode(response.data!);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
import 'dart:convert';
|
||||
|
||||
class StoreExtensionPage {
|
||||
final List<StoreExtension> data;
|
||||
final StorePagination pagination;
|
||||
|
||||
StoreExtensionPage({required this.data, required this.pagination});
|
||||
|
||||
factory StoreExtensionPage.fromJson(Map<String, dynamic> json) {
|
||||
return StoreExtensionPage(
|
||||
data: (json['data'] as List<dynamic>? ?? [])
|
||||
.map((e) => StoreExtension.fromJson(e as Map<String, dynamic>))
|
||||
.toList(),
|
||||
pagination: StorePagination.fromJson(
|
||||
json['pagination'] as Map<String, dynamic>? ?? {}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class StorePagination {
|
||||
final int page;
|
||||
final int limit;
|
||||
final int total;
|
||||
final int totalPages;
|
||||
final bool hasNext;
|
||||
final bool hasPrev;
|
||||
|
||||
StorePagination({
|
||||
required this.page,
|
||||
required this.limit,
|
||||
required this.total,
|
||||
required this.totalPages,
|
||||
required this.hasNext,
|
||||
required this.hasPrev,
|
||||
});
|
||||
|
||||
factory StorePagination.fromJson(Map<String, dynamic> json) {
|
||||
return StorePagination(
|
||||
page: (json['page'] as num?)?.toInt() ?? 1,
|
||||
limit: (json['limit'] as num?)?.toInt() ?? 20,
|
||||
total: (json['total'] as num?)?.toInt() ?? 0,
|
||||
totalPages: (json['totalPages'] as num?)?.toInt() ?? 1,
|
||||
hasNext: json['hasNext'] as bool? ?? false,
|
||||
hasPrev: json['hasPrev'] as bool? ?? false,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class StoreExtension {
|
||||
final String id;
|
||||
final String repoFullName;
|
||||
final String repoUrl;
|
||||
final String? directory;
|
||||
final String? commitSha;
|
||||
final String name;
|
||||
final String author;
|
||||
final String title;
|
||||
final String description;
|
||||
final String? icon;
|
||||
final String version;
|
||||
final String? homepage;
|
||||
final String? readme;
|
||||
final int installCount;
|
||||
final int stars;
|
||||
final List<String> topics;
|
||||
final DateTime? createdAt;
|
||||
final DateTime? updatedAt;
|
||||
|
||||
StoreExtension({
|
||||
required this.id,
|
||||
required this.repoFullName,
|
||||
required this.repoUrl,
|
||||
this.directory,
|
||||
this.commitSha,
|
||||
required this.name,
|
||||
required this.author,
|
||||
required this.title,
|
||||
required this.description,
|
||||
this.icon,
|
||||
required this.version,
|
||||
this.homepage,
|
||||
this.readme,
|
||||
required this.installCount,
|
||||
required this.stars,
|
||||
required this.topics,
|
||||
this.createdAt,
|
||||
this.updatedAt,
|
||||
});
|
||||
|
||||
factory StoreExtension.fromJson(Map<String, dynamic> json) {
|
||||
return StoreExtension(
|
||||
id: json['id'] as String? ?? '',
|
||||
repoFullName: json['repoFullName'] as String? ?? '',
|
||||
repoUrl: json['repoUrl'] as String? ?? '',
|
||||
directory: json['directory'] as String?,
|
||||
commitSha: json['commitSha'] as String?,
|
||||
name: json['name'] as String? ?? '',
|
||||
author: json['author'] as String? ?? '',
|
||||
title: json['title'] as String? ?? '',
|
||||
description: json['description'] as String? ?? '',
|
||||
icon: json['icon'] as String?,
|
||||
version: json['version'] as String? ?? '0.0.0',
|
||||
homepage: json['homepage'] as String?,
|
||||
readme: json['readme'] as String?,
|
||||
installCount: (json['installCount'] as num?)?.toInt() ?? 0,
|
||||
stars: (json['stars'] as num?)?.toInt() ?? 0,
|
||||
topics: _parseTopics(json['topics']),
|
||||
createdAt: _parseDate(json['createdAt']),
|
||||
updatedAt: _parseDate(json['updatedAt']),
|
||||
);
|
||||
}
|
||||
|
||||
static List<String> _parseTopics(dynamic value) {
|
||||
if (value is List) {
|
||||
return value.map((e) => e.toString()).toList();
|
||||
}
|
||||
if (value is String && value.isNotEmpty) {
|
||||
try {
|
||||
final parsed = jsonDecode(value);
|
||||
if (parsed is List) {
|
||||
return parsed.map((e) => e.toString()).toList();
|
||||
}
|
||||
} catch (_) {}
|
||||
}
|
||||
return const [];
|
||||
}
|
||||
|
||||
static DateTime? _parseDate(dynamic value) {
|
||||
if (value == null) return null;
|
||||
if (value is int) {
|
||||
return DateTime.fromMillisecondsSinceEpoch(value);
|
||||
}
|
||||
if (value is String && value.isNotEmpty) {
|
||||
return DateTime.tryParse(value);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
enum StoreExtensionSort {
|
||||
stars,
|
||||
installs,
|
||||
updated,
|
||||
}
|
||||
|
||||
enum StoreSortOrder {
|
||||
asc,
|
||||
desc,
|
||||
}
|
||||
Reference in new issue
Block a user