Files
video/app/lib/services/upload_service.dart
T
2026-10-15 20:36:59 +08:00

146 lines
4.2 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import 'package:dio/dio.dart';
import '../core/network/api_client.dart';
import '../core/network/endpoints.dart';
/// 上传发布服务(《03-接口文档》5.5 / 5.6 / 5.8)
/// 开发环境链路:upload/token(server 中转模式)→ upload/file(multipart)→ 发布
class UploadService {
UploadService._();
/// 5.8 分类列表(发布时选择)
static Future<List<VideoCategory>> fetchCategories() async {
final data = await ApiClient.get<List<dynamic>>(Endpoints.categories);
return data
.whereType<Map<String, dynamic>>()
.map(VideoCategory.fromJson)
.toList();
}
/// 5.5 获取上传凭证(开发环境返回 server 中转模式)
static Future<UploadTokenInfo> fetchUploadToken({
required String fileName,
required int fileSize,
}) async {
final data = await ApiClient.post<Map<String, dynamic>>(
Endpoints.uploadToken,
data: {'file_name': fileName, 'file_size': fileSize},
);
return UploadTokenInfo.fromJson(data);
}
/// 5.5 配套:multipart 中转上传(字段 object_key + file)
static Future<UploadFileResult> uploadFile({
required String objectKey,
required String filePath,
required String fileName,
void Function(int sent, int total)? onProgress,
}) async {
final data = await ApiClient.post<Map<String, dynamic>>(
Endpoints.uploadFile,
data: FormData.fromMap({
'object_key': objectKey,
'file': await MultipartFile.fromFile(filePath, filename: fileName),
}),
onSendProgress: onProgress,
);
return UploadFileResult.fromJson(data);
}
/// 5.6 发布视频
static Future<PublishResult> publish({
required String objectKey,
required String title,
String description = '',
required int categoryId,
List<String> tags = const [],
}) async {
final data = await ApiClient.post<Map<String, dynamic>>(
Endpoints.publish,
data: {
'object_key': objectKey,
'title': title,
'description': description,
'category_id': categoryId,
'tags': tags,
},
);
return PublishResult.fromJson(data);
}
}
/// 视频分类
class VideoCategory {
VideoCategory({required this.categoryId, required this.name});
final int categoryId;
final String name;
factory VideoCategory.fromJson(Map<String, dynamic> json) => VideoCategory(
categoryId: (json['category_id'] as num?)?.toInt() ?? 0,
name: (json['name'] as String?) ?? '',
);
}
/// 上传凭证(server 中转模式)
class UploadTokenInfo {
UploadTokenInfo({
required this.uploadType,
required this.objectKey,
required this.uploadUrl,
});
final String uploadType; // server / oss_sts
final String objectKey;
final String uploadUrl;
factory UploadTokenInfo.fromJson(Map<String, dynamic> json) =>
UploadTokenInfo(
uploadType: (json['upload_type'] as String?) ?? '',
objectKey: (json['object_key'] as String?) ?? '',
uploadUrl: (json['upload_url'] as String?) ?? '',
);
}
/// 中转上传结果
class UploadFileResult {
UploadFileResult({
required this.objectKey,
required this.url,
required this.fileSize,
});
final String objectKey;
final String url;
final int fileSize;
factory UploadFileResult.fromJson(Map<String, dynamic> json) =>
UploadFileResult(
objectKey: (json['object_key'] as String?) ?? '',
url: (json['url'] as String?) ?? '',
fileSize: (json['file_size'] as num?)?.toInt() ?? 0,
);
}
/// 发布结果
class PublishResult {
PublishResult({
required this.videoId,
required this.status,
required this.statusText,
required this.isPriority,
});
final int videoId;
final int status; // 0转码中 1待审核 2已发布 3拒绝 4下架 5转码失败
final String statusText;
final bool isPriority; // 会员优先转码
factory PublishResult.fromJson(Map<String, dynamic> json) => PublishResult(
videoId: (json['video_id'] as num?)?.toInt() ?? 0,
status: (json['status'] as num?)?.toInt() ?? 0,
statusText: (json['status_text'] as String?) ?? '',
isPriority: (json['is_priority'] as bool?) ?? false,
);
}