Files
video/app/lib/models/video_item.dart
T
2026-10-25 11:46:44 +08:00

156 lines
4.9 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.
/// Feed 视频项(GET /videos/feed 列表项,对应服务端 video_service 输出)
class VideoItem {
VideoItem({
required this.videoId,
this.title = '',
this.coverUrl = '',
this.videoUrl = '',
this.duration = 0,
required this.author,
this.categoryId = 0,
this.sourceId = 0,
this.sourceName = '',
this.viewCount = 0,
this.likeCount = 0,
this.commentCount = 0,
this.favoriteCount = 0,
this.tags = const [],
this.isLiked = false,
this.isFavorited = false,
this.description = '',
this.status = -1,
this.statusText = '',
this.rejectReason = '',
this.seriesId = 0,
this.totalEpisodes = 0,
});
final int videoId;
final String title;
final String coverUrl;
final String videoUrl; // m3u8
final int duration; // 秒
final VideoAuthor author;
final int categoryId;
/// 内容来源(麻豆 / 91 ...)
final int sourceId;
final String sourceName;
final int viewCount;
final int likeCount;
final int commentCount;
final int favoriteCount;
final List<String> tags;
final bool isLiked;
final bool isFavorited;
final String description;
/// 作品状态(仅「我的作品」接口返回):-1 未提供;0转码中 1待审核 2已发布 3拒绝 4下架 5转码失败
final int status;
final String statusText;
final String rejectReason;
/// 所属系列 id(0 = 非系列视频);系列聚合 Feed 中为首集 video_id
final int seriesId;
/// 系列总集数(系列聚合 Feed 返回,用于卡片「全N集」角标)
final int totalEpisodes;
/// 拷贝更新(点赞/收藏乐观更新用)
VideoItem copyWith({
bool? isLiked,
bool? isFavorited,
int? likeCount,
int? favoriteCount,
int? commentCount,
}) =>
VideoItem(
videoId: videoId,
title: title,
coverUrl: coverUrl,
videoUrl: videoUrl,
duration: duration,
author: author,
categoryId: categoryId,
sourceId: sourceId,
sourceName: sourceName,
viewCount: viewCount,
likeCount: likeCount ?? this.likeCount,
commentCount: commentCount ?? this.commentCount,
favoriteCount: favoriteCount ?? this.favoriteCount,
tags: tags,
isLiked: isLiked ?? this.isLiked,
isFavorited: isFavorited ?? this.isFavorited,
description: description,
status: status,
statusText: statusText,
rejectReason: rejectReason,
seriesId: seriesId,
totalEpisodes: totalEpisodes,
);
factory VideoItem.fromJson(Map<String, dynamic> json) => VideoItem(
videoId: json['video_id'] as int,
title: (json['title'] as String?) ?? '',
coverUrl: (json['cover_url'] as String?) ?? '',
videoUrl: (json['video_url'] as String?) ?? '',
duration: (json['duration'] as num?)?.toInt() ?? 0,
categoryId: (json['category_id'] as num?)?.toInt() ?? 0,
sourceId: (json['source_id'] as num?)?.toInt() ?? 0,
sourceName: (json['source_name'] as String?) ?? '',
author: VideoAuthor.fromJson(
(json['author'] as Map<String, dynamic>?) ?? const {},
),
viewCount: (json['view_count'] as num?)?.toInt() ?? 0,
likeCount: (json['like_count'] as num?)?.toInt() ?? 0,
commentCount: (json['comment_count'] as num?)?.toInt() ?? 0,
favoriteCount: (json['favorite_count'] as num?)?.toInt() ?? 0,
tags: ((json['tags'] as List?) ?? const [])
.map((e) => e.toString())
.toList(),
isLiked: (json['is_liked'] as bool?) ?? false,
isFavorited: (json['is_favorited'] as bool?) ?? false,
description: (json['description'] as String?) ?? '',
status: (json['status'] as num?)?.toInt() ?? -1,
statusText: (json['status_text'] as String?) ?? '',
rejectReason: (json['reject_reason'] as String?) ?? '',
seriesId: (json['series_id'] as num?)?.toInt() ?? 0,
totalEpisodes: (json['total_episodes'] as num?)?.toInt() ?? 0,
);
}
/// 内容来源(片商):麻豆 / 91 ...
class VideoSource {
VideoSource({required this.sourceId, required this.name, this.code = ''});
final int sourceId;
final String name;
final String code;
factory VideoSource.fromJson(Map<String, dynamic> json) => VideoSource(
sourceId: (json['source_id'] as num?)?.toInt() ?? 0,
name: (json['name'] as String?) ?? '',
code: (json['code'] as String?) ?? '',
);
}
/// 作者简要信息
class VideoAuthor {
VideoAuthor({
required this.userId,
this.nickname = '',
this.avatarUrl = '',
});
final int userId;
final String nickname;
final String avatarUrl;
factory VideoAuthor.fromJson(Map<String, dynamic> json) => VideoAuthor(
userId: (json['user_id'] as num?)?.toInt() ?? 0,
nickname: (json['nickname'] as String?) ?? '',
avatarUrl: (json['avatar_url'] as String?) ?? '',
);
}