146 lines
4.2 KiB
Dart
146 lines
4.2 KiB
Dart
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,
|
||
);
|
||
}
|