Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add URL caching and URL preloading #246

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
1 change: 0 additions & 1 deletion analysis_options.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ analyzer:
missing_required_param: error
prefer_const_declarations: warning
prefer_const_constructors: warning
import_of_legacy_library_into_null_safe: warning
public_member_api_docs: ignore
language:
strict-casts: true
Expand Down
1 change: 1 addition & 0 deletions lib/pod_player.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@ export 'src/models/pod_progress_bar_config.dart';
export 'src/models/vimeo_models.dart';
export 'src/pod_player.dart';
export 'src/utils/enums.dart';
export 'src/utils/video_apis.dart';
export 'src/widgets/pod_progress_bar.dart';
75 changes: 32 additions & 43 deletions lib/src/controllers/pod_getx_video_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import 'package:wakelock_plus/wakelock_plus.dart';

import '../../pod_player.dart';
import '../utils/logger.dart';
import '../utils/video_apis.dart';

part 'pod_base_controller.dart';
part 'pod_gestures_controller.dart';
Expand Down Expand Up @@ -93,7 +92,6 @@ class PodGetXVideoController extends _PodGesturesController {
httpHeaders: playVideoFrom.httpHeaders,
);
playingVideoUrl = playVideoFrom.dataSource;
break;
case PodVideoPlayerType.networkQualityUrls:
final url = await getUrlFromVideoQualityUrls(
qualityList: podPlayerConfig.videoQualityPriority,
Expand All @@ -110,7 +108,6 @@ class PodGetXVideoController extends _PodGesturesController {
);
playingVideoUrl = url;

break;
case PodVideoPlayerType.youtube:
final urls = await getVideoQualityUrlsFromYoutube(
playVideoFrom.dataSource!,
Expand All @@ -131,7 +128,6 @@ class PodGetXVideoController extends _PodGesturesController {
);
playingVideoUrl = url;

break;
case PodVideoPlayerType.vimeo:
await getQualityUrlsFromVimeoId(
playVideoFrom.dataSource!,
Expand All @@ -151,7 +147,6 @@ class PodGetXVideoController extends _PodGesturesController {
);
playingVideoUrl = url;

break;
case PodVideoPlayerType.asset:

///
Expand All @@ -163,7 +158,6 @@ class PodGetXVideoController extends _PodGesturesController {
);
playingVideoUrl = playVideoFrom.dataSource;

break;
case PodVideoPlayerType.file:
if (kIsWeb) {
throw Exception('file doesnt support web');
Expand All @@ -176,7 +170,6 @@ class PodGetXVideoController extends _PodGesturesController {
videoPlayerOptions: playVideoFrom.videoPlayerOptions,
);

break;
case PodVideoPlayerType.vimeoPrivateVideos:
await getQualityUrlsFromVimeoPrivateId(
playVideoFrom.dataSource!,
Expand All @@ -195,49 +188,49 @@ class PodGetXVideoController extends _PodGesturesController {
httpHeaders: playVideoFrom.httpHeaders,
);
playingVideoUrl = url;

break;
}
}

///Listning on keyboard events
void onKeyBoardEvents({
required RawKeyEvent event,
required KeyEvent event,
required BuildContext appContext,
required String tag,
}) {
if (kIsWeb) {
if (event.isKeyPressed(LogicalKeyboardKey.space)) {
togglePlayPauseVideo();
return;
}
if (event.isKeyPressed(LogicalKeyboardKey.keyM)) {
toggleMute();
return;
}
if (event.isKeyPressed(LogicalKeyboardKey.arrowLeft)) {
onLeftDoubleTap();
return;
}
if (event.isKeyPressed(LogicalKeyboardKey.arrowRight)) {
onRightDoubleTap();
return;
}
if (event.isKeyPressed(LogicalKeyboardKey.keyF) &&
event.logicalKey.keyLabel == 'F') {
toggleFullScreenOnWeb(appContext, tag);
}
if (event.isKeyPressed(LogicalKeyboardKey.escape)) {
if (isFullScreen) {
uni_html.document.exitFullscreen();
if (!isWebPopupOverlayOpen) {
disableFullScreen(appContext, tag);
}
}
}
if (!kIsWeb) return;

if (event is! KeyDownEvent) {
return;
}

if (event.logicalKey == LogicalKeyboardKey.space) {
togglePlayPauseVideo();
return;
}
if (event.logicalKey == LogicalKeyboardKey.keyM) {
toggleMute();
return;
}
if (event.logicalKey == LogicalKeyboardKey.arrowLeft) {
onLeftDoubleTap();
return;
}
if (event.logicalKey == LogicalKeyboardKey.arrowRight) {
onRightDoubleTap();
return;
}
if (event.logicalKey == LogicalKeyboardKey.keyF &&
event.logicalKey.keyLabel == 'F') {
toggleFullScreenOnWeb(appContext, tag);
}
if (event.logicalKey == LogicalKeyboardKey.escape) {
if (isFullScreen) {
uni_html.document.exitFullscreen();
if (!isWebPopupOverlayOpen) {
disableFullScreen(appContext, tag);
}
}
}
}

void toggleFullScreenOnWeb(BuildContext context, String tag) {
Expand All @@ -259,18 +252,14 @@ class PodGetXVideoController extends _PodGesturesController {
case PodVideoState.playing:
if (podPlayerConfig.wakelockEnabled) WakelockPlus.enable();
playVideo(true);
break;
case PodVideoState.paused:
if (podPlayerConfig.wakelockEnabled) WakelockPlus.disable();
playVideo(false);
break;
case PodVideoState.loading:
isShowOverlay(true);
break;
case PodVideoState.error:
if (podPlayerConfig.wakelockEnabled) WakelockPlus.disable();
playVideo(false);
break;
}
}

Expand Down
1 change: 0 additions & 1 deletion lib/src/controllers/pod_player_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import 'package:wakelock_plus/wakelock_plus.dart';

import '../../pod_player.dart';
import '../utils/logger.dart';
import '../utils/video_apis.dart';
import 'pod_getx_video_controller.dart';

class PodPlayerController {
Expand Down
25 changes: 25 additions & 0 deletions lib/src/controllers/pod_url_cache_singleton.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import '../../pod_player.dart';

class PodUrlCacheSingleton {
static final PodUrlCacheSingleton _singleton =
PodUrlCacheSingleton._internal();

factory PodUrlCacheSingleton() {
return _singleton;
}

PodUrlCacheSingleton._internal();

final Map<String, List<VideoQalityUrls>> _podPreFetchMap = {};

/// Add a list of urls to the pre-fetch list.
void addUrls(String key, List<VideoQalityUrls> urls) {
_podPreFetchMap[key] = urls;
}

/// Get the list of urls from the pre-fetch list.
List<VideoQalityUrls> getUrls(String key) {
final urls = _podPreFetchMap[key] ?? [];
return urls;
}
}
2 changes: 1 addition & 1 deletion lib/src/controllers/pod_video_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ class _PodVideoController extends _PodUiController {
SystemUiMode.manual,
overlays: SystemUiOverlay.values,
),
]
],
]);
}

