1
0
Fork 0
mirror of https://github.com/jellyfin/jellyfin-web synced 2025-03-30 19:56:21 +00:00

update offline detection

This commit is contained in:
Luke Pulverenti 2015-09-21 11:43:10 -04:00
parent c651a45dea
commit 930c8cf6d8
26 changed files with 813 additions and 784 deletions

View file

@ -137,28 +137,30 @@
}
};
var streamInfo = MediaPlayer.createStreamInfo('Video', item, mediaSource, startPosition);
var currentSrc = streamInfo.url;
MediaPlayer.createStreamInfo('Video', item, mediaSource, startPosition).done(function (streamInfo) {
var audioStreamIndex = getParameterByName('AudioStreamIndex', currentSrc);
var currentSrc = streamInfo.url;
if (audioStreamIndex) {
basePlayerState.PlayState.AudioStreamIndex = parseInt(audioStreamIndex);
}
basePlayerState.PlayState.SubtitleStreamIndex = self.currentSubtitleStreamIndex;
var audioStreamIndex = getParameterByName('AudioStreamIndex', currentSrc);
basePlayerState.PlayState.PlayMethod = getParameterByName('static', currentSrc) == 'true' ?
'DirectStream' :
'Transcode';
if (audioStreamIndex) {
basePlayerState.PlayState.AudioStreamIndex = parseInt(audioStreamIndex);
}
basePlayerState.PlayState.SubtitleStreamIndex = self.currentSubtitleStreamIndex;
basePlayerState.PlayState.LiveStreamId = getParameterByName('LiveStreamId', currentSrc);
basePlayerState.PlayState.PlaySessionId = getParameterByName('PlaySessionId', currentSrc);
basePlayerState.PlayState.PlayMethod = getParameterByName('static', currentSrc) == 'true' ?
'DirectStream' :
'Transcode';
basePlayerState.PlayState.MediaSourceId = mediaSource.Id;
basePlayerState.PlayState.CanSeek = false;
basePlayerState.NowPlayingItem = MediaPlayer.getNowPlayingItemForReporting(item, mediaSource);
basePlayerState.PlayState.LiveStreamId = getParameterByName('LiveStreamId', currentSrc);
basePlayerState.PlayState.PlaySessionId = getParameterByName('PlaySessionId', currentSrc);
deferred.resolveWith(null, [streamInfo]);
basePlayerState.PlayState.MediaSourceId = mediaSource.Id;
basePlayerState.PlayState.CanSeek = false;
basePlayerState.NowPlayingItem = MediaPlayer.getNowPlayingItemForReporting(item, mediaSource);
deferred.resolveWith(null, [streamInfo]);
});
}
function getPlayerState(positionTicks) {

View file

@ -12,7 +12,7 @@
function hideStatusBar() {
if (options.type == 'video' && window.StatusBar) {
StatusBar.backgroundColorByName("black");
StatusBar.overlaysWebView(true);
//StatusBar.overlaysWebView(true);
StatusBar.hide();
}
}
@ -20,7 +20,7 @@
function showStatusBar() {
if (options.type == 'video' && window.StatusBar) {
StatusBar.show();
StatusBar.overlaysWebView(false);
//StatusBar.overlaysWebView(false);
}
}
@ -355,6 +355,11 @@
}
var val = streamInfo.url;
if (AppInfo.isNativeApp && $.browser.safari) {
val = val.replace('file://', '');
}
requiresSettingStartTimeOnStart = false;
var startTime = getStartTime(val);
var playNow = false;

View file

