Compare commits
21 Commits
renovate/d
...
release-10
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bc66fadb0e | ||
|
|
298d8d7929 | ||
|
|
bdf8553728 | ||
|
|
8ac155fb7a | ||
|
|
54dee197fd | ||
|
|
7a3eb3ffad | ||
|
|
15b987e0de | ||
|
|
54b05ab27d | ||
|
|
e1308f01b6 | ||
|
|
c596c19bfd | ||
|
|
087d06debf | ||
|
|
0b4402b642 | ||
|
|
b36369b562 | ||
|
|
78a2ba73e7 | ||
|
|
1be5e20363 | ||
|
|
9a130f5869 | ||
|
|
d6cec24d9e | ||
|
|
2044efc0c3 | ||
|
|
e12a8bc39d | ||
|
|
a885964e46 | ||
|
|
efdc07e032 |
@@ -28,6 +28,10 @@
|
||||
- [lewazo](https://github.com/lewazo)
|
||||
- [Raghu Saxena](https://github.com/ckcr4lyf)
|
||||
- [Nickbert7](https://github.com/Nickbert7)
|
||||
- [ferferga](https://github.com/ferferga)
|
||||
- [bilde2910](https://github.com/bilde2910)
|
||||
- [Daniel Hartung](https://github.com/dhartung)
|
||||
- [Ryan Hartzell](https://github.com/ryan-hartzell)
|
||||
|
||||
# Emby Contributors
|
||||
|
||||
|
||||
10
package.json
10
package.json
@@ -16,13 +16,15 @@
|
||||
"webpack-merge": "^4.2.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"jstree": "^3.3.7",
|
||||
"jquery": "^3.4.1",
|
||||
"flv.js": "^1.5.0",
|
||||
"hls.js": "^0.12.4",
|
||||
"howler": "^2.1.2",
|
||||
"swiper": "^4.5.0",
|
||||
"jquery": "^3.4.1",
|
||||
"jstree": "^3.3.7",
|
||||
"libjass": "^0.11.0",
|
||||
"shaka-player": "^2.5.5",
|
||||
"sortablejs": "^1.9.0",
|
||||
"libjass": "^0.11.0"
|
||||
"swiper": "^3.4.2"
|
||||
},
|
||||
"scripts": {
|
||||
"serve": "webpack-dev-server --config webpack.dev.js --open",
|
||||
|
||||
@@ -313,7 +313,7 @@ define(["appSettings", "browser", "events", "htmlMediaHelper"], function (appSet
|
||||
var deviceId;
|
||||
var deviceName;
|
||||
var appName = "Jellyfin Web";
|
||||
var appVersion = "10.4.0";
|
||||
var appVersion = "10.4.3";
|
||||
var visibilityChange;
|
||||
var visibilityState;
|
||||
|
||||
|
||||
@@ -156,7 +156,7 @@ button {
|
||||
}
|
||||
|
||||
.cardImageContainer {
|
||||
background-size: contain;
|
||||
background-size: cover;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center center;
|
||||
display: -webkit-flex;
|
||||
|
||||
@@ -223,9 +223,9 @@ define(['loading', 'dialogHelper', 'dom', 'listViewStyle', 'emby-input', 'paper-
|
||||
|
||||
function getDefaultPath(options) {
|
||||
if (options.path) {
|
||||
Promise.resolve(options.path);
|
||||
return Promise.resolve(options.path);
|
||||
} else {
|
||||
ApiClient.getJSON(ApiClient.getUrl("Environment/DefaultDirectoryBrowser")).then(
|
||||
return ApiClient.getJSON(ApiClient.getUrl("Environment/DefaultDirectoryBrowser")).then(
|
||||
function(result) {
|
||||
return result.Path || "";
|
||||
}, function() {
|
||||
|
||||
@@ -560,31 +560,31 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
|
||||
|
||||
if (enableScrollX()) {
|
||||
html += '<div is="emby-scroller" class="padded-top-focusscale padded-bottom-focusscale" data-mousewheel="false" data-centerfocus="true" data-scrollbuttons="false">';
|
||||
html += '<div class="padded-left padded-right padded-top padded-bottom scrollSlider focuscontainer-x">';
|
||||
html += '<div class="padded-top padded-bottom scrollSlider focuscontainer-x">';
|
||||
} else {
|
||||
html += '<div class="padded-left padded-right padded-top padded-bottom focuscontainer-x">';
|
||||
html += '<div class="padded-top padded-bottom focuscontainer-x">';
|
||||
}
|
||||
|
||||
html += '<a style="margin-left:.8em;margin-right:0;" is="emby-linkbutton" href="' + appRouter.getRouteUrl('livetv', {
|
||||
html += '<a is="emby-linkbutton" href="' + appRouter.getRouteUrl('livetv', {
|
||||
serverId: apiClient.serverId(),
|
||||
section: 'programs'
|
||||
}) + '" class="raised"><span>' + globalize.translate('Programs') + '</span></a>';
|
||||
|
||||
html += '<a style="margin-left:.5em;margin-right:0;" is="emby-linkbutton" href="' + appRouter.getRouteUrl('livetv', {
|
||||
html += '<a is="emby-linkbutton" href="' + appRouter.getRouteUrl('livetv', {
|
||||
serverId: apiClient.serverId(),
|
||||
section: 'guide'
|
||||
}) + '" class="raised"><span>' + globalize.translate('Guide') + '</span></a>';
|
||||
|
||||
html += '<a style="margin-left:.5em;margin-right:0;" is="emby-linkbutton" href="' + appRouter.getRouteUrl('recordedtv', {
|
||||
html += '<a is="emby-linkbutton" href="' + appRouter.getRouteUrl('recordedtv', {
|
||||
serverId: apiClient.serverId()
|
||||
}) + '" class="raised"><span>' + globalize.translate('Recordings') + '</span></a>';
|
||||
|
||||
html += '<a style="margin-left:.5em;margin-right:0;" is="emby-linkbutton" href="' + appRouter.getRouteUrl('livetv', {
|
||||
html += '<a is="emby-linkbutton" href="' + appRouter.getRouteUrl('livetv', {
|
||||
serverId: apiClient.serverId(),
|
||||
section: 'dvrschedule'
|
||||
}) + '" class="raised"><span>' + globalize.translate('Schedule') + '</span></a>';
|
||||
|
||||
html += '<a style="margin-left:.5em;margin-right:0;" is="emby-linkbutton" href="' + appRouter.getRouteUrl('livetv', {
|
||||
html += '<a is="emby-linkbutton" href="' + appRouter.getRouteUrl('livetv', {
|
||||
serverId: apiClient.serverId(),
|
||||
section: 'seriesrecording'
|
||||
}) + '" class="raised"><span>' + globalize.translate('Series') + '</span></a>';
|
||||
|
||||
@@ -188,7 +188,7 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa
|
||||
var currentAssRenderer;
|
||||
var customTrackIndex = -1;
|
||||
|
||||
var showTrackOffset = false;
|
||||
var showTrackOffset;
|
||||
var currentTrackOffset;
|
||||
|
||||
var videoSubtitlesElem;
|
||||
@@ -280,6 +280,8 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa
|
||||
|
||||
self._currentTime = null;
|
||||
|
||||
self.resetSubtitleOffset();
|
||||
|
||||
return createMediaElement(options).then(function (elem) {
|
||||
|
||||
return updateVideoUrl(options, options.mediaSource).then(function () {
|
||||
@@ -560,6 +562,11 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa
|
||||
setCurrentTrackElement(index);
|
||||
};
|
||||
|
||||
self.resetSubtitleOffset = function() {
|
||||
currentTrackOffset = 0;
|
||||
showTrackOffset = false;
|
||||
}
|
||||
|
||||
self.enableShowingSubtitleOffset = function() {
|
||||
showTrackOffset = true;
|
||||
}
|
||||
@@ -575,36 +582,34 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa
|
||||
self.setSubtitleOffset = function(offset) {
|
||||
|
||||
var offsetValue = parseFloat(offset);
|
||||
var videoElement = self._mediaElement;
|
||||
var mediaStreamTextTracks = getMediaStreamTextTracks(self._currentPlayOptions.mediaSource);
|
||||
|
||||
Array.from(videoElement.textTracks)
|
||||
.filter(function(trackElement) {
|
||||
if (customTrackIndex === -1 ) {
|
||||
// if .ass currently rendering
|
||||
if (currentAssRenderer){
|
||||
updateCurrentTrackOffset(offsetValue);
|
||||
} else {
|
||||
var videoElement = self._mediaElement;
|
||||
var mediaStreamTextTracks = getMediaStreamTextTracks(self._currentPlayOptions.mediaSource);
|
||||
|
||||
Array.from(videoElement.textTracks)
|
||||
.filter(function(trackElement) {
|
||||
// get showing .vtt textTacks
|
||||
return trackElement.mode === 'showing';
|
||||
} else {
|
||||
// get current .ass textTrack
|
||||
return ("textTrack" + customTrackIndex) === trackElement.id;
|
||||
}
|
||||
})
|
||||
.forEach(function(trackElement) {
|
||||
})
|
||||
.forEach(function(trackElement) {
|
||||
|
||||
var track = mediaStreamTextTracks.filter(function(stream) {
|
||||
return ("textTrack" + stream.Index) === trackElement.id;
|
||||
})[0];
|
||||
var track = customTrackIndex === -1 ? null : mediaStreamTextTracks.filter(function (t) {
|
||||
return t.Index === customTrackIndex;
|
||||
})[0];
|
||||
|
||||
if(track) {
|
||||
offsetValue = updateCurrentTrackOffset(offsetValue);
|
||||
var format = (track.Codec || '').toLowerCase();
|
||||
if (format !== 'ass' && format !== 'ssa') {
|
||||
if (track) {
|
||||
offsetValue = updateCurrentTrackOffset(offsetValue);
|
||||
setVttSubtitleOffset(trackElement, offsetValue);
|
||||
} else {
|
||||
console.log("No available track, cannot apply offset : " + offsetValue);
|
||||
}
|
||||
} else {
|
||||
console.log("No available track, cannot apply offset : " + offsetValue);
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
function updateCurrentTrackOffset(offsetValue) {
|
||||
@@ -1192,44 +1197,43 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa
|
||||
}
|
||||
|
||||
var trackElement = null;
|
||||
var expectedId = 'manualTrack' + track.Index;
|
||||
if (videoElement.textTracks && videoElement.textTracks.length > 0) {
|
||||
trackElement = videoElement.textTracks[0];
|
||||
|
||||
// get list of tracks
|
||||
var allTracks = videoElement.textTracks;
|
||||
for (var i = 0; i < allTracks.length; i++) {
|
||||
|
||||
var currentTrack = allTracks[i];
|
||||
|
||||
if (currentTrack.label === expectedId) {
|
||||
trackElement = currentTrack;
|
||||
break;
|
||||
} else {
|
||||
currentTrack.mode = 'disabled';
|
||||
}
|
||||
}
|
||||
|
||||
if (!trackElement) {
|
||||
trackElement = videoElement.addTextTrack('subtitles', 'manualTrack' + track.Index, track.Language || 'und');
|
||||
|
||||
// download the track json
|
||||
fetchSubtitles(track, item).then(function (data) {
|
||||
|
||||
// show in ui
|
||||
console.log('downloaded ' + data.TrackEvents.length + ' track events');
|
||||
// add some cues to show the text
|
||||
// in safari, the cues need to be added before setting the track mode to showing
|
||||
data.TrackEvents.forEach(function (trackEvent) {
|
||||
|
||||
var trackCueObject = window.VTTCue || window.TextTrackCue;
|
||||
var cue = new trackCueObject(trackEvent.StartPositionTicks / 10000000, trackEvent.EndPositionTicks / 10000000, normalizeTrackEventText(trackEvent.Text));
|
||||
|
||||
trackElement.addCue(cue);
|
||||
});
|
||||
// This throws an error in IE, but is fine in chrome
|
||||
// In IE it's not necessary anyway because changing the src seems to be enough
|
||||
try {
|
||||
trackElement.mode = 'showing';
|
||||
});
|
||||
while (trackElement.cues.length) {
|
||||
trackElement.removeCue(trackElement.cues[0]);
|
||||
}
|
||||
} catch (e) {
|
||||
console.log('Error removing cue from textTrack');
|
||||
}
|
||||
|
||||
trackElement.mode = 'disabled';
|
||||
} else {
|
||||
trackElement.mode = 'showing';
|
||||
// There is a function addTextTrack but no function for removeTextTrack
|
||||
// Therefore we add ONE element and replace its cue data
|
||||
trackElement = videoElement.addTextTrack('subtitles', 'manualTrack', 'und');
|
||||
}
|
||||
|
||||
// download the track json
|
||||
fetchSubtitles(track, item).then(function (data) {
|
||||
|
||||
// show in ui
|
||||
console.log('downloaded ' + data.TrackEvents.length + ' track events');
|
||||
// add some cues to show the text
|
||||
// in safari, the cues need to be added before setting the track mode to showing
|
||||
data.TrackEvents.forEach(function (trackEvent) {
|
||||
|
||||
var trackCueObject = window.VTTCue || window.TextTrackCue;
|
||||
var cue = new trackCueObject(trackEvent.StartPositionTicks / 10000000, trackEvent.EndPositionTicks / 10000000, normalizeTrackEventText(trackEvent.Text));
|
||||
|
||||
trackElement.addCue(cue);
|
||||
});
|
||||
trackElement.mode = 'showing';
|
||||
});
|
||||
}
|
||||
|
||||
function updateSubtitleText(timeMs) {
|
||||
@@ -1484,6 +1488,7 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa
|
||||
}
|
||||
|
||||
list.push('SetBrightness');
|
||||
list.push("SetAspectRatio")
|
||||
|
||||
return list;
|
||||
}
|
||||
@@ -1712,7 +1717,15 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa
|
||||
};
|
||||
|
||||
HtmlVideoPlayer.prototype.setAspectRatio = function (val) {
|
||||
|
||||
var mediaElement = this._mediaElement;
|
||||
if (mediaElement) {
|
||||
if ("auto" === val) {
|
||||
mediaElement.style.removeProperty("object-fit")
|
||||
} else {
|
||||
mediaElement.style["object-fit"] = val
|
||||
}
|
||||
}
|
||||
this._currentAspectRatio = val
|
||||
};
|
||||
|
||||
HtmlVideoPlayer.prototype.getAspectRatio = function () {
|
||||
@@ -1720,7 +1733,16 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa
|
||||
};
|
||||
|
||||
HtmlVideoPlayer.prototype.getSupportedAspectRatios = function () {
|
||||
return [];
|
||||
return [{
|
||||
name: "Auto",
|
||||
id: "auto"
|
||||
}, {
|
||||
name: "Cover",
|
||||
id: "cover"
|
||||
}, {
|
||||
name: "Fill",
|
||||
id: "fill"
|
||||
}]
|
||||
};
|
||||
|
||||
HtmlVideoPlayer.prototype.togglePictureInPicture = function () {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
define(['apphost', 'globalize', 'connectionManager', 'itemHelper', 'appRouter', 'playbackManager', 'loading', 'appSettings', 'browser', 'actionsheet'], function (appHost, globalize, connectionManager, itemHelper, appRouter, playbackManager, loading, appSettings, browser, actionsheet) {
|
||||
'use strict';
|
||||
define(["apphost", "globalize", "connectionManager", "itemHelper", "appRouter", "playbackManager", "loading", "appSettings", "browser", "actionsheet"], function (appHost, globalize, connectionManager, itemHelper, appRouter, playbackManager, loading, appSettings, browser, actionsheet) {
|
||||
"use strict";
|
||||
|
||||
function getCommands(options) {
|
||||
var item = options.item;
|
||||
@@ -9,18 +9,20 @@ define(['apphost', 'globalize', 'connectionManager', 'itemHelper', 'appRouter',
|
||||
var user = options.user;
|
||||
var commands = [];
|
||||
|
||||
if (canPlay && item.MediaType !== 'Photo') {
|
||||
if (canPlay && item.MediaType !== "Photo") {
|
||||
if (options.play !== false) {
|
||||
commands.push({
|
||||
name: globalize.translate('Play'),
|
||||
id: 'resume'
|
||||
name: globalize.translate("Play"),
|
||||
id: "resume",
|
||||
icon: "play_arrow"
|
||||
});
|
||||
}
|
||||
|
||||
if (options.playAllFromHere && item.Type !== 'Program' && item.Type !== 'TvChannel') {
|
||||
if (options.playAllFromHere && item.Type !== "Program" && item.Type !== "TvChannel") {
|
||||
commands.push({
|
||||
name: globalize.translate('PlayAllFromHere'),
|
||||
id: 'playallfromhere'
|
||||
name: globalize.translate("PlayAllFromHere"),
|
||||
id: "playallfromhere",
|
||||
icon: "play_arrow"
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -28,22 +30,24 @@ define(['apphost', 'globalize', 'connectionManager', 'itemHelper', 'appRouter',
|
||||
if (playbackManager.canQueue(item)) {
|
||||
if (options.queue !== false) {
|
||||
commands.push({
|
||||
name: globalize.translate('AddToPlayQueue'),
|
||||
id: 'queue'
|
||||
name: globalize.translate("AddToPlayQueue"),
|
||||
id: "queue",
|
||||
icon: "playlist_add"
|
||||
});
|
||||
}
|
||||
|
||||
if (options.queue !== false) {
|
||||
commands.push({
|
||||
name: globalize.translate('PlayNext'),
|
||||
id: 'queuenext'
|
||||
name: globalize.translate("PlayNext"),
|
||||
id: "queuenext",
|
||||
icon: "playlist_add"
|
||||
});
|
||||
}
|
||||
|
||||
//if (options.queueAllFromHere) {
|
||||
// commands.push({
|
||||
// name: globalize.translate('QueueAllFromHere'),
|
||||
// id: 'queueallfromhere'
|
||||
// name: globalize.translate("QueueAllFromHere"),
|
||||
// id: "queueallfromhere"
|
||||
// });
|
||||
//}
|
||||
}
|
||||
@@ -51,11 +55,12 @@ define(['apphost', 'globalize', 'connectionManager', 'itemHelper', 'appRouter',
|
||||
|
||||
|
||||
if (item.IsFolder || item.Type === "MusicArtist" || item.Type === "MusicGenre") {
|
||||
if (item.CollectionType !== 'livetv') {
|
||||
if (item.CollectionType !== "livetv") {
|
||||
if (options.shuffle !== false) {
|
||||
commands.push({
|
||||
name: globalize.translate('Shuffle'),
|
||||
id: 'shuffle'
|
||||
name: globalize.translate("Shuffle"),
|
||||
id: "shuffle",
|
||||
icon: "shuffle"
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -64,8 +69,9 @@ define(['apphost', 'globalize', 'connectionManager', 'itemHelper', 'appRouter',
|
||||
if (item.MediaType === "Audio" || item.Type === "MusicAlbum" || item.Type === "MusicArtist" || item.Type === "MusicGenre") {
|
||||
if (options.instantMix !== false && !itemHelper.isLocalItem(item)) {
|
||||
commands.push({
|
||||
name: globalize.translate('InstantMix'),
|
||||
id: 'instantmix'
|
||||
name: globalize.translate("InstantMix"),
|
||||
id: "instantmix",
|
||||
icon: "shuffle"
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -79,75 +85,91 @@ define(['apphost', 'globalize', 'connectionManager', 'itemHelper', 'appRouter',
|
||||
if (!restrictOptions) {
|
||||
if (itemHelper.supportsAddingToCollection(item)) {
|
||||
commands.push({
|
||||
name: globalize.translate('AddToCollection'),
|
||||
id: 'addtocollection'
|
||||
name: globalize.translate("AddToCollection"),
|
||||
id: "addtocollection",
|
||||
icon: "playlist_add"
|
||||
});
|
||||
}
|
||||
|
||||
if (itemHelper.supportsAddingToPlaylist(item)) {
|
||||
commands.push({
|
||||
name: globalize.translate('AddToPlaylist'),
|
||||
id: 'addtoplaylist'
|
||||
name: globalize.translate("AddToPlaylist"),
|
||||
id: "addtoplaylist",
|
||||
icon: "playlist_add"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if ((item.Type === 'Timer') && user.Policy.EnableLiveTvManagement && options.cancelTimer !== false) {
|
||||
if ((item.Type === "Timer") && user.Policy.EnableLiveTvManagement && options.cancelTimer !== false) {
|
||||
commands.push({
|
||||
name: globalize.translate('CancelRecording'),
|
||||
id: 'canceltimer'
|
||||
name: globalize.translate("CancelRecording"),
|
||||
id: "canceltimer",
|
||||
icon: "cancel"
|
||||
});
|
||||
}
|
||||
|
||||
if ((item.Type === 'Recording' && item.Status === 'InProgress') && user.Policy.EnableLiveTvManagement && options.cancelTimer !== false) {
|
||||
if ((item.Type === "Recording" && item.Status === "InProgress") && user.Policy.EnableLiveTvManagement && options.cancelTimer !== false) {
|
||||
commands.push({
|
||||
name: globalize.translate('CancelRecording'),
|
||||
id: 'canceltimer'
|
||||
name: globalize.translate("CancelRecording"),
|
||||
id: "canceltimer",
|
||||
icon: "cancel"
|
||||
});
|
||||
}
|
||||
|
||||
if ((item.Type === 'SeriesTimer') && user.Policy.EnableLiveTvManagement && options.cancelTimer !== false) {
|
||||
if ((item.Type === "SeriesTimer") && user.Policy.EnableLiveTvManagement && options.cancelTimer !== false) {
|
||||
commands.push({
|
||||
name: globalize.translate('CancelSeries'),
|
||||
id: 'cancelseriestimer'
|
||||
name: globalize.translate("CancelSeries"),
|
||||
id: "cancelseriestimer",
|
||||
icon: "cancel"
|
||||
});
|
||||
}
|
||||
|
||||
if (item.CanDelete && options.deleteItem !== false) {
|
||||
|
||||
if (item.Type === 'Playlist' || item.Type === 'BoxSet') {
|
||||
if (item.Type === "Playlist" || item.Type === "BoxSet") {
|
||||
commands.push({
|
||||
name: globalize.translate('Delete'),
|
||||
id: 'delete'
|
||||
name: globalize.translate("Delete"),
|
||||
id: "delete",
|
||||
icon: "delete"
|
||||
});
|
||||
} else {
|
||||
commands.push({
|
||||
name: globalize.translate('DeleteMedia'),
|
||||
id: 'delete'
|
||||
name: globalize.translate("DeleteMedia"),
|
||||
id: "delete",
|
||||
icon: "delete"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Books are promoted to major download Button and therefor excluded in the context menu
|
||||
if ((item.CanDownload && appHost.supports('filedownload')) && item.Type !== "Book") {
|
||||
if ((item.CanDownload && appHost.supports("filedownload")) && item.Type !== "Book") {
|
||||
commands.push({
|
||||
name: globalize.translate('Download'),
|
||||
id: 'download'
|
||||
name: globalize.translate("Download"),
|
||||
id: "download",
|
||||
icon: "file_download"
|
||||
});
|
||||
|
||||
commands.push({
|
||||
name: globalize.translate('CopyStreamURL'),
|
||||
id: 'copy-stream'
|
||||
name: globalize.translate("CopyStreamURL"),
|
||||
id: "copy-stream",
|
||||
icon: "content_copy"
|
||||
});
|
||||
}
|
||||
|
||||
if (commands.length) {
|
||||
commands.push({
|
||||
divider: true
|
||||
});
|
||||
}
|
||||
|
||||
var canEdit = itemHelper.canEdit(user, item);
|
||||
if (canEdit) {
|
||||
if (options.edit !== false && item.Type !== 'SeriesTimer') {
|
||||
var text = (item.Type === 'Timer' || item.Type === 'SeriesTimer') ? globalize.translate('Edit') : globalize.translate('EditMetadata');
|
||||
if (options.edit !== false && item.Type !== "SeriesTimer") {
|
||||
var text = (item.Type === "Timer" || item.Type === "SeriesTimer") ? globalize.translate("Edit") : globalize.translate("EditMetadata");
|
||||
commands.push({
|
||||
name: text,
|
||||
id: 'edit'
|
||||
id: "edit",
|
||||
icon: "edit"
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -155,18 +177,20 @@ define(['apphost', 'globalize', 'connectionManager', 'itemHelper', 'appRouter',
|
||||
if (itemHelper.canEditImages(user, item)) {
|
||||
if (options.editImages !== false) {
|
||||
commands.push({
|
||||
name: globalize.translate('EditImages'),
|
||||
id: 'editimages'
|
||||
name: globalize.translate("EditImages"),
|
||||
id: "editimages",
|
||||
icon: "edit"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (canEdit) {
|
||||
if (item.MediaType === 'Video' && item.Type !== 'TvChannel' && item.Type !== 'Program' && item.LocationType !== 'Virtual' && !(item.Type === 'Recording' && item.Status !== 'Completed')) {
|
||||
if (item.MediaType === "Video" && item.Type !== "TvChannel" && item.Type !== "Program" && item.LocationType !== "Virtual" && !(item.Type === "Recording" && item.Status !== "Completed")) {
|
||||
if (options.editSubtitles !== false) {
|
||||
commands.push({
|
||||
name: globalize.translate('EditSubtitles'),
|
||||
id: 'editsubtitles'
|
||||
name: globalize.translate("EditSubtitles"),
|
||||
id: "editsubtitles",
|
||||
icon: "closed_caption"
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -175,8 +199,9 @@ define(['apphost', 'globalize', 'connectionManager', 'itemHelper', 'appRouter',
|
||||
if (options.identify !== false) {
|
||||
if (itemHelper.canIdentify(user, item)) {
|
||||
commands.push({
|
||||
name: globalize.translate('Identify'),
|
||||
id: 'identify'
|
||||
name: globalize.translate("Identify"),
|
||||
id: "identify",
|
||||
icon: "edit"
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -184,48 +209,54 @@ define(['apphost', 'globalize', 'connectionManager', 'itemHelper', 'appRouter',
|
||||
if (item.MediaSources) {
|
||||
if (options.moremediainfo !== false) {
|
||||
commands.push({
|
||||
name: globalize.translate('MoreMediaInfo'),
|
||||
id: 'moremediainfo'
|
||||
name: globalize.translate("MoreMediaInfo"),
|
||||
id: "moremediainfo",
|
||||
icon: "info"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (item.Type === 'Program' && options.record !== false) {
|
||||
if (item.Type === "Program" && options.record !== false) {
|
||||
if (item.TimerId) {
|
||||
commands.push({
|
||||
name: Globalize.translate('ManageRecording'),
|
||||
id: 'record'
|
||||
name: Globalize.translate("ManageRecording"),
|
||||
id: "record",
|
||||
icon: "fiber_manual_record"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (item.Type === 'Program' && options.record !== false) {
|
||||
if (item.Type === "Program" && options.record !== false) {
|
||||
if (!item.TimerId) {
|
||||
commands.push({
|
||||
name: Globalize.translate('Record'),
|
||||
id: 'record'
|
||||
name: Globalize.translate("Record"),
|
||||
id: "record",
|
||||
icon: "fiber_manual_record"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (itemHelper.canRefreshMetadata(item, user)) {
|
||||
commands.push({
|
||||
name: globalize.translate('RefreshMetadata'),
|
||||
id: 'refresh'
|
||||
name: globalize.translate("RefreshMetadata"),
|
||||
id: "refresh",
|
||||
icon: "refresh"
|
||||
});
|
||||
}
|
||||
|
||||
if (item.PlaylistItemId && options.playlistId) {
|
||||
commands.push({
|
||||
name: globalize.translate('RemoveFromPlaylist'),
|
||||
id: 'removefromplaylist'
|
||||
name: globalize.translate("RemoveFromPlaylist"),
|
||||
id: "removefromplaylist",
|
||||
icon: "remove"
|
||||
});
|
||||
}
|
||||
|
||||
if (options.collectionId) {
|
||||
commands.push({
|
||||
name: globalize.translate('RemoveFromCollection'),
|
||||
id: 'removefromcollection'
|
||||
name: globalize.translate("RemoveFromCollection"),
|
||||
id: "removefromcollection",
|
||||
icon: "remove"
|
||||
});
|
||||
}
|
||||
|
||||
@@ -233,8 +264,9 @@ define(['apphost', 'globalize', 'connectionManager', 'itemHelper', 'appRouter',
|
||||
if (options.share === true) {
|
||||
if (itemHelper.canShare(item, user)) {
|
||||
commands.push({
|
||||
name: globalize.translate('Share'),
|
||||
id: 'share'
|
||||
name: globalize.translate("Share"),
|
||||
id: "share",
|
||||
icon: "share"
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -243,23 +275,26 @@ define(['apphost', 'globalize', 'connectionManager', 'itemHelper', 'appRouter',
|
||||
if (options.sync !== false) {
|
||||
if (itemHelper.canSync(user, item)) {
|
||||
commands.push({
|
||||
name: globalize.translate('Sync'),
|
||||
id: 'sync'
|
||||
name: globalize.translate("Sync"),
|
||||
id: "sync",
|
||||
icon: "sync"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (options.openAlbum !== false && item.AlbumId && item.MediaType !== 'Photo') {
|
||||
if (options.openAlbum !== false && item.AlbumId && item.MediaType !== "Photo") {
|
||||
commands.push({
|
||||
name: Globalize.translate('ViewAlbum'),
|
||||
id: 'album'
|
||||
name: Globalize.translate("ViewAlbum"),
|
||||
id: "album",
|
||||
icon: "album"
|
||||
});
|
||||
}
|
||||
|
||||
if (options.openArtist !== false && item.ArtistItems && item.ArtistItems.length) {
|
||||
commands.push({
|
||||
name: Globalize.translate('ViewArtist'),
|
||||
id: 'artist'
|
||||
name: Globalize.translate("ViewArtist"),
|
||||
id: "artist",
|
||||
icon: "person"
|
||||
});
|
||||
}
|
||||
|
||||
@@ -283,24 +318,24 @@ define(['apphost', 'globalize', 'connectionManager', 'itemHelper', 'appRouter',
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
switch (id) {
|
||||
case 'addtocollection':
|
||||
require(['collectionEditor'], function (collectionEditor) {
|
||||
case "addtocollection":
|
||||
require(["collectionEditor"], function (collectionEditor) {
|
||||
new collectionEditor().show({
|
||||
items: [itemId],
|
||||
serverId: serverId
|
||||
}).then(getResolveFunction(resolve, id, true), getResolveFunction(resolve, id));
|
||||
});
|
||||
break;
|
||||
case 'addtoplaylist':
|
||||
require(['playlistEditor'], function (playlistEditor) {
|
||||
case "addtoplaylist":
|
||||
require(["playlistEditor"], function (playlistEditor) {
|
||||
new playlistEditor().show({
|
||||
items: [itemId],
|
||||
serverId: serverId
|
||||
}).then(getResolveFunction(resolve, id, true), getResolveFunction(resolve, id));
|
||||
});
|
||||
break;
|
||||
case 'download':
|
||||
require(['fileDownloader'], function (fileDownloader) {
|
||||
case "download":
|
||||
require(["fileDownloader"], function (fileDownloader) {
|
||||
var downloadHref = apiClient.getItemDownloadUrl(itemId);
|
||||
fileDownloader.download([{
|
||||
url: downloadHref,
|
||||
@@ -310,7 +345,7 @@ define(['apphost', 'globalize', 'connectionManager', 'itemHelper', 'appRouter',
|
||||
getResolveFunction(getResolveFunction(resolve, id), id)();
|
||||
});
|
||||
break;
|
||||
case 'copy-stream':
|
||||
case "copy-stream":
|
||||
var downloadHref = apiClient.getItemDownloadUrl(itemId);
|
||||
var textArea = document.createElement("textarea");
|
||||
textArea.value = downloadHref;
|
||||
@@ -318,10 +353,10 @@ define(['apphost', 'globalize', 'connectionManager', 'itemHelper', 'appRouter',
|
||||
textArea.focus();
|
||||
textArea.select();
|
||||
try {
|
||||
document.execCommand('copy');
|
||||
document.execCommand("copy");
|
||||
|
||||
require(['toast'], function (toast) {
|
||||
toast(globalize.translate('CopyStreamURLSuccess'));
|
||||
require(["toast"], function (toast) {
|
||||
toast(globalize.translate("CopyStreamURLSuccess"));
|
||||
});
|
||||
} catch (err) {
|
||||
console.error("Failed to copy to clipboard");
|
||||
@@ -330,118 +365,118 @@ define(['apphost', 'globalize', 'connectionManager', 'itemHelper', 'appRouter',
|
||||
document.body.removeChild(textArea);
|
||||
getResolveFunction(resolve, id)();
|
||||
break;
|
||||
case 'editsubtitles':
|
||||
require(['subtitleEditor'], function (subtitleEditor) {
|
||||
case "editsubtitles":
|
||||
require(["subtitleEditor"], function (subtitleEditor) {
|
||||
subtitleEditor.show(itemId, serverId).then(getResolveFunction(resolve, id, true), getResolveFunction(resolve, id));
|
||||
});
|
||||
break;
|
||||
case 'edit':
|
||||
case "edit":
|
||||
editItem(apiClient, item).then(getResolveFunction(resolve, id, true), getResolveFunction(resolve, id));
|
||||
break;
|
||||
case 'editimages':
|
||||
require(['imageEditor'], function (imageEditor) {
|
||||
case "editimages":
|
||||
require(["imageEditor"], function (imageEditor) {
|
||||
imageEditor.show({
|
||||
itemId: itemId,
|
||||
serverId: serverId
|
||||
}).then(getResolveFunction(resolve, id, true), getResolveFunction(resolve, id));
|
||||
});
|
||||
break;
|
||||
case 'identify':
|
||||
require(['itemIdentifier'], function (itemIdentifier) {
|
||||
case "identify":
|
||||
require(["itemIdentifier"], function (itemIdentifier) {
|
||||
itemIdentifier.show(itemId, serverId).then(getResolveFunction(resolve, id, true), getResolveFunction(resolve, id));
|
||||
});
|
||||
break;
|
||||
case 'moremediainfo':
|
||||
require(['itemMediaInfo'], function (itemMediaInfo) {
|
||||
case "moremediainfo":
|
||||
require(["itemMediaInfo"], function (itemMediaInfo) {
|
||||
itemMediaInfo.show(itemId, serverId).then(getResolveFunction(resolve, id, true), getResolveFunction(resolve, id));
|
||||
});
|
||||
break;
|
||||
case 'refresh':
|
||||
case "refresh":
|
||||
refresh(apiClient, item);
|
||||
getResolveFunction(resolve, id)();
|
||||
break;
|
||||
case 'open':
|
||||
case "open":
|
||||
appRouter.showItem(item);
|
||||
getResolveFunction(resolve, id)();
|
||||
break;
|
||||
case 'play':
|
||||
case "play":
|
||||
play(item, false);
|
||||
getResolveFunction(resolve, id)();
|
||||
break;
|
||||
case 'resume':
|
||||
case "resume":
|
||||
play(item, true);
|
||||
getResolveFunction(resolve, id)();
|
||||
break;
|
||||
case 'queue':
|
||||
case "queue":
|
||||
play(item, false, true);
|
||||
getResolveFunction(resolve, id)();
|
||||
break;
|
||||
case 'queuenext':
|
||||
case "queuenext":
|
||||
play(item, false, true, true);
|
||||
getResolveFunction(resolve, id)();
|
||||
break;
|
||||
case 'record':
|
||||
require(['recordingCreator'], function (recordingCreator) {
|
||||
case "record":
|
||||
require(["recordingCreator"], function (recordingCreator) {
|
||||
recordingCreator.show(itemId, serverId).then(getResolveFunction(resolve, id, true), getResolveFunction(resolve, id));
|
||||
});
|
||||
break;
|
||||
case 'shuffle':
|
||||
case "shuffle":
|
||||
playbackManager.shuffle(item);
|
||||
getResolveFunction(resolve, id)();
|
||||
break;
|
||||
case 'instantmix':
|
||||
case "instantmix":
|
||||
playbackManager.instantMix(item);
|
||||
getResolveFunction(resolve, id)();
|
||||
break;
|
||||
case 'delete':
|
||||
case "delete":
|
||||
deleteItem(apiClient, item).then(getResolveFunction(resolve, id, true, true), getResolveFunction(resolve, id));
|
||||
break;
|
||||
case 'share':
|
||||
case "share":
|
||||
navigator.share({
|
||||
title: item.Name,
|
||||
text: item.Overview,
|
||||
url: "https://github.com/jellyfin/jellyfin"
|
||||
});
|
||||
break;
|
||||
case 'album':
|
||||
case "album":
|
||||
appRouter.showItem(item.AlbumId, item.ServerId);
|
||||
getResolveFunction(resolve, id)();
|
||||
break;
|
||||
case 'artist':
|
||||
case "artist":
|
||||
appRouter.showItem(item.ArtistItems[0].Id, item.ServerId);
|
||||
getResolveFunction(resolve, id)();
|
||||
break;
|
||||
case 'playallfromhere':
|
||||
case "playallfromhere":
|
||||
getResolveFunction(resolve, id)();
|
||||
break;
|
||||
case 'queueallfromhere':
|
||||
case "queueallfromhere":
|
||||
getResolveFunction(resolve, id)();
|
||||
break;
|
||||
case 'removefromplaylist':
|
||||
case "removefromplaylist":
|
||||
apiClient.ajax({
|
||||
url: apiClient.getUrl('Playlists/' + options.playlistId + '/Items', {
|
||||
EntryIds: [item.PlaylistItemId].join(',')
|
||||
url: apiClient.getUrl("Playlists/" + options.playlistId + "/Items", {
|
||||
EntryIds: [item.PlaylistItemId].join(",")
|
||||
}),
|
||||
type: 'DELETE'
|
||||
type: "DELETE"
|
||||
}).then(function () {
|
||||
getResolveFunction(resolve, id, true)();
|
||||
});
|
||||
break;
|
||||
case 'removefromcollection':
|
||||
case "removefromcollection":
|
||||
apiClient.ajax({
|
||||
type: "DELETE",
|
||||
url: apiClient.getUrl("Collections/" + options.collectionId + "/Items", {
|
||||
|
||||
Ids: [item.Id].join(',')
|
||||
Ids: [item.Id].join(",")
|
||||
})
|
||||
}).then(function () {
|
||||
getResolveFunction(resolve, id, true)();
|
||||
});
|
||||
break;
|
||||
case 'canceltimer':
|
||||
case "canceltimer":
|
||||
deleteTimer(apiClient, item, resolve, id);
|
||||
break;
|
||||
case 'cancelseriestimer':
|
||||
case "cancelseriestimer":
|
||||
deleteSeriesTimer(apiClient, item, resolve, id);
|
||||
break;
|
||||
default:
|
||||
@@ -452,7 +487,7 @@ define(['apphost', 'globalize', 'connectionManager', 'itemHelper', 'appRouter',
|
||||
}
|
||||
|
||||
function deleteTimer(apiClient, item, resolve, command) {
|
||||
require(['recordingHelper'], function (recordingHelper) {
|
||||
require(["recordingHelper"], function (recordingHelper) {
|
||||
var timerId = item.TimerId || item.Id;
|
||||
recordingHelper.cancelTimerWithConfirmation(timerId, item.ServerId).then(function () {
|
||||
getResolveFunction(resolve, command, true)();
|
||||
@@ -461,7 +496,7 @@ define(['apphost', 'globalize', 'connectionManager', 'itemHelper', 'appRouter',
|
||||
}
|
||||
|
||||
function deleteSeriesTimer(apiClient, item, resolve, command) {
|
||||
require(['recordingHelper'], function (recordingHelper) {
|
||||
require(["recordingHelper"], function (recordingHelper) {
|
||||
recordingHelper.cancelSeriesTimerWithConfirmation(item.Id, item.ServerId).then(function () {
|
||||
getResolveFunction(resolve, command, true)();
|
||||
});
|
||||
@@ -469,14 +504,14 @@ define(['apphost', 'globalize', 'connectionManager', 'itemHelper', 'appRouter',
|
||||
}
|
||||
|
||||
function play(item, resume, queue, queueNext) {
|
||||
var method = queue ? (queueNext ? 'queueNext' : 'queue') : 'play';
|
||||
var method = queue ? (queueNext ? "queueNext" : "queue") : "play";
|
||||
|
||||
var startPosition = 0;
|
||||
if (resume && item.UserData && item.UserData.PlaybackPositionTicks) {
|
||||
startPosition = item.UserData.PlaybackPositionTicks;
|
||||
}
|
||||
|
||||
if (item.Type === 'Program') {
|
||||
if (item.Type === "Program") {
|
||||
playbackManager[method]({
|
||||
ids: [item.ChannelId],
|
||||
startPositionTicks: startPosition,
|
||||
@@ -494,16 +529,16 @@ define(['apphost', 'globalize', 'connectionManager', 'itemHelper', 'appRouter',
|
||||
return new Promise(function (resolve, reject) {
|
||||
var serverId = apiClient.serverInfo().Id;
|
||||
|
||||
if (item.Type === 'Timer') {
|
||||
require(['recordingEditor'], function (recordingEditor) {
|
||||
if (item.Type === "Timer") {
|
||||
require(["recordingEditor"], function (recordingEditor) {
|
||||
recordingEditor.show(item.Id, serverId).then(resolve, reject);
|
||||
});
|
||||
} else if (item.Type === 'SeriesTimer') {
|
||||
require(['seriesRecordingEditor'], function (recordingEditor) {
|
||||
} else if (item.Type === "SeriesTimer") {
|
||||
require(["seriesRecordingEditor"], function (recordingEditor) {
|
||||
recordingEditor.show(item.Id, serverId).then(resolve, reject);
|
||||
});
|
||||
} else {
|
||||
require(['metadataEditor'], function (metadataEditor) {
|
||||
require(["metadataEditor"], function (metadataEditor) {
|
||||
metadataEditor.show(item.Id, serverId).then(resolve, reject);
|
||||
});
|
||||
}
|
||||
@@ -512,7 +547,7 @@ define(['apphost', 'globalize', 'connectionManager', 'itemHelper', 'appRouter',
|
||||
|
||||
function deleteItem(apiClient, item) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
require(['deleteHelper'], function (deleteHelper) {
|
||||
require(["deleteHelper"], function (deleteHelper) {
|
||||
deleteHelper.deleteItem({
|
||||
item: item,
|
||||
navigate: false
|
||||
@@ -524,11 +559,11 @@ define(['apphost', 'globalize', 'connectionManager', 'itemHelper', 'appRouter',
|
||||
}
|
||||
|
||||
function refresh(apiClient, item) {
|
||||
require(['refreshDialog'], function (refreshDialog) {
|
||||
require(["refreshDialog"], function (refreshDialog) {
|
||||
new refreshDialog({
|
||||
itemIds: [item.Id],
|
||||
serverId: apiClient.serverInfo().Id,
|
||||
mode: item.Type === 'CollectionFolder' ? 'scan' : null
|
||||
mode: item.Type === "CollectionFolder" ? "scan" : null
|
||||
}).show();
|
||||
});
|
||||
}
|
||||
@@ -542,7 +577,7 @@ define(['apphost', 'globalize', 'connectionManager', 'itemHelper', 'appRouter',
|
||||
return actionsheet.show({
|
||||
items: commands,
|
||||
positionTo: options.positionTo,
|
||||
resolveOnClick: ['share']
|
||||
resolveOnClick: ["share"]
|
||||
}).then(function (id) {
|
||||
return executeCommand(options.item, id, options);
|
||||
});
|
||||
|
||||
@@ -370,6 +370,14 @@ define(['dialogHelper', 'loading', 'connectionManager', 'require', 'globalize',
|
||||
scrollHelper.centerFocus.on(dlg.querySelector('.formDialogContent'), false);
|
||||
}
|
||||
|
||||
if (item.Path) {
|
||||
dlg.querySelector('.fldPath').classList.remove('hide');
|
||||
} else {
|
||||
dlg.querySelector('.fldPath').classList.add('hide');
|
||||
}
|
||||
|
||||
dlg.querySelector('.txtPath').innerHTML = item.Path || '';
|
||||
|
||||
dialogHelper.open(dlg);
|
||||
|
||||
dlg.querySelector('.popupIdentifyForm').addEventListener('submit', function (e) {
|
||||
@@ -440,6 +448,8 @@ define(['dialogHelper', 'loading', 'connectionManager', 'require', 'globalize',
|
||||
scrollHelper.centerFocus.on(dlg.querySelector('.formDialogContent'), false);
|
||||
}
|
||||
|
||||
|
||||
|
||||
dialogHelper.open(dlg);
|
||||
|
||||
dlg.querySelector('.btnCancel').addEventListener('click', function (e) {
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<div class="formDialogHeader">
|
||||
<button is="paper-icon-button-light" class="btnCancel autoSize" tabindex="-1"><i class="md-icon"></i></button>
|
||||
<button is="paper-icon-button-light" class="btnCancel autoSize" tabindex="-1">
|
||||
<i class="md-icon"></i>
|
||||
</button>
|
||||
<h3 class="formDialogHeaderTitle">
|
||||
${Identify}
|
||||
</h3>
|
||||
@@ -10,11 +12,17 @@
|
||||
<form class="popupIdentifyForm" style="margin:auto;">
|
||||
|
||||
<p>${HeaderIdentifyItemHelp}</p>
|
||||
<div class="padded-bottom fldPath hide">
|
||||
<div>${LabelPath}</div>
|
||||
<div class="txtPath fieldDescription"></div>
|
||||
</div>
|
||||
<div class="inputContainer">
|
||||
<input is="emby-input" type="text" id="txtLookupName" class="identifyField" data-lookup="Name" label="${LabelName}" />
|
||||
<input is="emby-input" type="text" id="txtLookupName" class="identifyField" data-lookup="Name"
|
||||
label="${LabelName}" />
|
||||
</div>
|
||||
<div class="fldLookupYear inputContainer">
|
||||
<input is="emby-input" type="number" id="txtLookupYear" class="identifyField" data-lookup="Year" pattern="[0-9]*" min="1800" label="${LabelYear}" />
|
||||
<input is="emby-input" type="number" id="txtLookupYear" class="identifyField" data-lookup="Year"
|
||||
pattern="[0-9]*" min="1800" label="${LabelYear}" />
|
||||
</div>
|
||||
|
||||
<div class="identifyProviderIds">
|
||||
@@ -43,10 +51,11 @@
|
||||
</label>
|
||||
|
||||
<div class="formDialogFooter">
|
||||
<button is="emby-button" type="submit" class="raised button-submit block btnSubmit formDialogFooterItem">
|
||||
<button is="emby-button" type="submit"
|
||||
class="raised button-submit block btnSubmit formDialogFooterItem">
|
||||
<span>${ButtonOk}</span>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1667,7 +1667,7 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla
|
||||
|
||||
self.getPlayerSubtitleOffset = function(player) {
|
||||
player = player || self._currentPlayer;
|
||||
if (player.getPlayerSubtitleOffset) {
|
||||
if (player.getSubtitleOffset) {
|
||||
return player.getSubtitleOffset();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -511,7 +511,9 @@ define(["browser", "datetime", "backdrop", "libraryBrowser", "listView", "imageL
|
||||
|
||||
function getSaveablePlaylistItems() {
|
||||
return getPlaylistItems(currentPlayer).then(function (items) {
|
||||
return i.Id && i.ServerId
|
||||
return items.filter(function (i) {
|
||||
return i.Id && i.ServerId;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -588,8 +588,6 @@ define(['layoutManager', 'globalize', 'require', 'events', 'connectionManager',
|
||||
allowBottomPadding: !enableScrollX()
|
||||
|
||||
}, cardOptions || {}));
|
||||
|
||||
section.querySelector('.emby-scroller').scrollToBeginning(true);
|
||||
}
|
||||
|
||||
function enableScrollX() {
|
||||
@@ -643,4 +641,4 @@ define(['layoutManager', 'globalize', 'require', 'events', 'connectionManager',
|
||||
};
|
||||
|
||||
return SearchResults;
|
||||
});
|
||||
});
|
||||
|
||||
@@ -207,7 +207,7 @@ define(['dialogHelper', 'inputManager', 'connectionManager', 'layoutManager', 'f
|
||||
dlg.querySelector('.swiper-wrapper').innerHTML = currentOptions.items.map(getSwiperSlideHtmlFromItem).join('');
|
||||
}
|
||||
|
||||
require(['swiper'], function (swiper) {
|
||||
require(['swiper'], function (Swiper) {
|
||||
|
||||
swiperInstance = new Swiper(dlg.querySelector('.slideshowSwiperContainer'), {
|
||||
// Optional parameters
|
||||
|
||||
@@ -49,7 +49,7 @@ html {
|
||||
}
|
||||
|
||||
.backgroundContainer.withBackdrop {
|
||||
opacity: .93
|
||||
opacity: .86
|
||||
}
|
||||
|
||||
@media (orientation:portrait) {
|
||||
|
||||
@@ -48,7 +48,7 @@ html {
|
||||
}
|
||||
|
||||
.backgroundContainer.withBackdrop {
|
||||
background-color: rgba(255, 255, 255, .94)
|
||||
background-color: rgba(255, 255, 255, .80)
|
||||
}
|
||||
|
||||
.dialog {
|
||||
|
||||
@@ -49,7 +49,7 @@ html {
|
||||
}
|
||||
|
||||
.backgroundContainer.withBackdrop {
|
||||
opacity: .93
|
||||
opacity: .86
|
||||
}
|
||||
|
||||
@media (orientation:portrait) {
|
||||
|
||||
@@ -507,7 +507,6 @@ define(["datetime", "events", "itemHelper", "serverNotifications", "dom", "globa
|
||||
if (session.UserId && session.UserPrimaryImageTag) {
|
||||
return ApiClient.getUserImageUrl(session.UserId, {
|
||||
tag: session.UserPrimaryImageTag,
|
||||
height: 24,
|
||||
type: "Primary"
|
||||
});
|
||||
}
|
||||
@@ -602,7 +601,6 @@ define(["datetime", "events", "itemHelper", "serverNotifications", "dom", "globa
|
||||
if (item && item.BackdropImageTags && item.BackdropImageTags.length) {
|
||||
return ApiClient.getScaledImageUrl(item.Id, {
|
||||
type: "Backdrop",
|
||||
width: 275,
|
||||
tag: item.BackdropImageTags[0]
|
||||
});
|
||||
}
|
||||
@@ -610,7 +608,6 @@ define(["datetime", "events", "itemHelper", "serverNotifications", "dom", "globa
|
||||
if (item && item.ParentBackdropImageTags && item.ParentBackdropImageTags.length) {
|
||||
return ApiClient.getScaledImageUrl(item.ParentBackdropItemId, {
|
||||
type: "Backdrop",
|
||||
width: 275,
|
||||
tag: item.ParentBackdropImageTags[0]
|
||||
});
|
||||
}
|
||||
@@ -618,7 +615,6 @@ define(["datetime", "events", "itemHelper", "serverNotifications", "dom", "globa
|
||||
if (item && item.BackdropImageTag) {
|
||||
return ApiClient.getScaledImageUrl(item.BackdropItemId, {
|
||||
type: "Backdrop",
|
||||
width: 275,
|
||||
tag: item.BackdropImageTag
|
||||
});
|
||||
}
|
||||
@@ -628,7 +624,6 @@ define(["datetime", "events", "itemHelper", "serverNotifications", "dom", "globa
|
||||
if (item && imageTags.Thumb) {
|
||||
return ApiClient.getScaledImageUrl(item.Id, {
|
||||
type: "Thumb",
|
||||
width: 275,
|
||||
tag: imageTags.Thumb
|
||||
});
|
||||
}
|
||||
@@ -636,7 +631,6 @@ define(["datetime", "events", "itemHelper", "serverNotifications", "dom", "globa
|
||||
if (item && item.ParentThumbImageTag) {
|
||||
return ApiClient.getScaledImageUrl(item.ParentThumbItemId, {
|
||||
type: "Thumb",
|
||||
width: 275,
|
||||
tag: item.ParentThumbImageTag
|
||||
});
|
||||
}
|
||||
@@ -644,7 +638,6 @@ define(["datetime", "events", "itemHelper", "serverNotifications", "dom", "globa
|
||||
if (item && item.ThumbImageTag) {
|
||||
return ApiClient.getScaledImageUrl(item.ThumbItemId, {
|
||||
type: "Thumb",
|
||||
width: 275,
|
||||
tag: item.ThumbImageTag
|
||||
});
|
||||
}
|
||||
@@ -652,7 +645,6 @@ define(["datetime", "events", "itemHelper", "serverNotifications", "dom", "globa
|
||||
if (item && imageTags.Primary) {
|
||||
return ApiClient.getScaledImageUrl(item.Id, {
|
||||
type: "Primary",
|
||||
width: 275,
|
||||
tag: imageTags.Primary
|
||||
});
|
||||
}
|
||||
@@ -660,7 +652,6 @@ define(["datetime", "events", "itemHelper", "serverNotifications", "dom", "globa
|
||||
if (item && item.PrimaryImageTag) {
|
||||
return ApiClient.getScaledImageUrl(item.PrimaryImageItemId, {
|
||||
type: "Primary",
|
||||
width: 275,
|
||||
tag: item.PrimaryImageTag
|
||||
});
|
||||
}
|
||||
@@ -668,7 +659,6 @@ define(["datetime", "events", "itemHelper", "serverNotifications", "dom", "globa
|
||||
if (item && item.AlbumPrimaryImageTag) {
|
||||
return ApiClient.getScaledImageUrl(item.AlbumId, {
|
||||
type: "Primary",
|
||||
width: 275,
|
||||
tag: item.AlbumPrimaryImageTag
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
define(["loading", "appRouter", "layoutManager", "connectionManager", "cardBuilder", "datetime", "mediaInfo", "backdrop", "listView", "itemContextMenu", "itemHelper", "dom", "indicators", "apphost", "imageLoader", "libraryMenu", "globalize", "browser", "events", "scrollHelper", "playbackManager", "libraryBrowser", "scrollStyles", "emby-itemscontainer", "emby-checkbox", "emby-button", "emby-playstatebutton", "emby-ratingbutton", "emby-scroller", "emby-select"], function(loading, appRouter, layoutManager, connectionManager, cardBuilder, datetime, mediaInfo, backdrop, listView, itemContextMenu, itemHelper, dom, indicators, appHost, imageLoader, libraryMenu, globalize, browser, events, scrollHelper, playbackManager, libraryBrowser) {
|
||||
define(["loading", "appRouter", "layoutManager", "userSettings", "connectionManager", "cardBuilder", "datetime", "mediaInfo", "backdrop", "listView", "itemContextMenu", "itemHelper", "dom", "indicators", "apphost", "imageLoader", "libraryMenu", "globalize", "browser", "events", "scrollHelper", "playbackManager", "libraryBrowser", "scrollStyles", "emby-itemscontainer", "emby-checkbox", "emby-button", "emby-playstatebutton", "emby-ratingbutton", "emby-scroller", "emby-select"], function (loading, appRouter, layoutManager, userSettings, connectionManager, cardBuilder, datetime, mediaInfo, backdrop, listView, itemContextMenu, itemHelper, dom, indicators, appHost, imageLoader, libraryMenu, globalize, browser, events, scrollHelper, playbackManager, libraryBrowser) {
|
||||
"use strict";
|
||||
|
||||
function getPromise(apiClient, params) {
|
||||
@@ -255,44 +255,97 @@ define(["loading", "appRouter", "layoutManager", "connectionManager", "cardBuild
|
||||
(item.LocalTrailerCount || item.RemoteTrailers && item.RemoteTrailers.length) && -1 !== playbackManager.getSupportedCommands().indexOf("PlayTrailers") ? hideAll(page, "btnPlayTrailer", !0) : hideAll(page, "btnPlayTrailer")
|
||||
}
|
||||
|
||||
function enabled() {
|
||||
return userSettings.enableBackdrops();
|
||||
}
|
||||
|
||||
function renderBackdrop(page, item, apiClient) {
|
||||
if (enabled()) {
|
||||
if (dom.getWindowSize().innerWidth >= 1000) {
|
||||
backdrop.setBackdrops([item]);
|
||||
} else {
|
||||
backdrop.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function renderDetailPageBackdrop(page, item, apiClient) {
|
||||
var imgUrl, screenWidth = screen.availWidth,
|
||||
hasbackdrop = !1,
|
||||
itemBackdropElement = page.querySelector("#itemBackdrop"),
|
||||
usePrimaryImage = ("Video" === item.MediaType && "Movie" !== item.Type && "Trailer" !== item.Type) || (item.MediaType && "Video" !== item.MediaType) || ("MusicAlbum" === item.Type) || ("MusicArtist" === item.Type);
|
||||
return "Program" === item.Type && item.ImageTags && item.ImageTags.Thumb ? (imgUrl = apiClient.getScaledImageUrl(item.Id, {
|
||||
type: "Thumb",
|
||||
index: 0,
|
||||
maxWidth: screenWidth,
|
||||
tag: item.ImageTags.Thumb
|
||||
}), itemBackdropElement.classList.remove("noBackdrop"), imageLoader.lazyImage(itemBackdropElement, imgUrl, !1), hasbackdrop = !0) : usePrimaryImage && item.ImageTags && item.ImageTags.Primary ? (imgUrl = apiClient.getScaledImageUrl(item.Id, {
|
||||
type: "Primary",
|
||||
index: 0,
|
||||
maxWidth: screenWidth,
|
||||
tag: item.ImageTags.Primary
|
||||
}), itemBackdropElement.classList.remove("noBackdrop"), imageLoader.lazyImage(itemBackdropElement, imgUrl, !1), hasbackdrop = !0) : item.BackdropImageTags && item.BackdropImageTags.length ? (imgUrl = apiClient.getScaledImageUrl(item.Id, {
|
||||
type: "Backdrop",
|
||||
index: 0,
|
||||
maxWidth: screenWidth,
|
||||
tag: item.BackdropImageTags[0]
|
||||
}), itemBackdropElement.classList.remove("noBackdrop"), imageLoader.lazyImage(itemBackdropElement, imgUrl, !1), hasbackdrop = !0) : item.ParentBackdropItemId && item.ParentBackdropImageTags && item.ParentBackdropImageTags.length ? (imgUrl = apiClient.getScaledImageUrl(item.ParentBackdropItemId, {
|
||||
type: "Backdrop",
|
||||
index: 0,
|
||||
tag: item.ParentBackdropImageTags[0],
|
||||
maxWidth: screenWidth
|
||||
}), itemBackdropElement.classList.remove("noBackdrop"), imageLoader.lazyImage(itemBackdropElement, imgUrl, !1), hasbackdrop = !0) : item.ImageTags && item.ImageTags.Thumb ? (imgUrl = apiClient.getScaledImageUrl(item.Id, {
|
||||
type: "Thumb",
|
||||
index: 0,
|
||||
maxWidth: screenWidth,
|
||||
tag: item.ImageTags.Thumb
|
||||
}), itemBackdropElement.classList.remove("noBackdrop"), imageLoader.lazyImage(itemBackdropElement, imgUrl, !1), hasbackdrop = !0) : (itemBackdropElement.classList.add("noBackdrop"), itemBackdropElement.style.backgroundImage = ""), hasbackdrop
|
||||
var imgUrl;
|
||||
var screenWidth = screen.availWidth;
|
||||
var hasbackdrop = false;
|
||||
var itemBackdropElement = page.querySelector("#itemBackdrop");
|
||||
var usePrimaryImage = item.MediaType === "Video" && item.Type !== "Movie" && item.Type !== "Trailer" ||
|
||||
item.MediaType && item.MediaType !== "Video" ||
|
||||
item.Type === "MusicAlbum" ||
|
||||
item.Type === "MusicArtist";
|
||||
|
||||
if ("Program" === item.Type && item.ImageTags && item.ImageTags.Thumb) {
|
||||
imgUrl = apiClient.getScaledImageUrl(item.Id, {
|
||||
type: "Thumb",
|
||||
index: 0,
|
||||
tag: item.ImageTags.Thumb
|
||||
});
|
||||
itemBackdropElement.classList.remove("noBackdrop");
|
||||
imageLoader.lazyImage(itemBackdropElement, imgUrl, false);
|
||||
hasbackdrop = true;
|
||||
} else if (usePrimaryImage && item.ImageTags && item.ImageTags.Primary) {
|
||||
imgUrl = apiClient.getScaledImageUrl(item.Id, {
|
||||
type: "Primary",
|
||||
index: 0,
|
||||
tag: item.ImageTags.Primary
|
||||
});
|
||||
itemBackdropElement.classList.remove("noBackdrop");
|
||||
imageLoader.lazyImage(itemBackdropElement, imgUrl, false);
|
||||
hasbackdrop = true;
|
||||
} else if (item.BackdropImageTags && item.BackdropImageTags.length) {
|
||||
imgUrl = apiClient.getScaledImageUrl(item.Id, {
|
||||
type: "Backdrop",
|
||||
index: 0,
|
||||
tag: item.BackdropImageTags[0]
|
||||
});
|
||||
itemBackdropElement.classList.remove("noBackdrop");
|
||||
imageLoader.lazyImage(itemBackdropElement, imgUrl, false);
|
||||
hasbackdrop = true;
|
||||
} else if (item.ParentBackdropItemId && item.ParentBackdropImageTags && item.ParentBackdropImageTags.length) {
|
||||
imgUrl = apiClient.getScaledImageUrl(item.ParentBackdropItemId, {
|
||||
type: "Backdrop",
|
||||
index: 0,
|
||||
tag: item.ParentBackdropImageTags[0]
|
||||
});
|
||||
itemBackdropElement.classList.remove("noBackdrop");
|
||||
imageLoader.lazyImage(itemBackdropElement, imgUrl, false);
|
||||
hasbackdrop = true;
|
||||
} else if (item.ImageTags && item.ImageTags.Thumb) {
|
||||
imgUrl = apiClient.getScaledImageUrl(item.Id, {
|
||||
type: "Thumb",
|
||||
index: 0,
|
||||
tag: item.ImageTags.Thumb
|
||||
});
|
||||
itemBackdropElement.classList.remove("noBackdrop");
|
||||
imageLoader.lazyImage(itemBackdropElement, imgUrl, false);
|
||||
hasbackdrop = true;
|
||||
} else {
|
||||
itemBackdropElement.classList.add("noBackdrop");
|
||||
itemBackdropElement.style.backgroundImage = "";
|
||||
}
|
||||
|
||||
return hasbackdrop;
|
||||
}
|
||||
|
||||
function reloadFromItem(instance, page, params, item, user) {
|
||||
var context = params.context;
|
||||
renderName(item, page.querySelector(".nameContainer"), !1, context);
|
||||
var apiClient = connectionManager.getApiClient(item.ServerId);
|
||||
renderSeriesTimerEditor(page, item, apiClient, user), renderTimerEditor(page, item, apiClient, user), renderImage(page, item, apiClient, user), renderLogo(page, item, apiClient), setTitle(item, apiClient), setInitialCollapsibleState(page, item, apiClient, context, user), renderDetails(page, item, apiClient, context), renderTrackSelections(page, instance, item), dom.getWindowSize().innerWidth >= 1e3 ? backdrop.setBackdrops([item]) : backdrop.clear(), renderDetailPageBackdrop(page, item, apiClient);
|
||||
renderSeriesTimerEditor(page, item, apiClient, user);
|
||||
renderTimerEditor(page, item, apiClient, user);
|
||||
renderImage(page, item, apiClient, user);
|
||||
renderLogo(page, item, apiClient);
|
||||
setTitle(item, apiClient);
|
||||
setInitialCollapsibleState(page, item, apiClient, context, user);
|
||||
renderDetails(page, item, apiClient, context);
|
||||
renderTrackSelections(page, instance, item);
|
||||
renderBackdrop(page, item, apiClient);
|
||||
renderDetailPageBackdrop(page, item, apiClient);
|
||||
var canPlay = reloadPlayButtons(page, item);
|
||||
if ((item.LocalTrailerCount || item.RemoteTrailers && item.RemoteTrailers.length) && -1 !== playbackManager.getSupportedCommands().indexOf("PlayTrailers")) {
|
||||
hideAll(page, "btnPlayTrailer", true);
|
||||
|
||||
@@ -6,17 +6,11 @@ define(["loading"], function(loading) {
|
||||
url: ApiClient.getUrl("Startup/Complete"),
|
||||
type: "POST"
|
||||
}).then(function() {
|
||||
Dashboard.navigate("dashboard.html");
|
||||
loading.hide();
|
||||
window.location.href = "index.html";
|
||||
});
|
||||
}
|
||||
return function(view, params) {
|
||||
view.querySelector(".btnWizardNext").addEventListener("click", onFinish);
|
||||
view.addEventListener("viewshow", function() {
|
||||
document.querySelector(".skinHeader").classList.add("noHomeButtonHeader")
|
||||
});
|
||||
view.addEventListener("viewhide", function() {
|
||||
document.querySelector(".skinHeader").classList.remove("noHomeButtonHeader")
|
||||
});
|
||||
};
|
||||
});
|
||||
|
||||
@@ -1013,14 +1013,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
.layout-tv .itemsViewSettingsContainer {
|
||||
-webkit-box-pack: end;
|
||||
-webkit-justify-content: flex-end;
|
||||
justify-content: flex-end;
|
||||
padding: 1.5em .75em 1em 0;
|
||||
font-size: 92%
|
||||
}
|
||||
|
||||
.itemsViewSettingsContainer>.button-flat {
|
||||
margin: 0
|
||||
}
|
||||
|
||||
@@ -6,14 +6,17 @@
|
||||
|
||||
<h1 style="margin-top:1em;text-align: left;">${HeaderPleaseSignIn}</h1>
|
||||
|
||||
<div style="height:0; overflow: hidden;"><input type="text" name="fakeusernameremembered" tabindex="-1" /><input type="password" name="fakepasswordremembered" tabindex="-1" /></div>
|
||||
|
||||
<div class="inputContainer">
|
||||
<input is="emby-input" type="text" id="txtManualName" required="required" label="${LabelUser}" />
|
||||
<div style="height:0; overflow: hidden;">
|
||||
<input type="text" name="fakeusernameremembered" tabindex="-1" />
|
||||
<input type="password" name="fakepasswordremembered" tabindex="-1" />
|
||||
</div>
|
||||
|
||||
<div class="inputContainer">
|
||||
<input is="emby-input" id="txtManualPassword" type="password" label="${LabelPassword}" />
|
||||
<input is="emby-input" type="text" id="txtManualName" required="required" label="${LabelUser}" autocomplete="username" />
|
||||
</div>
|
||||
|
||||
<div class="inputContainer">
|
||||
<input is="emby-input" id="txtManualPassword" type="password" label="${LabelPassword}" autocomplete="current-password" />
|
||||
</div>
|
||||
|
||||
<label class="checkboxContainer">
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"description": "Jellyfin: the Free Software Media System.",
|
||||
"lang": "en-US",
|
||||
"short_name": "Jellyfin",
|
||||
"start_url": "/web/index.html#!/home.html",
|
||||
"start_url": "index.html#!/home.html",
|
||||
"theme_color": "#101010",
|
||||
"background_color": "#101010",
|
||||
"display": "standalone",
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
<div class="padded-left padded-right padded-bottom-page">
|
||||
<div class="readOnlyContent" style="margin: 0 auto; padding: 0 1em;">
|
||||
<div style="position:relative;display:inline-block;max-width:200px;">
|
||||
<img id="image" width="200px" />
|
||||
<input id="uploadImage" type="file" accept="image/*" style="position:absolute;right:0;width:100%;height:100%;opacity:0;" />
|
||||
<div id="image" style="width:200px;height:200px;background-repeat:no-repeat;background-position:center;border-radius:100%;background-size:cover;"></div>
|
||||
</div>
|
||||
<div style="vertical-align:top;margin:1em 2em;display:inline-block;">
|
||||
<h2 class="username" style="margin:0;font-size:xx-large;"></h2>
|
||||
@@ -68,4 +68,4 @@
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -107,8 +107,9 @@ define(["datetime", "jQuery", "material-icons"], function (datetime, $) {
|
||||
});
|
||||
}
|
||||
|
||||
function loadLiveTvChannels(openItems, callback) {
|
||||
function loadLiveTvChannels(service, openItems, callback) {
|
||||
ApiClient.getLiveTvChannels({
|
||||
ServiceName: service,
|
||||
AddCurrentProgram: false
|
||||
}).then(function (result) {
|
||||
var nodes = result.Items.map(function (i) {
|
||||
|
||||
@@ -25,11 +25,6 @@ define(["dom", "layoutManager", "inputManager", "connectionManager", "events", "
|
||||
if (user && user.name) {
|
||||
if (user.imageUrl) {
|
||||
var url = user.imageUrl;
|
||||
|
||||
if (user.supportsImageParams) {
|
||||
url += "&height=" + Math.round(26 * Math.max(window.devicePixelRatio || 1, 2));
|
||||
}
|
||||
|
||||
updateHeaderUserButton(url);
|
||||
hasImage = true;
|
||||
}
|
||||
|
||||
@@ -10,8 +10,14 @@
|
||||
<p style="margin:2em 0;">${WizardCompleted}</p>
|
||||
|
||||
<div class="wizardNavigation">
|
||||
<button is="emby-button" type="button" class="raised button-cancel" onclick="history.back();"><i class="md-icon">arrow_back</i><span>${LabelPrevious}</span></button>
|
||||
<button is="emby-button" type="button" class="raised btnWizardNext button-submit"><i class="md-icon">check</i><span>${LabelFinish}</span></button>
|
||||
<button is="emby-button" type="button" class="raised button-cancel" onclick="history.back();">
|
||||
<i class="md-icon">arrow_back</i>
|
||||
<span>${LabelPrevious}</span>
|
||||
</button>
|
||||
<button is="emby-button" type="button" class="raised btnWizardNext button-submit">
|
||||
<i class="md-icon">check</i>
|
||||
<span>${LabelFinish}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user