media_item.dart
2.38 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
/// 媒体项类型
enum MediaType {
image,
video,
}
/// 媒体项数据模型
///
/// 用于 [previewMedia] 指令统一描述图片或视频。
class MediaItem {
final String url;
final MediaType type;
/// 视频封面图(仅视频有效,可选)
final String? poster;
const MediaItem({
required this.url,
required this.type,
this.poster,
});
/// 根据 URL 后缀粗略推断媒体类型
///
/// 支持的视频后缀:mp4 / mov / m4v / 3gp / mkv / webm / avi / flv / ts
/// 其它默认按图片处理
factory MediaItem.fromUrl(String url) {
return MediaItem(url: url, type: _detectType(url));
}
/// 从 previewMedia 指令的 source 对象创建:
/// {
/// "url": String, // 必填,远程或本地 URL
/// "type": "image|video", // 可选,未提供时按 URL 后缀推断
/// "poster": String, // 可选,视频封面图
/// }
factory MediaItem.fromSource(Map source) {
final dynamic rawUrl = source['url'];
final String url = rawUrl is String ? rawUrl : '';
MediaType type;
final dynamic rawType = source['type'];
if (rawType is String) {
final String t = rawType.trim().toLowerCase();
if (t == 'video') {
type = MediaType.video;
} else if (t == 'image') {
type = MediaType.image;
} else {
type = _detectType(url);
}
} else {
type = _detectType(url);
}
final dynamic rawPoster = source['poster'];
final String? poster =
(rawPoster is String && rawPoster.isNotEmpty) ? rawPoster : null;
return MediaItem(url: url, type: type, poster: poster);
}
static MediaType _detectType(String url) {
if (url.isEmpty) {
return MediaType.image;
}
// 去除 query / fragment
String path = url;
final int qIdx = path.indexOf('?');
if (qIdx >= 0) {
path = path.substring(0, qIdx);
}
final int hIdx = path.indexOf('#');
if (hIdx >= 0) {
path = path.substring(0, hIdx);
}
final int dotIdx = path.lastIndexOf('.');
if (dotIdx < 0) {
return MediaType.image;
}
final String ext = path.substring(dotIdx + 1).toLowerCase();
const Set<String> videoExt = {
'mp4',
'mov',
'm4v',
'3gp',
'mkv',
'webm',
'avi',
'flv',
'ts',
};
return videoExt.contains(ext) ? MediaType.video : MediaType.image;
}
}