@ -270,9 +270,26 @@
}, delay);
});
function fadeOutLeftBig(elem, iterations) {
var keyframes = [{ opacity: '1', transform: 'none', offset: 0 },
{ opacity: '0', transform: 'translate3d(-2000px, 0, 0)', offset: 1 }];
var timing = { duration: 700, iterations: iterations };
return elem.animate(keyframes, timing);
}
if (!LibraryBrowser.navigateOnLibraryTabSelect()) {
tabs.addEventListener('iron-select', function () {
pages.selected = this.selected;
var selected = pages.selected;
if (selected != null) {
var newValue = this.selected;
fadeOutLeftBig(pages.querySelectorAll('.pageTabContent')[selected], 1).onfinish = function () {
pages.selected = newValue;
};
}
else {
pages.selected = this.selected;
}
});
}
},
@ -2362,12 +2379,12 @@
var syncPercent = item.SyncPercent;
if (syncPercent) {
return '<div class="workingSyncIndicator syncIndicator"><iron-icon icon="sync"></iron-icon></div>';
return '<div class="syncIndicator"><iron-icon icon="sync"></iron-icon></div>';
}
if (item.SyncStatus == 'Queued' || item.SyncStatus == 'Converting' || item.SyncStatus == 'ReadyToTransfer' || item.SyncStatus == 'Transferring') {
return '<div class="workingSyncIndicator syncIndicator"><iron-icon icon="sync"></iron-icon></div>';
return '<div class="syncIndicator"><iron-icon icon="sync"></iron-icon></div>';
}
return '';

View file

@ -617,6 +617,13 @@
return;
}
var url = 'itemdetails.html?id=' + itemId;
if (context) {
url += '&context=' + context;
}
Dashboard.navigate(url);
return;
var ids = items.map(function (i) {
return i.Id;
});

View file

