@@ -3,9 +3,11 @@ import 'package:flutter/material.dart';
3
3
import 'package:media_kit/media_kit.dart' ;
4
4
import 'package:media_kit_video/media_kit_video.dart' ;
5
5
import 'package:ytd_web/components/download_section.dart' ;
6
+ import 'package:ytd_web/modals/downloadable.dart' ;
6
7
import 'package:ytd_web/util/api.dart' ;
7
8
import 'package:ytd_web/modals/search_result_model.dart' ;
8
9
import 'package:dio/dio.dart' ;
10
+ import 'package:ytd_web/util/constants.dart' ;
9
11
import 'package:ytd_web/util/styles.dart' ;
10
12
import 'package:ytd_web/components/channel_label.dart' ;
11
13
import 'package:ytd_web/widgets/download_button/download_button.dart' ;
@@ -19,9 +21,11 @@ class VideoScreen extends StatefulWidget {
19
21
}
20
22
21
23
class _VideoScreenState extends State <VideoScreen > {
22
- static const double playerMaxWidth = 540 ;
24
+ static const double playerMaxWidth = 640 ;
23
25
final ValueNotifier <String > videoResolution = ValueNotifier ("360p" );
24
- final Map <String , String > downloadable = {};
26
+ final ValueNotifier <String > audioBitRate = ValueNotifier ("128kbps" );
27
+ final ValueNotifier <DownloadType > type = ValueNotifier (DownloadType .video);
28
+ final List <Downloadable > downloadables = [];
25
29
final Player videoPlayer = Player ();
26
30
late final VideoController controller;
27
31
Widget ? preview;
@@ -96,36 +100,44 @@ class _VideoScreenState extends State<VideoScreen> {
96
100
setState (() {
97
101
startPlayerIndicator = const CircularProgressIndicator ();
98
102
});
99
- if (downloadable["link" ] == null ) {
100
- Response <dynamic > response = await Api .instance.getVideo (
103
+ Downloadable ? match = Downloadable .getDownloadableFromList (
104
+ downloadables: downloadables,
105
+ type: type.value,
106
+ blacklistQualities: ["144p" , "240p" ]
107
+ );
108
+
109
+ if (match == null ) {
110
+ final Response <dynamic > fileResponse = await Api .instance.getVideo (
101
111
widget.searchResult.videoId,
102
- videoResolution.value
112
+ () {
113
+ // Ignoring 144p and 240p because they tend to cause errors with the player
114
+ // and its also not practical to show preview of such low quality
115
+ if (videoResolution.value == "144p" || videoResolution.value == "240p" ) {
116
+ return "360p" ;
117
+ }
118
+
119
+ return videoResolution.value;
120
+ } ()
103
121
);
104
- if (response.statusCode != 404 ) {
105
- downloadable["link" ] = response.data["downloadable_link" ];
106
- downloadable["name" ] = response.data["file_name" ];
107
- setupPlayer (downloadable["link" ]! );
108
- }
109
- else {
110
- setState (() {
111
- startPlayerIndicator = const Icon (
112
- Icons .close,
113
- size: 69 ,
114
- color: Colors .red,
115
- );
116
- });
117
- if (! mounted) return ;
118
- showDialog (
119
- context: context,
120
- builder: (context) => const AlertDialog (
121
- content: Text ("Video unavailable!" ),
122
- )
123
- );
122
+ if (fileResponse.statusCode != 404 ) {
123
+ final String url = fileResponse.data["downloadable_link" ];
124
+ downloadables.add (Downloadable (
125
+ url: url,
126
+ type: DownloadType .video,
127
+ quality: () {
128
+ // Applying the correct quality to the downloadable
129
+ // Because it 144p and 240p were replaced with 360p above
130
+ if (videoResolution.value == "144p" || videoResolution.value == "240p" ) {
131
+ return "360p" ;
132
+ }
133
+
134
+ return videoResolution.value;
135
+ } (),
136
+ name: fileResponse.data["file_name" ]
137
+ ));
138
+ setupPlayer (url);
124
139
}
125
140
}
126
- else {
127
- setupPlayer (downloadable["link" ]! );
128
- }
129
141
}
130
142
),
131
143
const SizedBox (height: 30 ,),
@@ -157,21 +169,58 @@ class _VideoScreenState extends State<VideoScreen> {
157
169
borderRadius: BorderRadius .circular (15 ),
158
170
border: Border .all (
159
171
color: Colors .red,
160
- width: 2
172
+ width: 1
161
173
)
162
174
),
163
175
child: Column (
164
176
children: [
165
177
DownloadSection (
166
178
videoId: widget.searchResult.videoId,
167
179
videoResolution: videoResolution,
180
+ audioBitRate: audioBitRate,
181
+ type: type,
168
182
onDownload: (type, quality) {},
169
183
),
170
184
const SizedBox (height: 30 ,),
171
185
DownloadButton (
172
- downloadable: downloadable,
173
- searchResult: widget.searchResult,
174
- quality: videoResolution
186
+ getDownloadable: () async {
187
+ Downloadable ? downloadable = Downloadable .getDownloadableFromList (
188
+ downloadables: downloadables,
189
+ type: type.value,
190
+ quality: type.value == DownloadType .video
191
+ ? videoResolution.value
192
+ : audioBitRate.value
193
+ );
194
+ if (downloadable != null ) {
195
+ return downloadable;
196
+ }
197
+ if (type.value == DownloadType .video) {
198
+ dynamic video = (await Api .instance.getVideo (
199
+ widget.searchResult.videoId,
200
+ videoResolution.value
201
+ )).data;
202
+
203
+ video["type" ] = type.value.name;
204
+ video["quality" ] = videoResolution.value;
205
+ Downloadable downloadable = Downloadable .fromJson (video);
206
+ downloadables.add (downloadable);
207
+
208
+ return downloadable;
209
+ }
210
+ else {
211
+ dynamic audio = (await Api .instance.getAudio (
212
+ widget.searchResult.videoId,
213
+ audioBitRate.value
214
+ )).data;
215
+
216
+ audio["type" ] = type.value.name;
217
+ audio["quality" ] = audioBitRate.value;
218
+ Downloadable downloadable = Downloadable .fromJson (audio);
219
+ downloadables.add (downloadable);
220
+
221
+ return downloadable;
222
+ }
223
+ },
175
224
)
176
225
],
177
226
),
@@ -197,12 +246,14 @@ class _VideoScreenState extends State<VideoScreen> {
197
246
void setupPlayer (String src) {
198
247
videoPlayer.open (Media (src));
199
248
setState (() {
200
- preview = Container (
201
- constraints: const BoxConstraints (
249
+ preview = AspectRatio (
250
+ aspectRatio: 16 / 9 ,
251
+ child: Container (
252
+ constraints: const BoxConstraints (
202
253
maxWidth: playerMaxWidth,
203
- maxHeight : 304
204
- ),
205
- child : Video (controller : controller,)
254
+ ),
255
+ child : Video (controller : controller,)
256
+ ),
206
257
);
207
258
});
208
259
}
0 commit comments