Line data Source code
1 : import 'dart:typed_data';
2 : import 'package:cross_file/cross_file.dart';
3 : import 'package:media_source/src/media_type.dart';
4 : import 'package:media_source/src/sources/file_media_source.dart';
5 : import 'package:media_source/src/sources/media_source.dart';
6 : import 'package:media_source/src/utils/platform_utils.dart';
7 : import 'package:file_sized/file_sized.dart';
8 : import 'package:path/path.dart' as p;
9 : import 'package:file_type_plus/file_type_plus.dart';
10 :
11 : /// Abstract base class for in-memory media sources.
12 : ///
13 : /// Stores media content as a byte array (Uint8List) in memory. This is useful for:
14 : /// - Uploading files without file system access
15 : /// - Processing downloaded media
16 : /// - Caching media in memory
17 : /// - Avoiding file system operations
18 : ///
19 : /// Subclasses include:
20 : /// - [VideoMemoryMedia] for video data
21 : /// - [AudioMemoryMedia] for audio data
22 : /// - [ImageMemoryMedia] for image data
23 : /// - [DocumentMemoryMedia] for document data
24 : /// - [OtherTypeMemoryMedia] for unclassified data
25 : abstract class MemoryMediaSource<M extends FileType> extends MediaSource<M> implements ToFileConvertableMedia<M> {
26 : /// The raw byte data of the media.
27 : final Uint8List bytes;
28 :
29 : /// Internal constructor for creating in-memory media sources.
30 : ///
31 : /// Parameters:
32 : /// - [bytes]: The media content as a byte array
33 : /// - [name]: Display name
34 : /// - [metadata]: Type-specific metadata (VideoType, AudioType, etc.)
35 : /// - [mimeType]: Optional MIME type, auto-detected from bytes if not provided
36 1 : MemoryMediaSource._(
37 : this.bytes, {
38 : required super.name,
39 : required super.metadata,
40 : String? mimeType,
41 1 : }) : super(
42 0 : mimeType: mimeType ?? FileUtil.getMimeTypeFromBytes(bytes),
43 2 : size: bytes.lengthInBytes.b,
44 : );
45 :
46 : /// Includes the byte array in equality comparisons.
47 0 : @override
48 0 : List<Object?> get props => [bytes, ...super.props];
49 :
50 : /// Disables automatic string representation of byte arrays.
51 : ///
52 : /// Returns false to prevent printing large byte arrays in debug output.
53 0 : @override
54 : bool? get stringify => false;
55 :
56 : /// Saves this media to a file in the specified folder.
57 : ///
58 : /// Uses the original filename and creates directories as needed.
59 : ///
60 : /// Parameters:
61 : /// - [folderPath]: The directory where the file should be saved
62 : ///
63 : /// Returns a new [FileMediaSource] pointing to the saved file.
64 0 : Future<FileMediaSource<M>> saveToFolder(String folderPath) {
65 0 : final path = p.join(folderPath, name);
66 0 : return saveTo(path);
67 : }
68 : }
69 :
70 : /// Represents video data stored in memory.
71 : ///
72 : /// Stores video metadata including optional duration information.
73 : /// Can be saved to a file or transmitted without file system operations.
74 : class VideoMemoryMedia extends MemoryMediaSource<VideoType> {
75 : /// Creates a [VideoMemoryMedia] with video content and optional duration.
76 : ///
77 : /// Parameters:
78 : /// - [bytes]: The video data as a byte array
79 : /// - [name]: Display name of the video
80 : /// - [duration]: Optional video duration
81 : /// - [mimeType]: Optional MIME type override
82 1 : VideoMemoryMedia(
83 : super.bytes, {
84 : required super.name,
85 : Duration? duration,
86 : super.mimeType,
87 2 : }) : super._(metadata: VideoType(duration));
88 :
89 : /// Saves this video to a file at the specified path.
90 : ///
91 : /// Creates the directory if it doesn't exist, then saves the bytes
92 : /// and returns a new [VideoFileMedia] instance.
93 0 : @override
94 : Future<VideoFileMedia> saveTo(String path) async {
95 0 : final file = XFile.fromData(
96 0 : bytes,
97 0 : name: name,
98 0 : mimeType: mimeType,
99 : path: path,
100 0 : length: size?.inBytes,
101 : );
102 0 : await PlatformUtils.instance.createDirectoryIfNotExists(path);
103 0 : await file.saveTo(path);
104 0 : return VideoFileMedia.fromFile(
105 : file,
106 0 : duration: metadata.duration,
107 0 : mimeType: mimeType,
108 0 : name: name,
109 0 : size: size,
110 : );
111 : }
112 : }
113 :
114 : /// Represents audio data stored in memory.
115 : ///
116 : /// Stores audio metadata including optional duration information.
117 : /// Can be saved to a file or transmitted without file system operations.
118 : class AudioMemoryMedia extends MemoryMediaSource<AudioType> {
119 : /// Creates an [AudioMemoryMedia] with audio content and optional duration.
120 : ///
121 : /// Parameters:
122 : /// - [bytes]: The audio data as a byte array
123 : /// - [name]: Display name of the audio
124 : /// - [duration]: Optional audio duration
125 : /// - [mimeType]: Optional MIME type override
126 1 : AudioMemoryMedia(
127 : super.bytes, {
128 : required super.name,
129 : Duration? duration,
130 : super.mimeType,
131 2 : }) : super._(metadata: AudioType(duration));
132 :
133 : /// Saves this audio to a file at the specified path.
134 : ///
135 : /// Creates the directory if it doesn't exist, then saves the bytes
136 : /// and returns a new [AudioFileMedia] instance.
137 1 : @override
138 : Future<AudioFileMedia> saveTo(String path) async {
139 1 : final file = XFile.fromData(
140 1 : bytes,
141 1 : name: name,
142 1 : mimeType: mimeType,
143 : path: path,
144 2 : length: size?.inBytes,
145 : );
146 2 : await PlatformUtils.instance.createDirectoryIfNotExists(path);
147 1 : await file.saveTo(path);
148 1 : return AudioFileMedia.fromFile(
149 : file,
150 2 : duration: metadata.duration,
151 1 : mimeType: mimeType,
152 1 : name: name,
153 1 : size: size,
154 : );
155 : }
156 : }
157 :
158 : /// Represents image data stored in memory.
159 : ///
160 : /// Can be saved to a file or transmitted without file system operations.
161 : class ImageMemoryMedia extends MemoryMediaSource<ImageType> {
162 : /// Creates an [ImageMemoryMedia] with image content.
163 : ///
164 : /// Parameters:
165 : /// - [bytes]: The image data as a byte array
166 : /// - [name]: Display name of the image
167 : /// - [mimeType]: Optional MIME type override
168 1 : ImageMemoryMedia(
169 : super.bytes, {
170 : required super.name,
171 : super.mimeType,
172 2 : }) : super._(metadata: ImageType());
173 :
174 : /// Saves this image to a file at the specified path.
175 : ///
176 : /// Creates the directory if it doesn't exist, then saves the bytes
177 : /// and returns a new [ImageFileMedia] instance.
178 0 : @override
179 : Future<ImageFileMedia> saveTo(String path) async {
180 0 : final file = XFile.fromData(
181 0 : bytes,
182 0 : name: name,
183 0 : mimeType: mimeType,
184 : path: path,
185 0 : length: size?.inBytes,
186 : );
187 0 : await PlatformUtils.instance.createDirectoryIfNotExists(path);
188 0 : await file.saveTo(path);
189 0 : return ImageFileMedia.fromFile(
190 : file,
191 0 : mimeType: mimeType,
192 0 : name: name,
193 0 : size: size,
194 : );
195 : }
196 : }
197 :
198 : /// Represents document data stored in memory.
199 : ///
200 : /// Supports documents like PDF, DOC, XLSX, etc.
201 : /// Can be saved to a file or transmitted without file system operations.
202 : class DocumentMemoryMedia extends MemoryMediaSource<DocumentType> {
203 : /// Creates a [DocumentMemoryMedia] with document content.
204 : ///
205 : /// Parameters:
206 : /// - [bytes]: The document data as a byte array
207 : /// - [name]: Display name of the document
208 : /// - [mimeType]: Optional MIME type override
209 1 : @override
210 : DocumentMemoryMedia(
211 : super.bytes, {
212 : required super.name,
213 : super.mimeType,
214 2 : }) : super._(metadata: DocumentType());
215 :
216 : /// Saves this document to a file at the specified path.
217 : ///
218 : /// Creates the directory if it doesn't exist, then saves the bytes
219 : /// and returns a new [DocumentFileMedia] instance.
220 0 : @override
221 : Future<DocumentFileMedia> saveTo(String path) async {
222 0 : final file = XFile.fromData(
223 0 : bytes,
224 0 : name: name,
225 0 : mimeType: mimeType,
226 : path: path,
227 : );
228 0 : await PlatformUtils.instance.createDirectoryIfNotExists(path);
229 0 : await file.saveTo(path);
230 0 : return DocumentFileMedia.fromFile(
231 : file,
232 0 : mimeType: mimeType,
233 0 : name: name,
234 0 : size: size,
235 : );
236 : }
237 : }
238 :
239 : /// Represents unclassified or unknown data stored in memory.
240 : ///
241 : /// Used for media that doesn't fit into standard categories
242 : /// (video, audio, image, document).
243 : /// Can be saved to a file or transmitted without file system operations.
244 : class OtherTypeMemoryMedia extends MemoryMediaSource<OtherType> {
245 : /// Creates an [OtherTypeMemoryMedia] with unclassified content.
246 : ///
247 : /// Parameters:
248 : /// - [bytes]: The media data as a byte array
249 : /// - [name]: Display name of the media
250 : /// - [mimeType]: Optional MIME type override
251 1 : @override
252 : OtherTypeMemoryMedia(
253 : super.bytes, {
254 : required super.name,
255 : super.mimeType,
256 2 : }) : super._(metadata: OtherType());
257 :
258 : /// Saves this media to a file at the specified path.
259 : ///
260 : /// Creates the directory if it doesn't exist, then saves the bytes
261 : /// and returns a new [OtherTypeFileMedia] instance.
262 0 : @override
263 : Future<OtherTypeFileMedia> saveTo(String path) async {
264 0 : final file = XFile.fromData(
265 0 : bytes,
266 0 : name: name,
267 0 : mimeType: mimeType,
268 : path: path,
269 0 : length: size?.inBytes,
270 : );
271 0 : await PlatformUtils.instance.createDirectoryIfNotExists(path);
272 0 : await file.saveTo(path);
273 0 : return OtherTypeFileMedia.fromFile(
274 : file,
275 0 : mimeType: mimeType,
276 0 : name: name,
277 0 : size: size,
278 : );
279 : }
280 : }
|