@ -121,7 +121,7 @@
var mainDrawerButton = document.querySelector('.mainDrawerButton');
if (mainDrawerButton) {
if (AppInfo.isTouchPreferred) {
if (AppInfo.isTouchPreferred || $.browser.mobile) {
Events.on(mainDrawerButton, 'click', openMainDrawer);
@ -178,32 +178,35 @@
document.body.classList.add('bodyWithPopupOpen');
}
var drawer = document.querySelector('.mainDrawerPanel .mainDrawer');
var pageElem = $($.mobile.activePage)[0];
ConnectionManager.user(window.ApiClient).done(function (user) {
if (requiresDrawerRefresh || requiresDashboardDrawerRefresh) {
if (requiresDrawerRefresh) {
ensureDrawerStructure(drawer);
ConnectionManager.user(window.ApiClient).done(function (user) {
refreshUserInfoInDrawer(user, drawer);
refreshLibraryInfoInDrawer(user, drawer);
refreshBottomUserInfoInDrawer(user, drawer);
var drawer = document.querySelector('.mainDrawerPanel .mainDrawer');
Events.trigger(document, 'libraryMenuCreated');
updateLibraryMenu(user.localUser);
}
if (requiresDrawerRefresh) {
ensureDrawerStructure(drawer);
var pageElem = $($.mobile.activePage)[0];
refreshUserInfoInDrawer(user, drawer);
refreshLibraryInfoInDrawer(user, drawer);
refreshBottomUserInfoInDrawer(user, drawer);
if (requiresDrawerRefresh || requiresDashboardDrawerRefresh) {
refreshDashboardInfoInDrawer(pageElem, user, drawer);
requiresDashboardDrawerRefresh = false;
}
Events.trigger(document, 'libraryMenuCreated');
updateLibraryMenu(user.localUser);
}
requiresDrawerRefresh = false;
if (requiresDrawerRefresh || requiresDashboardDrawerRefresh) {
refreshDashboardInfoInDrawer(pageElem, user, drawer);
requiresDashboardDrawerRefresh = false;
}
updateLibraryNavLinks(pageElem);
});
requiresDrawerRefresh = false;
});
}
updateLibraryNavLinks(pageElem);
document.querySelector('.mainDrawerPanel #drawer').classList.add('verticalScrollingDrawer');
}
@ -714,26 +717,33 @@
lnkMediaFolder.classList.remove('selectedMediaFolder');
}
}
}
function updateTabLinks(page) {
var context = getParameterByName('context');
if (context !== 'playlists') {
var elems = page.querySelectorAll('.scopedLibraryViewNav a');
elems = page.querySelectorAll('.scopedLibraryViewNav a');
var id = page.classList.contains('liveTvPage') || page.classList.contains('channelsPage') || page.classList.contains('metadataEditorPage') || page.classList.contains('reportsPage') || page.classList.contains('mySyncPage') || page.classList.contains('allLibraryPage') ?
'' :
getTopParentId() || '';
for (i = 0, length = elems.length; i < length; i++) {
if (!id) {
return;
}
var lnk = elems[i];
var src = lnk.href;
for (i = 0, length = elems.length; i < length; i++) {
if (src.indexOf('#') != -1) {
continue;
}
var lnk = elems[i];
var src = lnk.href;
src = replaceQueryString(src, 'topParentId', id);
lnk.href = src;
if (src.indexOf('#') != -1) {
continue;
}
src = replaceQueryString(src, 'topParentId', id);
lnk.href = src;
}
}
@ -792,7 +802,9 @@
var page = this;
requiresDashboardDrawerRefresh = true;
if (page.classList.contains('type-interior')) {
requiresDashboardDrawerRefresh = true;
}
onPageBeforeShowDocumentReady(page);
@ -861,7 +873,12 @@
if (AppInfo.enableBottomTabs) {
page.classList.add('noSecondaryNavPage');
document.querySelector('.footer').classList.add('footerOverBottomTabs');
if (page.classList.contains('pageWithAbsoluteTabs')) {
document.querySelector('.footer').classList.add('footerOverBottomTabs');
}
else {
document.querySelector('.footer').classList.remove('footerOverBottomTabs');
}
} else {
@ -927,6 +944,7 @@
// Scroll back up so in case vertical scroll was messed with
window.scrollTo(0, 0);
}
updateTabLinks(page);
}
function initHeadRoom(elem) {

View file

@ -96,16 +96,16 @@
function updateFilterControls(page) {
var query = getQuery();
$('#chkFavorite', page).checked(query.IsFavorite == true);
$('#chkLikes', page).checked(query.IsLiked == true);
$('#chkDislikes', page).checked(query.IsDisliked == true);
$('.chkFavorite', page).checked(query.IsFavorite == true);
$('.chkLikes', page).checked(query.IsLiked == true);
$('.chkDislikes', page).checked(query.IsDisliked == true);
}
window.LiveTvPage.initChannelsTab = function (page, tabContent) {
var viewPanel = page.querySelector('.channelViewPanel');
$('#chkFavorite', viewPanel).on('change', function () {
$('.chkFavorite', viewPanel).on('change', function () {
var query = getQuery();
query.StartIndex = 0;
@ -115,7 +115,7 @@
});
$('#chkLikes', viewPanel).on('change', function () {
$('.chkLikes', viewPanel).on('change', function () {
var query = getQuery();
query.StartIndex = 0;
@ -124,7 +124,7 @@
reloadItems(tabContent, viewPanel);
});
$('#chkDislikes', viewPanel).on('change', function () {
$('.chkDislikes', viewPanel).on('change', function () {
var query = getQuery();
query.StartIndex = 0;

View file

@ -891,28 +891,29 @@
requirejs(['videorenderer'], function () {
var streamInfo = self.createStreamInfo('Video', item, mediaSource, startPosition);
self.createStreamInfo('Video', item, mediaSource, startPosition).done(function (streamInfo) {
// Huge hack alert. Safari doesn't seem to like if the segments aren't available right away when playback starts
// This will start the transcoding process before actually feeding the video url into the player
if ($.browser.safari && !mediaSource.RunTimeTicks) {
// Huge hack alert. Safari doesn't seem to like if the segments aren't available right away when playback starts
// This will start the transcoding process before actually feeding the video url into the player
if ($.browser.safari && !mediaSource.RunTimeTicks) {
Dashboard.showLoadingMsg();
Dashboard.showLoadingMsg();
ApiClient.ajax({
type: 'GET',
url: streamInfo.url.replace('master.m3u8', 'live.m3u8')
}).always(function () {
ApiClient.ajax({
type: 'GET',
url: streamInfo.url.replace('master.m3u8', 'live.m3u8')
}).always(function () {
Dashboard.hideLoadingMsg();
Dashboard.hideLoadingMsg();
}).done(function () {
}).done(function () {
self.playVideoInternal(item, mediaSource, startPosition, streamInfo, callback);
});
} else {
self.playVideoInternal(item, mediaSource, startPosition, streamInfo, callback);
});
} else {
self.playVideoInternal(item, mediaSource, startPosition, streamInfo, callback);
}
}
});
});
};

View file

@ -291,8 +291,6 @@
profile.ContainerProfiles = [];
var maxAudioChannels = isVlc ? '6' : '2';
profile.CodecProfiles = [];
profile.CodecProfiles.push({
Type: 'Audio',
@ -303,16 +301,6 @@
}]
});
profile.CodecProfiles.push({
Type: 'VideoAudio',
Codec: 'mp3',
Conditions: [{
Condition: 'LessThanEqual',
Property: 'AudioChannels',
Value: maxAudioChannels
}]
});
if (!isVlc) {
profile.CodecProfiles.push({
Type: 'VideoAudio',
@ -340,7 +328,7 @@
{
Condition: 'LessThanEqual',
Property: 'AudioChannels',
Value: maxAudioChannels
Value: '6'
}
]
});
@ -641,17 +629,18 @@
if (validatePlaybackInfoResult(result)) {
self.currentMediaSource = result.MediaSources[0];
var streamInfo = self.createStreamInfo(self.currentItem.MediaType, self.currentItem, self.currentMediaSource, ticks);
self.createStreamInfo(self.currentItem.MediaType, self.currentItem, self.currentMediaSource, ticks).done(function (streamInfo) {
if (!streamInfo.url) {
MediaController.showPlaybackInfoErrorMessage('NoCompatibleStream');
self.stop();
return false;
}
if (!streamInfo.url) {
MediaController.showPlaybackInfoErrorMessage('NoCompatibleStream');
self.stop();
return;
}
self.currentSubtitleStreamIndex = subtitleStreamIndex;
self.currentSubtitleStreamIndex = subtitleStreamIndex;
changeStreamToUrl(mediaRenderer, playSessionId, streamInfo, streamInfo.startTimeTicksOffset || 0);
changeStreamToUrl(mediaRenderer, playSessionId, streamInfo, streamInfo.startTimeTicksOffset || 0);
});
}
});
};
@ -915,6 +904,8 @@
self.createStreamInfo = function (type, item, mediaSource, startPosition) {
var deferred = $.Deferred();
var mediaUrl;
var contentType;
var startTimeTicksOffset = 0;
@ -1018,13 +1009,32 @@
}
}
return {
var resultInfo = {
url: mediaUrl,
mimeType: contentType,
startTimeTicksOffset: startTimeTicksOffset,
startPositionInSeekParam: startPositionInSeekParam,
playMethod: playMethod
};
if (playMethod == 'DirectPlay' && mediaSource.Protocol == 'File') {
require(['localassetmanager'], function () {
LocalAssetManager.translateFilePath(resultInfo.url).done(function (path) {
resultInfo.url = path;
Logger.log('LocalAssetManager.translateFilePath: path: ' + resultInfo.url + ' result: ' + path);
deferred.resolveWith(null, [resultInfo]);
});
});
}
else {
deferred.resolveWith(null, [resultInfo]);
}
return deferred.promise();
};
self.lastBitrateDetect = 0;
@ -1872,65 +1882,67 @@
function playAudioInternal(item, mediaSource, startPositionTicks) {
var streamInfo = self.createStreamInfo('Audio', item, mediaSource, startPositionTicks);
var audioUrl = streamInfo.url;
self.startTimeTicksOffset = streamInfo.startTimeTicksOffset;
self.createStreamInfo('Audio', item, mediaSource, startPositionTicks).done(function (streamInfo) {
var initialVolume = self.getSavedVolume();
var audioUrl = streamInfo.url;
self.startTimeTicksOffset = streamInfo.startTimeTicksOffset;
var mediaRenderer = new AudioRenderer({
poster: self.getPosterUrl(item)
});
var initialVolume = self.getSavedVolume();
Events.on(mediaRenderer, "volumechange.mediaplayerevent", function () {
var mediaRenderer = new AudioRenderer({
poster: self.getPosterUrl(item)
});
Logger.log('audio element event: volumechange');
Events.on(mediaRenderer, "volumechange.mediaplayerevent", function () {
self.onVolumeChanged(this);
Logger.log('audio element event: volumechange');
});
self.onVolumeChanged(this);
$(mediaRenderer).one("playing.mediaplayerevent", function () {
});
Logger.log('audio element event: playing');
$(mediaRenderer).one("playing.mediaplayerevent", function () {
// For some reason this is firing at the start, so don't bind until playback has begun
Events.on(this, 'ended', self.onPlaybackStopped);
Logger.log('audio element event: playing');
$(this).one('ended', self.playNextAfterEnded);
// For some reason this is firing at the start, so don't bind until playback has begun
Events.on(this, 'ended', self.onPlaybackStopped);
self.onPlaybackStart(this, item, mediaSource);
$(this).one('ended', self.playNextAfterEnded);
}).on("pause.mediaplayerevent", function () {
self.onPlaybackStart(this, item, mediaSource);
Logger.log('audio element event: pause');
}).on("pause.mediaplayerevent", function () {
self.onPlaystateChange(this);
Logger.log('audio element event: pause');
// In the event timeupdate isn't firing, at least we can update when this happens
self.setCurrentTime(self.getCurrentTicks());
self.onPlaystateChange(this);
}).on("playing.mediaplayerevent", function () {
// In the event timeupdate isn't firing, at least we can update when this happens
self.setCurrentTime(self.getCurrentTicks());
Logger.log('audio element event: playing');
}).on("playing.mediaplayerevent", function () {
self.onPlaystateChange(this);
Logger.log('audio element event: playing');
// In the event timeupdate isn't firing, at least we can update when this happens
self.setCurrentTime(self.getCurrentTicks());
self.onPlaystateChange(this);
}).on("timeupdate.mediaplayerevent", onTimeUpdate);
// In the event timeupdate isn't firing, at least we can update when this happens
self.setCurrentTime(self.getCurrentTicks());
self.currentMediaRenderer = mediaRenderer;
self.currentDurationTicks = self.currentMediaSource.RunTimeTicks;
}).on("timeupdate.mediaplayerevent", onTimeUpdate);
mediaRenderer.init().done(function () {
self.currentMediaRenderer = mediaRenderer;
self.currentDurationTicks = self.currentMediaSource.RunTimeTicks;
// Set volume first to avoid an audible change
mediaRenderer.volume(initialVolume);
mediaRenderer.init().done(function () {
mediaRenderer.setCurrentSrc(streamInfo, item, mediaSource);
self.streamInfo = streamInfo;
// Set volume first to avoid an audible change
mediaRenderer.volume(initialVolume);
mediaRenderer.setCurrentSrc(streamInfo, item, mediaSource);
self.streamInfo = streamInfo;
});
});
}

View file

@ -22,6 +22,39 @@
});
}
function getSyncStatusBanner(job) {
var opacity = '.85';
var background = 'rgba(204,51,51,' + opacity + ')';
var text = Globalize.translate('SyncJobStatus' + job.Status);
if (job.Status == 'Completed') {
background = 'rgba(82, 181, 75, ' + opacity + ')';
}
else if (job.Status == 'CompletedWithError') {
}
else if (job.Status == 'Queued') {
background = 'rgba(51, 136, 204, ' + opacity + ')';
}
else if (job.Status == 'ReadyToTransfer') {
background = 'rgba(51, 136, 204, ' + opacity + ')';
}
else if (job.Status == 'Transferring') {
background = 'rgba(72, 0, 255, ' + opacity + ')';
}
else if (job.Status == 'Converting') {
background = 'rgba(255, 106, 0, ' + opacity + ')';
}
var html = '';
html += '<div class="syncStatusBanner" data-status="' + job.Status + '" style="background-color:' + background + ';position:absolute;top:0;right:0;padding:.5em .5em; text-align:left;color: #fff; font-weight: 500; text-transform:uppercase; border-bottom-left-radius: 3px;">';
html += text;
html += '</div>';
return html;
}
function getSyncJobHtml(page, job, cardBoxCssClass, syncJobPage) {
var html = '';
@ -54,42 +87,23 @@
html += '<div class="cardImage coveredCardImage lazy" data-src="' + imgUrl + '" style="' + style + '">';
if (job.Progress && job.Progress < 100) {
html += '<div class="cardFooter fullCardFooter lightCardFooter">';
html += "<div class='cardText cardProgress'>";
html += '<progress class="itemProgressBar" min="0" max="100" value="' + job.Progress + '"></progress>';
html += "</div>";
html += "</div>";
var progress = job.Progress || 0;
var footerClass = 'cardFooter fullCardFooter lightCardFooter';
if (progress == 0 || progress >= 100) {
footerClass += ' hide';
}
html += '<div class="' + footerClass + '">';
html += "<div class='cardText cardProgress'>";
html += '<progress class="itemProgressBar" min="0" max="100" value="' + progress + '"></progress>';
html += "</div>";
html += "</div>";
html += "</div>";
var opacity = '.85';
var background = 'rgba(204,51,51,' + opacity + ')';
var text = Globalize.translate('SyncJobStatus' + job.Status);
if (job.Status == 'Completed') {
background = 'rgba(82, 181, 75, ' + opacity + ')';
}
else if (job.Status == 'CompletedWithError') {
}
else if (job.Status == 'Queued') {
background = 'rgba(51, 136, 204, ' + opacity + ')';
}
else if (job.Status == 'ReadyToTransfer') {
background = 'rgba(51, 136, 204, ' + opacity + ')';
}
else if (job.Status == 'Transferring') {
background = 'rgba(72, 0, 255, ' + opacity + ')';
}
else if (job.Status == 'Converting') {
background = 'rgba(255, 106, 0, ' + opacity + ')';
}
html += '<div class="syncStatusBanner" style="background-color:' + background + ';position:absolute;top:0;right:0;padding:.5em .5em; text-align:left;color: #fff; font-weight: 500; text-transform:uppercase; border-bottom-left-radius: 3px;">';
html += text;
html += '</div>';
html += getSyncStatusBanner(job);
// cardContent
html += "</a>";
@ -139,8 +153,17 @@
return html;
}
var lastDataLoad = 0;
function loadData(page, jobs) {
if ((new Date().getTime() - lastDataLoad) < 60000) {
refreshData(page, jobs);
return;
}
lastDataLoad = new Date().getTime();
var html = '';
var lastTargetName = '';
@ -195,6 +218,46 @@
}
}
function refreshData(page, jobs) {
for (var i = 0, length = jobs.length; i < length; i++) {
var job = jobs[i];
refreshJob(page, job);
}
}
function refreshJob(page, job) {
var card = page.querySelector('.card[data-id=\'' + job.Id + '\']');
if (!card) {
return;
}
var banner = card.querySelector('.syncStatusBanner');
if (banner.getAttribute('data-status') == job.Status) {
var elem = document.createElement('div');
elem.innerHTML = getSyncStatusBanner(job);
elem = elem.querySelector('.syncStatusBanner');
elem.parentNode.removeChild(elem);
banner.parentNode.replaceChild(elem, banner);
}
var progress = job.Progress || 0;
var cardFooter = card.querySelector('.cardFooter');
if (progress == 0 || progress >= 100) {
cardFooter.classList.add('hide');
}
else {
cardFooter.classList.remove('hide');
cardFooter.querySelector('.itemProgressBar').value = progress;
}
}
function showJobMenu(page, elem) {
var card = $(elem).parents('.card');
@ -265,6 +328,9 @@
loadData(page, response.Items);
setTimeout(function () {
loadData(page, response.Items);
}, 2000);
Dashboard.hideLoadingMsg();
});
@ -314,6 +380,7 @@
$(document).on('pageshowready', ".syncActivityPage", function () {
var page = this;
lastDataLoad = 0;
Dashboard.getPluginSecurityInfo().done(function (pluginSecurityInfo) {

View file

@ -85,6 +85,10 @@
}
html += '</div>';
html += '<div secondary style="padding-top:5px;">';
html += '<paper-progress class="mini" style="width:100%;" value="' + (jobItem.Progress || 0) + '"></paper-progress>';
html += '</div>';
html += '</paper-item-body>';
if (hasActions) {