Expand Down
27 changes: 27 additions & 0 deletions lib/src/utils/video_apis.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:http/http.dart';
import 'package:youtube_explode_dart/youtube_explode_dart.dart';
import '../controllers/pod_url_cache_singleton.dart';
import '../models/vimeo_models.dart';

String podErrorString(String val) {
Expand All @@ -28,6 +29,12 @@ class VideoApis {
String videoId,
String? hash,
) async {
final podCache = PodUrlCacheSingleton();
final cachedUrls = podCache.getUrls(videoId);
if (cachedUrls.isNotEmpty) {
return cachedUrls;
}

try {
final response = await _makeRequestHash(videoId, hash);
final jsonData = jsonDecode(response.body)['request']['files'];
Expand Down Expand Up @@ -66,6 +73,8 @@ class VideoApis {
);
}

podCache.addUrls(videoId, vimeoQualityUrls);

return vimeoQualityUrls;
} catch (error) {
if (error.toString().contains('XMLHttpRequest')) {
Expand All @@ -84,6 +93,12 @@ class VideoApis {
String videoId,
Map<String, String> httpHeader,
) async {
final podCache = PodUrlCacheSingleton();
final cachedUrls = podCache.getUrls(videoId);
if (cachedUrls.isNotEmpty) {
return cachedUrls;
}

try {
final response = await http.get(
Uri.parse('https://api.vimeo.com/videos/$videoId'),
Expand All @@ -106,6 +121,9 @@ class VideoApis {
);
}
}

podCache.addUrls(videoId, list);

return list;
} catch (error) {
if (error.toString().contains('XMLHttpRequest')) {
Expand All @@ -124,6 +142,12 @@ class VideoApis {
String youtubeIdOrUrl,
bool live,
) async {
final podCache = PodUrlCacheSingleton();
final cachedUrls = podCache.getUrls(youtubeIdOrUrl);
if (cachedUrls.isNotEmpty) {
return cachedUrls;
}

try {
final yt = YoutubeExplode();
final urls = <VideoQalityUrls>[];
Expand Down Expand Up @@ -151,6 +175,9 @@ class VideoApis {
}
// Close the YoutubeExplode's http client.
yt.close();

podCache.addUrls(youtubeIdOrUrl, urls);

return urls;
} catch (error) {
if (error.toString().contains('XMLHttpRequest')) {
Expand Down
3 changes: 0 additions & 3 deletions lib/src/widgets/core/overlays/web_dropdown_menu.dart
Original file line number Diff line number Diff line change
Expand Up @@ -68,14 +68,11 @@ class _WebSettingsDropdownState extends State<_WebSettingsDropdown> {
switch (settingsMenu) {
case 'OUALITY':
await _onVimeoQualitySelect(details, podCtr);
break;
case 'SPEED':
await _onPlaybackSpeedSelect(details, podCtr);
break;
case 'LOOP':
podCtr.isWebPopupOverlayOpen = false;
await podCtr.toggleLooping();
break;
default:
podCtr.isWebPopupOverlayOpen = false;
}
Expand Down
4 changes: 2 additions & 2 deletions lib/src/widgets/core/pod_core_player.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@ class _PodCoreVideoPlayer extends StatelessWidget {
final podCtr = Get.find<PodGetXVideoController>(tag: tag);
return Builder(
builder: (ctrx) {
return RawKeyboardListener(
return KeyboardListener(
autofocus: true,
focusNode:
(podCtr.isFullScreen ? FocusNode() : podCtr.keyboardFocusWeb) ??
FocusNode(),
onKey: (value) => podCtr.onKeyBoardEvents(
onKeyEvent: (value) => podCtr.onKeyBoardEvents(
event: value,
appContext: ctrx,
tag: tag,
Expand Down
2 changes: 1 addition & 1 deletion lib/src/widgets/doubble_tap_effect.dart
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ class _DoubleTapRippleEffectState extends State<DoubleTapRippleEffect>
fillColor: widget.rippleColor,
),
),
)
),
],
),
),
Expand Down
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: pod_player
description: Vimeo and youtube player for flutter, Pod player provides customizable video player controls that support android, ios and web.
version: 0.2.2
version: 0.2.6
homepage: https://github.com/newtaDev/pod_player

environment:
Expand Down