Merge branch 'feature/PSDK-1155/json_api' into 'develop'
PSDK-1155 - Поддержка json-провайдера See merge request mobile/Flutter/nut_player!94
This commit is contained in:
+2
-2
@@ -13,8 +13,8 @@ class StatisticRecord {
|
||||
return StatisticRecord(
|
||||
name: data['name'],
|
||||
urlTemplate: data['url_template'],
|
||||
start: data['start'],
|
||||
delay: data['delay'],
|
||||
start: data['start'] == null ? 0.0 : data['start'].toDouble(),
|
||||
delay: data['delay'] == null ? 0.0 : data['delay'].toDouble(),
|
||||
count: data['count'],
|
||||
method: data['method'],
|
||||
body: data['body'],
|
||||
|
||||
@@ -143,6 +143,7 @@ class UseLinkExampleState extends JsonState {
|
||||
const UseLinkExampleState(
|
||||
String title,
|
||||
Key key,
|
||||
String? urlPath,
|
||||
List<OptionData> options,
|
||||
int? initialIndex,
|
||||
int? currentIndex,
|
||||
@@ -153,24 +154,35 @@ class UseLinkExampleState extends JsonState {
|
||||
): super(
|
||||
title: title,
|
||||
key: key,
|
||||
urlPath: urlPath,
|
||||
options: options,
|
||||
initialIndex: initialIndex,
|
||||
currentIndex: currentIndex,
|
||||
parent: parent,
|
||||
isFinal: isFinal,
|
||||
isFinal: isFinal,
|
||||
uiType: uiType,
|
||||
createIndexedEvent: createIndexedEvent
|
||||
);
|
||||
|
||||
factory UseLinkExampleState.create({JsonState? parent, int? selectedIndex}) {
|
||||
var options = const [
|
||||
OptionData(key: Key('ListElementUrl1ID'), title: 'Статистика (GET)', value: 'http://chest-101.gc.nut.team:8000/play/opt/5edd1215b2e34a3eb70654a117ea2935'),
|
||||
OptionData(key: Key('ListElementUrl2ID'), title: 'Статистика (POST)', value: 'http://chest-101.gc.nut.team:8000/play/opt/5edd1215b2e34a3eb70654a117ea2937'),
|
||||
OptionData(key: Key('ListElementUrl3ID'), title: 'Субтитры (SRT)', value: 'http://chest-101.gc.nut.team:8000/play/opt/e1dc888381e04b4290924dd9ec7b33ed'),
|
||||
];
|
||||
|
||||
final String? currentUrlPath;
|
||||
if (selectedIndex != null) {
|
||||
currentUrlPath = options[selectedIndex].value;
|
||||
} else {
|
||||
currentUrlPath = null;
|
||||
}
|
||||
|
||||
return UseLinkExampleState(
|
||||
'3. Выберите пример ссылки',
|
||||
const Key('ChooseUrlExampleListID'),
|
||||
const [
|
||||
OptionData(key: Key('ListElementUrl1ID'), title: 'Статистика (GET)', value: 'http://chest-101.gc.nut.team:8000/play/opt/5edd1215b2e34a3eb70654a117ea2935'),
|
||||
OptionData(key: Key('ListElementUrl2ID'), title: 'Статистика (POST)', value: 'http://chest-101.gc.nut.team:8000/play/opt/5edd1215b2e34a3eb70654a117ea2937'),
|
||||
OptionData(key: Key('ListElementUrl3ID'), title: 'Субтитры (SRT)', value: 'http://chest-101.gc.nut.team:8000/play/opt/e1dc888381e04b4290924dd9ec7b33ed'),
|
||||
],
|
||||
currentUrlPath,
|
||||
options,
|
||||
0,
|
||||
selectedIndex,
|
||||
parent,
|
||||
@@ -206,7 +218,7 @@ class UseJsonOwnLinkState extends JsonState {
|
||||
);
|
||||
|
||||
factory UseJsonOwnLinkState.create({JsonState? parent, String? urlPath, bool? isLive}) {
|
||||
var finalUrlPath = urlPath ?? 'https://cloud.nut.tech/index.php/s/iY3KtaL7bekWnwM/download/IMG_3059.MP4';
|
||||
var finalUrlPath = urlPath ?? '';
|
||||
return UseJsonOwnLinkState(
|
||||
'3. Укажите ссылку',
|
||||
const Key('TypeOwnUrlViewID'),
|
||||
|
||||
@@ -40,6 +40,8 @@ class MainBloc extends Bloc<MainEvent, MainState> {
|
||||
if (event.jsonState.isFinal && jsonUrlPath != null) {
|
||||
if (event.jsonState is FirebaseChosenOptionState) {
|
||||
provider = FirebaseProvider(jsonUrlPath);
|
||||
} else if (event.jsonState is UseJsonOwnLinkState || event.jsonState is UseLinkExampleState) {
|
||||
provider = JsonProvider(jsonUrlPath);
|
||||
}
|
||||
// TODO: Поддежка Json-конфигов
|
||||
} else if (event.urlState.isFinal && urlUrlPath != null) {
|
||||
|
||||
@@ -7,6 +7,7 @@ export 'src/controller/video_player_controller.dart';
|
||||
//
|
||||
export 'src/provider/provider.dart';
|
||||
export 'src/provider/common_provider.dart';
|
||||
export 'src/provider/json_provider/json_provider.dart';
|
||||
export 'src/model/content_type.dart';
|
||||
export 'src/model/player_content.dart';
|
||||
export 'src/model/player_statistic_record.dart';
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
import 'dart:convert';
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
import 'package:nut_player/nut_player.dart';
|
||||
import 'package:nut_player/src/provider/json_provider/model/json_content.dart';
|
||||
import 'package:nut_player/src/provider/json_provider/model/json_error.dart';
|
||||
import 'package:nut_player/src/provider/json_provider/model/json_statistics.dart';
|
||||
import 'package:nut_player/src/provider/json_provider/model/json_subtitles.dart';
|
||||
import 'package:nut_player/src/provider/json_provider/parsing/response.dart';
|
||||
|
||||
class JsonProvider extends Provider {
|
||||
final String urlPath;
|
||||
|
||||
JsonProvider(this.urlPath);
|
||||
|
||||
@override
|
||||
Future<PlayerContent> retrieveContent() async {
|
||||
final response = await http.get(Uri.parse(urlPath));
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
return _handleSucceedResponse(response);
|
||||
} else {
|
||||
throw JsonBadStatusCodeError();
|
||||
}
|
||||
}
|
||||
|
||||
JsonContent _handleSucceedResponse(http.Response httpResponse) {
|
||||
var response = Response.fromJson(jsonDecode(httpResponse.body) as Map<String, dynamic>);
|
||||
|
||||
if (response.playbacks.isEmpty) { throw JsonNoPlaybacksError(); }
|
||||
var uri = Uri.tryParse(response.playbacks.first.streamUrl);
|
||||
if (uri != null) {
|
||||
final statistics = response.statistics.map((stat) =>
|
||||
JsonStatistics(
|
||||
stat.name,
|
||||
stat.urlTemplate,
|
||||
stat.start,
|
||||
stat.delay,
|
||||
stat.count,
|
||||
stat.method == "get" ? HTTPMethod.get : HTTPMethod.post,
|
||||
stat.body
|
||||
)
|
||||
);
|
||||
|
||||
final subtitles = response.subtitles.map((sub) =>
|
||||
JsonSubtitles(
|
||||
sub.title,
|
||||
sub.type == "srt" ? SubtitleType.srt : SubtitleType.unknown,
|
||||
sub.url,
|
||||
sub.language
|
||||
)
|
||||
);
|
||||
|
||||
final ContentType? contentType;
|
||||
final urlPath = uri.toString();
|
||||
if (urlPath.endsWith('.mp4')) {
|
||||
contentType = Mp4ContentType(urlPath: urlPath);
|
||||
} else if (urlPath.endsWith('.m3u8')) {
|
||||
final isLive = response.playbacks.first.isLive;
|
||||
contentType = HlsContentType(urlPath: urlPath, isLive: isLive);
|
||||
} else {
|
||||
contentType = null;
|
||||
}
|
||||
|
||||
if (contentType != null) {
|
||||
return JsonContent(
|
||||
contentType,
|
||||
statistics.toList(),
|
||||
subtitles.toList()
|
||||
);
|
||||
} else {
|
||||
throw JsonUnknownFormatError();
|
||||
}
|
||||
} else {
|
||||
throw JsonIncorrectUrlError();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
import 'package:nut_player/nut_player.dart';
|
||||
|
||||
class JsonContent extends PlayerContent {
|
||||
@override
|
||||
ContentType content;
|
||||
|
||||
@override
|
||||
List<PlayerStatisticRecord> statistics;
|
||||
|
||||
@override
|
||||
List<PlayerSubtitleRecord> subtitles;
|
||||
|
||||
JsonContent(this.content, this.statistics, this.subtitles);
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
|
||||
class JsonBadStatusCodeError extends Error {}
|
||||
class JsonNoPlaybacksError extends Error {}
|
||||
class JsonIncorrectUrlError extends Error {}
|
||||
class JsonUnknownFormatError extends Error {}
|
||||
@@ -0,0 +1,26 @@
|
||||
import 'package:nut_player/nut_player.dart';
|
||||
|
||||
class JsonStatistics extends PlayerStatisticRecord {
|
||||
@override
|
||||
String name;
|
||||
|
||||
@override
|
||||
String urlTemplate;
|
||||
|
||||
@override
|
||||
double start;
|
||||
|
||||
@override
|
||||
double delay;
|
||||
|
||||
@override
|
||||
int count;
|
||||
|
||||
@override
|
||||
HTTPMethod method;
|
||||
|
||||
@override
|
||||
String? body;
|
||||
|
||||
JsonStatistics(this.name, this.urlTemplate, this.start, this.delay, this.count, this.method, this.body);
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
import 'package:nut_player/nut_player.dart';
|
||||
|
||||
class JsonSubtitles extends PlayerSubtitleRecord {
|
||||
@override
|
||||
String title;
|
||||
|
||||
@override
|
||||
SubtitleType type;
|
||||
|
||||
@override
|
||||
String url;
|
||||
|
||||
@override
|
||||
String language;
|
||||
|
||||
JsonSubtitles(this.title, this.type, this.url, this.language);
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
class PlaybackRecord {
|
||||
final String streamType;
|
||||
final String streamUrl;
|
||||
final bool isLive;
|
||||
final bool isVideo;
|
||||
final bool isAudio;
|
||||
|
||||
PlaybackRecord({required this.streamType, required this.streamUrl, required this.isLive, required this.isVideo, required this.isAudio});
|
||||
|
||||
factory PlaybackRecord.fromJson(dynamic data) {
|
||||
return PlaybackRecord(
|
||||
streamType: data['stream_type'],
|
||||
streamUrl: data['stream_url'],
|
||||
isLive: data['is_live'],
|
||||
isVideo: data['is_video'],
|
||||
isAudio: data['is_audio']
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import 'statistic_record.dart';
|
||||
import 'subtitle_record.dart';
|
||||
import 'playback_record.dart';
|
||||
|
||||
class Response {
|
||||
final List<PlaybackRecord> playbacks;
|
||||
final List<StatisticRecord> statistics;
|
||||
final List<PlayerSubtitleRecord> subtitles;
|
||||
|
||||
Response({required this.playbacks, required this.statistics, required this.subtitles});
|
||||
|
||||
factory Response.fromJson(dynamic data) {
|
||||
var playbacks = data['playback'].map((item) => PlaybackRecord.fromJson(item)).toList();
|
||||
var statistics = data['stat'].map((item) => StatisticRecord.fromJson(item)).toList();
|
||||
var subtitles = data['subtitle'].map((item) => PlayerSubtitleRecord.fromJson(item)).toList();
|
||||
|
||||
return Response(
|
||||
playbacks: List<PlaybackRecord>.from(playbacks),
|
||||
statistics: List<StatisticRecord>.from(statistics),
|
||||
subtitles: List<PlayerSubtitleRecord>.from(subtitles)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
class StatisticRecord {
|
||||
final String name;
|
||||
final String urlTemplate;
|
||||
final double start;
|
||||
final double delay;
|
||||
final int count;
|
||||
final String method;
|
||||
final String? body;
|
||||
|
||||
StatisticRecord({required this.name, required this.urlTemplate, required this.start, required this.delay, required this.count, required this.method, this.body});
|
||||
|
||||
factory StatisticRecord.fromJson(dynamic data) {
|
||||
return StatisticRecord(
|
||||
name: data['name'],
|
||||
urlTemplate: data['url_template'],
|
||||
start: data['start'] == null ? 0.0 : data['start'].toDouble(),
|
||||
delay: data['delay'] == null ? 0.0 : data['delay'].toDouble(),
|
||||
count: data['count'],
|
||||
method: data['method'],
|
||||
body: data['body'],
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
class PlayerSubtitleRecord {
|
||||
final String title;
|
||||
final String type;
|
||||
final String url;
|
||||
final String language;
|
||||
|
||||
PlayerSubtitleRecord({required this.title, required this.type, required this.url, required this.language});
|
||||
|
||||
factory PlayerSubtitleRecord.fromJson(dynamic data) {
|
||||
return PlayerSubtitleRecord(
|
||||
title: data['title'],
|
||||
type: data['type'],
|
||||
url: data['url'],
|
||||
language: data['language']
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,7 @@ dependencies:
|
||||
sdk: flutter
|
||||
plugin_platform_interface: ^2.0.2
|
||||
screen_brightness: ^0.2.2
|
||||
http: ^1.1.0
|
||||
nut_player_platform_interface:
|
||||
path: ../nut_player_platform_interface
|
||||
nut_player_ios:
|
||||
|
||||
Reference in New Issue
Block a user