Compare commits
38 Commits
renovate/e
...
release-10
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fc461a830d | ||
|
|
e6e5f38a0d | ||
|
|
756e322e1c | ||
|
|
c9ed8c750e | ||
|
|
5f1af65c2e | ||
|
|
ff88922f19 | ||
|
|
47700dc29c | ||
|
|
c2ebc35080 | ||
|
|
d040177525 | ||
|
|
cac6b42dab | ||
|
|
15e9b645f2 | ||
|
|
1833b348e9 | ||
|
|
ccb74610aa | ||
|
|
5c37ee6276 | ||
|
|
e25721cb34 | ||
|
|
f11b27fc14 | ||
|
|
26d29dc2cb | ||
|
|
537b3a3351 | ||
|
|
ab58d3c3a1 | ||
|
|
e7be594b8f | ||
|
|
229294aecc | ||
|
|
e41c1854d0 | ||
|
|
e355fcdac0 | ||
|
|
453d225c84 | ||
|
|
ec9ab39d26 | ||
|
|
c2d9ca2af9 | ||
|
|
eba30bda75 | ||
|
|
5c9847468f | ||
|
|
027cb4f744 | ||
|
|
37cde45d12 | ||
|
|
875c4e0882 | ||
|
|
ee9d651246 | ||
|
|
7f133ff8cd | ||
|
|
76f9b2c741 | ||
|
|
51768eb119 | ||
|
|
cdaf03a769 | ||
|
|
f1acfda7d2 | ||
|
|
fef30a0be3 |
@@ -59,7 +59,15 @@ jobs:
|
||||
pool:
|
||||
vmImage: 'ubuntu-latest'
|
||||
|
||||
variables:
|
||||
- name: JellyfinVersion
|
||||
value: 0.0.0
|
||||
|
||||
steps:
|
||||
- script: echo "##vso[task.setvariable variable=JellyfinVersion]$( awk -F '/' '{ print $NF }' <<<'$(Build.SourceBranch)' | sed 's/^v//' )"
|
||||
displayName: Set release version (stable)
|
||||
condition: startsWith(variables['Build.SourceBranch'], 'refs/tags')
|
||||
|
||||
- task: Docker@2
|
||||
displayName: 'Push Unstable Image'
|
||||
condition: startsWith(variables['Build.SourceBranch'], 'refs/heads/master')
|
||||
@@ -84,7 +92,7 @@ jobs:
|
||||
containerRegistry: Docker Hub
|
||||
tags: |
|
||||
stable-$(Build.BuildNumber)
|
||||
stable
|
||||
$(JellyfinVersion)
|
||||
|
||||
- job: CollectArtifacts
|
||||
displayName: 'Collect Artifacts'
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
# We just wrap `build` so this is really it
|
||||
name: "jellyfin-web"
|
||||
version: "10.6.0"
|
||||
version: "10.6.4"
|
||||
packages:
|
||||
- debian.all
|
||||
- fedora.all
|
||||
|
||||
23
bump_version
23
bump_version
@@ -4,6 +4,7 @@
|
||||
|
||||
set -o errexit
|
||||
set -o pipefail
|
||||
set -o xtrace
|
||||
|
||||
usage() {
|
||||
echo -e "bump_version - increase the shared version and generate changelogs"
|
||||
@@ -23,10 +24,7 @@ build_file="./build.yaml"
|
||||
new_version="$1"
|
||||
|
||||
# Parse the version from shared version file
|
||||
old_version="$(
|
||||
grep "appVersion" ${shared_version_file} | head -1 \
|
||||
| sed -E 's/var appVersion = "([0-9\.]+)";/\1/'
|
||||
)"
|
||||
old_version="$( grep "appVersion" ${shared_version_file} | head -1 | sed -E "s/var appVersion = '([0-9\.]+)';/\1/" | tr -d '[:space:]' )"
|
||||
echo "Old version in appHost is: $old_version"
|
||||
|
||||
# Set the shared version to the specified new_version
|
||||
@@ -34,11 +32,8 @@ old_version_sed="$( sed 's/\./\\./g' <<<"${old_version}" )" # Escape the '.' cha
|
||||
new_version_sed="$( cut -f1 -d'-' <<<"${new_version}" )"
|
||||
sed -i "s/${old_version_sed}/${new_version_sed}/g" ${shared_version_file}
|
||||
|
||||
old_version="$(
|
||||
grep "version:" ${build_file} \
|
||||
| sed -E 's/version: "([0-9\.]+[-a-z0-9]*)"/\1/'
|
||||
)"
|
||||
echo "Old version in ${build_file}: $old_version`"
|
||||
old_version="$( grep "version:" ${build_file} | sed -E 's/version: "([0-9\.]+[-a-z0-9]*)"/\1/' )"
|
||||
echo "Old version in ${build_file}: ${old_version}"
|
||||
|
||||
# Set the build.yaml version to the specified new_version
|
||||
old_version_sed="$( sed 's/\./\\./g' <<<"${old_version}" )" # Escape the '.' chars
|
||||
@@ -54,7 +49,7 @@ fi
|
||||
debian_changelog_file="debian/changelog"
|
||||
debian_changelog_temp="$( mktemp )"
|
||||
# Create new temp file with our changelog
|
||||
echo -e "jellyfin (${new_version_deb}) unstable; urgency=medium
|
||||
echo -e "jellyfin-web (${new_version_deb}) unstable; urgency=medium
|
||||
|
||||
* New upstream version ${new_version}; release changelog at https://github.com/jellyfin/jellyfin-web/releases/tag/v${new_version}
|
||||
|
||||
@@ -65,15 +60,15 @@ cat ${debian_changelog_file} >> ${debian_changelog_temp}
|
||||
mv ${debian_changelog_temp} ${debian_changelog_file}
|
||||
|
||||
# Write out a temporary Yum changelog with our new stuff prepended and some templated formatting
|
||||
fedora_spec_file="fedora/jellyfin.spec"
|
||||
fedora_spec_file="fedora/jellyfin-web.spec"
|
||||
fedora_changelog_temp="$( mktemp )"
|
||||
fedora_spec_temp_dir="$( mktemp -d )"
|
||||
fedora_spec_temp="${fedora_spec_temp_dir}/jellyfin.spec.tmp"
|
||||
fedora_spec_temp="${fedora_spec_temp_dir}/jellyfin-web.spec.tmp"
|
||||
# Make a copy of our spec file for hacking
|
||||
cp ${fedora_spec_file} ${fedora_spec_temp_dir}/
|
||||
pushd ${fedora_spec_temp_dir}
|
||||
# Split out the stuff before and after changelog
|
||||
csplit jellyfin.spec "/^%changelog/" # produces xx00 xx01
|
||||
csplit jellyfin-web.spec "/^%changelog/" # produces xx00 xx01
|
||||
# Update the version in xx00
|
||||
sed -i "s/${old_version_sed}/${new_version_sed}/g" xx00
|
||||
# Remove the header from xx01
|
||||
@@ -92,5 +87,5 @@ mv ${fedora_spec_temp} ${fedora_spec_file}
|
||||
rm -rf ${fedora_changelog_temp} ${fedora_spec_temp_dir}
|
||||
|
||||
# Stage the changed files for commit
|
||||
git add ${shared_version_file} ${build_file} ${debian_changelog_file} ${fedora_spec_file} Dockerfile*
|
||||
git add ${shared_version_file} ${build_file} ${debian_changelog_file} ${fedora_spec_file}
|
||||
git status
|
||||
|
||||
24
debian/changelog
vendored
24
debian/changelog
vendored
@@ -1,3 +1,27 @@
|
||||
jellyfin-web (10.6.4-1) unstable; urgency=medium
|
||||
|
||||
* New upstream version 10.6.4; release changelog at https://github.com/jellyfin/jellyfin-web/releases/tag/v10.6.4
|
||||
|
||||
-- Jellyfin Packaging Team <packaging@jellyfin.org> Sun, 30 Aug 2020 16:45:08 -0400
|
||||
|
||||
jellyfin-web (10.6.3-1) unstable; urgency=medium
|
||||
|
||||
* New upstream version 10.6.3; release changelog at https://github.com/jellyfin/jellyfin-web/releases/tag/v10.6.3
|
||||
|
||||
-- Jellyfin Packaging Team <packaging@jellyfin.org> Sun, 16 Aug 2020 19:48:03 -0400
|
||||
|
||||
jellyfin-web (10.6.2-1) unstable; urgency=medium
|
||||
|
||||
* New upstream version 10.6.2; release changelog at https://github.com/jellyfin/jellyfin-web/releases/tag/v10.6.2
|
||||
|
||||
-- Jellyfin Packaging Team <packaging@jellyfin.org> Sun, 02 Aug 2020 20:25:58 -0400
|
||||
|
||||
jellyfin-web (10.6.1-1) unstable; urgency=medium
|
||||
|
||||
* New upstream version 10.6.1; release changelog at https://github.com/jellyfin/jellyfin-web/releases/tag/v10.6.1
|
||||
|
||||
-- Jellyfin Packaging Team <packaging@jellyfin.org> Mon, 27 Jul 2020 18:29:54 -0400
|
||||
|
||||
jellyfin-web (10.6.0-1) unstable; urgency=medium
|
||||
|
||||
* New upstream version 10.6.0; release changelog at https://github.com/jellyfin/jellyfin-web/releases/tag/v10.6.0
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
%global debug_package %{nil}
|
||||
|
||||
Name: jellyfin-web
|
||||
Version: 10.6.0
|
||||
Version: 10.6.4
|
||||
Release: 1%{?dist}
|
||||
Summary: The Free Software Media System web client
|
||||
License: GPLv3
|
||||
@@ -11,6 +11,8 @@ Source0: jellyfin-web-%{version}.tar.gz
|
||||
|
||||
%if 0%{?centos}
|
||||
BuildRequires: yarn
|
||||
# sadly the yarn RPM at https://dl.yarnpkg.com/rpm/ uses git but doesn't Requires: it
|
||||
BuildRequires: git
|
||||
%else
|
||||
BuildRequires: nodejs-yarn
|
||||
%endif
|
||||
@@ -39,5 +41,13 @@ mv dist %{buildroot}%{_datadir}/jellyfin-web
|
||||
%{_datadir}/licenses/jellyfin/LICENSE
|
||||
|
||||
%changelog
|
||||
* Sun Aug 30 2020 Jellyfin Packaging Team <packaging@jellyfin.org>
|
||||
- New upstream version 10.6.4; release changelog at https://github.com/jellyfin/jellyfin-web/releases/tag/v10.6.4
|
||||
* Sun Aug 16 2020 Jellyfin Packaging Team <packaging@jellyfin.org>
|
||||
- New upstream version 10.6.3; release changelog at https://github.com/jellyfin/jellyfin-web/releases/tag/v10.6.3
|
||||
* Sun Aug 02 2020 Jellyfin Packaging Team <packaging@jellyfin.org>
|
||||
- New upstream version 10.6.2; release changelog at https://github.com/jellyfin/jellyfin-web/releases/tag/v10.6.2
|
||||
* Mon Jul 27 2020 Jellyfin Packaging Team <packaging@jellyfin.org>
|
||||
- New upstream version 10.6.1; release changelog at https://github.com/jellyfin/jellyfin-web/releases/tag/v10.6.1
|
||||
* Mon Mar 23 2020 Jellyfin Packaging Team <packaging@jellyfin.org>
|
||||
- Forthcoming stable release
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
"hls.js": "^0.14.0",
|
||||
"howler": "^2.2.0",
|
||||
"intersection-observer": "^0.11.0",
|
||||
"jellyfin-apiclient": "^1.3.0",
|
||||
"jellyfin-apiclient": "^1.4.1",
|
||||
"jellyfin-noto": "https://github.com/jellyfin/jellyfin-noto",
|
||||
"jquery": "^3.5.1",
|
||||
"jstree": "^3.3.10",
|
||||
@@ -151,7 +151,7 @@
|
||||
"last 2 Chrome versions",
|
||||
"last 2 ChromeAndroid versions",
|
||||
"last 2 Safari versions",
|
||||
"last 2 iOS versions",
|
||||
"iOS > 10",
|
||||
"last 2 Edge versions",
|
||||
"Chrome 27",
|
||||
"Chrome 38",
|
||||
@@ -159,6 +159,7 @@
|
||||
"Chrome 53",
|
||||
"Chrome 56",
|
||||
"Chrome 63",
|
||||
"Edge 18",
|
||||
"Firefox ESR"
|
||||
],
|
||||
"scripts": {
|
||||
|
||||
@@ -646,7 +646,7 @@
|
||||
.layout-desktop .detailRibbon,
|
||||
.layout-tv .detailRibbon {
|
||||
margin-top: -7.2em;
|
||||
height: 7.18em;
|
||||
height: 7.2em;
|
||||
}
|
||||
|
||||
.layout-desktop .noBackdrop .detailRibbon,
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
}
|
||||
|
||||
.osdPoster img,
|
||||
.pageContainer,
|
||||
.videoOsdBottom {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
@@ -248,11 +247,6 @@
|
||||
animation: spin 4s linear infinite;
|
||||
}
|
||||
|
||||
.pageContainer {
|
||||
top: 0;
|
||||
position: fixed;
|
||||
}
|
||||
|
||||
@media all and (max-width: 30em) {
|
||||
.btnFastForward,
|
||||
.btnRewind,
|
||||
|
||||
1
src/assets/img/devices/edgechromium.svg
Normal file
1
src/assets/img/devices/edgechromium.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" role="img" viewBox="0 0 24 24"><title>Microsoft Edge icon</title><path d="M21.86 17.86q.14 0 .25.12.1.13.1.25t-.11.33l-.32.46-.43.53-.44.5q-.21.25-.38.42l-.22.23q-.58.53-1.34 1.04-.76.51-1.6.91-.86.4-1.74.64t-1.67.24q-.9 0-1.69-.28-.8-.28-1.48-.78-.68-.5-1.22-1.17-.53-.66-.92-1.44-.38-.77-.58-1.6-.2-.83-.2-1.67 0-1 .32-1.96.33-.97.87-1.8.14.95.55 1.77.41.82 1.02 1.5.6.68 1.38 1.21.78.54 1.64.9.86.36 1.77.56.92.2 1.8.2 1.12 0 2.18-.24 1.06-.23 2.06-.72l.2-.1.2-.05zm-15.5-1.27q0 1.1.27 2.15.27 1.06.78 2.03.51.96 1.24 1.77.74.82 1.66 1.4-1.47-.2-2.8-.74-1.33-.55-2.48-1.37-1.15-.83-2.08-1.9-.92-1.07-1.58-2.33T.36 14.94Q0 13.54 0 12.06q0-.81.32-1.49.31-.68.83-1.23.53-.55 1.2-.96.66-.4 1.35-.66.74-.27 1.5-.39.78-.12 1.55-.12.7 0 1.42.1.72.12 1.4.35.68.23 1.32.57.63.35 1.16.83-.35 0-.7.07-.33.07-.65.23v-.02q-.63.28-1.2.74-.57.46-1.05 1.04-.48.58-.87 1.26-.38.67-.65 1.39-.27.71-.42 1.44-.15.72-.15 1.38zM11.96.06q1.7 0 3.33.39 1.63.38 3.07 1.15 1.43.77 2.62 1.93 1.18 1.16 1.98 2.7.49.94.76 1.96.28 1 .28 2.08 0 .89-.23 1.7-.24.8-.69 1.48-.45.68-1.1 1.22-.64.53-1.45.88-.54.24-1.11.36-.58.13-1.16.13-.42 0-.97-.03-.54-.03-1.1-.12-.55-.1-1.05-.28-.5-.19-.84-.5-.12-.09-.23-.24-.1-.16-.1-.33 0-.15.16-.35.16-.2.35-.5.2-.28.36-.68.16-.4.16-.95 0-1.06-.4-1.96-.4-.91-1.06-1.64-.66-.74-1.52-1.28-.86-.55-1.79-.89-.84-.3-1.72-.44-.87-.14-1.76-.14-1.55 0-3.06.45T.94 7.55q.71-1.74 1.81-3.13 1.1-1.38 2.52-2.35Q6.68 1.1 8.37.58q1.7-.52 3.58-.52Z" fill="#fff"/></svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
@@ -105,6 +105,8 @@ define(['appSettings', 'browser', 'events', 'htmlMediaHelper', 'webSettings', 'g
|
||||
deviceName = 'Sony PS4';
|
||||
} else if (browser.chrome) {
|
||||
deviceName = 'Chrome';
|
||||
} else if (browser.edgeChromium) {
|
||||
deviceName = 'Edge Chromium';
|
||||
} else if (browser.edge) {
|
||||
deviceName = 'Edge';
|
||||
} else if (browser.firefox) {
|
||||
@@ -297,7 +299,7 @@ define(['appSettings', 'browser', 'events', 'htmlMediaHelper', 'webSettings', 'g
|
||||
features.push('fileinput');
|
||||
}
|
||||
|
||||
if (browser.chrome) {
|
||||
if (browser.chrome || browser.edgeChromium) {
|
||||
features.push('chromecast');
|
||||
}
|
||||
|
||||
@@ -353,7 +355,7 @@ define(['appSettings', 'browser', 'events', 'htmlMediaHelper', 'webSettings', 'g
|
||||
var deviceId;
|
||||
var deviceName;
|
||||
var appName = 'Jellyfin Web';
|
||||
var appVersion = '10.6.0';
|
||||
var appVersion = '10.6.4';
|
||||
|
||||
var appHost = {
|
||||
getWindowState: function () {
|
||||
|
||||
@@ -70,6 +70,10 @@
|
||||
contain: strict;
|
||||
}
|
||||
|
||||
.programContainer.emby-scroller {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.channelPrograms {
|
||||
height: 4.42em;
|
||||
contain: strict;
|
||||
|
||||
@@ -87,6 +87,9 @@ import 'css!./style';
|
||||
requestAnimationFrame(() => {
|
||||
if (elem.tagName !== 'IMG') {
|
||||
elem.style.backgroundImage = "url('" + url + "')";
|
||||
if (elem.classList.contains('blurhashed')) {
|
||||
elem.style.backgroundColor = '#fff';
|
||||
}
|
||||
} else {
|
||||
elem.setAttribute('src', url);
|
||||
}
|
||||
@@ -108,6 +111,7 @@ import 'css!./style';
|
||||
if (elem.tagName !== 'IMG') {
|
||||
url = elem.style.backgroundImage.slice(4, -1).replace(/"/g, '');
|
||||
elem.style.backgroundImage = 'none';
|
||||
elem.style.backgroundColor = null;
|
||||
} else {
|
||||
url = elem.getAttribute('src');
|
||||
elem.setAttribute('src', '');
|
||||
@@ -120,7 +124,7 @@ import 'css!./style';
|
||||
|
||||
export function lazyChildren(elem) {
|
||||
if (userSettings.enableBlurhash()) {
|
||||
for (const lazyElem of elem.getElementsByClassName('lazy')) {
|
||||
for (const lazyElem of elem.querySelectorAll('.lazy')) {
|
||||
const blurhashstr = lazyElem.getAttribute('data-blurhash');
|
||||
if (!lazyElem.classList.contains('blurhashed', 'non-blurhashable') && blurhashstr) {
|
||||
itemBlurhashing(lazyElem, blurhashstr);
|
||||
|
||||
@@ -245,6 +245,43 @@ define(['itemHelper', 'dom', 'layoutManager', 'dialogHelper', 'datetime', 'loadi
|
||||
});
|
||||
}
|
||||
|
||||
function afterDeleted(context, item) {
|
||||
var parentId = item.ParentId || item.SeasonId || item.SeriesId;
|
||||
|
||||
if (parentId) {
|
||||
reload(context, parentId, item.ServerId);
|
||||
} else {
|
||||
require(['appRouter'], function (appRouter) {
|
||||
appRouter.goHome();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function showMoreMenu(context, button, user) {
|
||||
require(['itemContextMenu'], function (itemContextMenu) {
|
||||
var item = currentItem;
|
||||
|
||||
itemContextMenu.show({
|
||||
item: item,
|
||||
positionTo: button,
|
||||
edit: false,
|
||||
editImages: true,
|
||||
editSubtitles: true,
|
||||
sync: false,
|
||||
share: false,
|
||||
play: false,
|
||||
queue: false,
|
||||
user: user
|
||||
}).then(function (result) {
|
||||
if (result.deleted) {
|
||||
afterDeleted(context, item);
|
||||
} else if (result.updated) {
|
||||
reload(context, item.Id, item.ServerId);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function onEditorClick(e) {
|
||||
|
||||
var btnRemoveFromEditorList = dom.parentWithClass(e.target, 'btnRemoveFromEditorList');
|
||||
@@ -270,7 +307,6 @@ define(['itemHelper', 'dom', 'layoutManager', 'dialogHelper', 'datetime', 'loadi
|
||||
}
|
||||
|
||||
function init(context, apiClient) {
|
||||
|
||||
context.querySelector('.externalIds').addEventListener('click', function (e) {
|
||||
var btnOpenExternalId = dom.parentWithClass(e.target, 'btnOpenExternalId');
|
||||
if (btnOpenExternalId) {
|
||||
@@ -294,13 +330,17 @@ define(['itemHelper', 'dom', 'layoutManager', 'dialogHelper', 'datetime', 'loadi
|
||||
closeDialog(false);
|
||||
});
|
||||
|
||||
context.querySelector('.btnHeaderSave').addEventListener('click', function (e) {
|
||||
context.querySelector('.btnMore').addEventListener('click', function (e) {
|
||||
getApiClient().getCurrentUser().then(function (user) {
|
||||
showMoreMenu(context, e.target, user);
|
||||
});
|
||||
});
|
||||
|
||||
context.querySelector('.btnHeaderSave').addEventListener('click', function (e) {
|
||||
context.querySelector('.btnSave').click();
|
||||
});
|
||||
|
||||
context.querySelector('#chkLockData').addEventListener('click', function (e) {
|
||||
|
||||
if (!e.target.checked) {
|
||||
showElement('.providerSettingsContainer');
|
||||
} else {
|
||||
@@ -1088,6 +1128,7 @@ define(['itemHelper', 'dom', 'layoutManager', 'dialogHelper', 'datetime', 'loadi
|
||||
elem.innerHTML = globalize.translateDocument(template, 'core');
|
||||
|
||||
elem.querySelector('.formDialogFooter').classList.remove('formDialogFooter');
|
||||
elem.querySelector('.btnClose').classList.add('hide');
|
||||
elem.querySelector('.btnHeaderSave').classList.remove('hide');
|
||||
elem.querySelector('.btnCancel').classList.add('hide');
|
||||
|
||||
|
||||
@@ -8,6 +8,9 @@
|
||||
<span class="material-icons check"></span>
|
||||
<span>${Save}</span>
|
||||
</button>
|
||||
<button is="paper-icon-button-light" class="btnMore autoSize" tabindex="-1">
|
||||
<span class="material-icons more_vert"></span>
|
||||
</button>
|
||||
<button is="paper-icon-button-light" class="btnCancel btnClose autoSize" tabindex="-1">
|
||||
<span class="material-icons close"></span>
|
||||
</button>
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'playQueueManager', 'userSettings', 'globalize', 'connectionManager', 'loading', 'apphost', 'screenfull'], function (events, datetime, appSettings, itemHelper, pluginManager, PlayQueueManager, userSettings, globalize, connectionManager, loading, apphost, screenfull) {
|
||||
'use strict';
|
||||
|
||||
/** Delay time in ms for reportPlayback logging */
|
||||
const reportPlaybackLogDelay = 1e3;
|
||||
|
||||
function enableLocalPlaylistManagement(player) {
|
||||
|
||||
if (player.getPlaylist) {
|
||||
@@ -24,6 +21,11 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla
|
||||
screenfull.on('change', function () {
|
||||
events.trigger(player, 'fullscreenchange');
|
||||
});
|
||||
} else {
|
||||
// iOS Safari
|
||||
document.addEventListener('webkitfullscreenchange', function () {
|
||||
events.trigger(player, 'fullscreenchange');
|
||||
}, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,12 +45,6 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla
|
||||
events.trigger(playbackManagerInstance, 'playerchange', [newPlayer, newTarget, previousPlayer]);
|
||||
}
|
||||
|
||||
/** Last invoked method */
|
||||
let reportPlaybackLastMethod;
|
||||
|
||||
/** Last invoke time of method */
|
||||
let reportPlaybackLastTime;
|
||||
|
||||
function reportPlayback(playbackManagerInstance, state, player, reportPlaylist, serverId, method, progressEventName) {
|
||||
|
||||
if (!serverId) {
|
||||
@@ -69,14 +65,6 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla
|
||||
addPlaylistToPlaybackReport(playbackManagerInstance, info, player, serverId);
|
||||
}
|
||||
|
||||
const now = (new Date).getTime();
|
||||
|
||||
if (method !== reportPlaybackLastMethod || now - (reportPlaybackLastTime || 0) >= reportPlaybackLogDelay) {
|
||||
console.debug(method + '-' + JSON.stringify(info));
|
||||
reportPlaybackLastMethod = method;
|
||||
reportPlaybackLastTime = now;
|
||||
}
|
||||
|
||||
var apiClient = connectionManager.getApiClient(serverId);
|
||||
var reportPlaybackPromise = apiClient[method](info);
|
||||
// Notify that report has been sent
|
||||
@@ -1537,6 +1525,11 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla
|
||||
return player.isFullscreen();
|
||||
}
|
||||
|
||||
if (!screenfull.isEnabled) {
|
||||
// iOS Safari
|
||||
return document.webkitIsFullScreen;
|
||||
}
|
||||
|
||||
return screenfull.isFullscreen;
|
||||
};
|
||||
|
||||
@@ -1549,6 +1542,16 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla
|
||||
|
||||
if (screenfull.isEnabled) {
|
||||
screenfull.toggle();
|
||||
} else {
|
||||
// iOS Safari
|
||||
if (document.webkitIsFullScreen && document.webkitCancelFullscreen) {
|
||||
document.webkitCancelFullscreen();
|
||||
} else {
|
||||
const elem = document.querySelector('video');
|
||||
if (elem && elem.webkitEnterFullscreen) {
|
||||
elem.webkitEnterFullscreen();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -3664,6 +3667,14 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla
|
||||
this.seek(parseInt(ticks), player);
|
||||
};
|
||||
|
||||
PlaybackManager.prototype.seekMs = function (ms, player) {
|
||||
|
||||
player = player || this._currentPlayer;
|
||||
|
||||
var ticks = ms * 10000;
|
||||
this.seek(ticks, player);
|
||||
};
|
||||
|
||||
PlaybackManager.prototype.playTrailers = function (item) {
|
||||
|
||||
var player = this._currentPlayer;
|
||||
|
||||
@@ -133,7 +133,7 @@ export function show(button) {
|
||||
|
||||
// Unfortunately we can't allow the url to change or chromecast will throw a security error
|
||||
// Might be able to solve this in the future by moving the dialogs to hashbangs
|
||||
if (!(!browser.chrome || appHost.supports('castmenuhashchange'))) {
|
||||
if (!(!browser.chrome && !browser.edgeChromium || appHost.supports('castmenuhashchange'))) {
|
||||
menuOptions.enableHistory = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -405,7 +405,8 @@ define(['events', 'globalize', 'playbackManager', 'connectionManager', 'syncPlay
|
||||
name: 'Original Media Info'
|
||||
});
|
||||
|
||||
if (syncPlayManager.isSyncPlayEnabled()) {
|
||||
var apiClient = connectionManager.getApiClient(playbackManager.currentItem(player).ServerId);
|
||||
if (syncPlayManager.isSyncPlayEnabled() && apiClient.isMinServerVersion('10.6.0')) {
|
||||
categories.push({
|
||||
stats: getSyncPlayStats(),
|
||||
name: 'SyncPlay Info'
|
||||
|
||||
@@ -119,9 +119,9 @@ define(['browser', 'datetime', 'backdrop', 'libraryBrowser', 'listView', 'imageL
|
||||
var nowPlayingServerId = (item.ServerId || serverId);
|
||||
if (item.Type == 'Audio' || item.MediaStreams[0].Type == 'Audio') {
|
||||
var songName = item.Name;
|
||||
if (item.Album != null && item.Artists != null) {
|
||||
var artistsSeries = '';
|
||||
var albumName = item.Album;
|
||||
var artistsSeries = '';
|
||||
var albumName = '';
|
||||
if (item.Artists != null) {
|
||||
if (item.ArtistItems != null) {
|
||||
for (const artist of item.ArtistItems) {
|
||||
let artistName = artist.Name;
|
||||
@@ -142,9 +142,12 @@ define(['browser', 'datetime', 'backdrop', 'libraryBrowser', 'listView', 'imageL
|
||||
}
|
||||
}
|
||||
}
|
||||
context.querySelector('.nowPlayingArtist').innerHTML = artistsSeries;
|
||||
context.querySelector('.nowPlayingAlbum').innerHTML = '<a class="button-link emby-button" is="emby-linkbutton" href="details?id=' + item.AlbumId + `&serverId=${nowPlayingServerId}">${albumName}</a>`;
|
||||
}
|
||||
if (item.Album != null) {
|
||||
albumName = '<a class="button-link emby-button" is="emby-linkbutton" href="details?id=' + item.AlbumId + `&serverId=${nowPlayingServerId}">` + item.Album + '</a>';
|
||||
}
|
||||
context.querySelector('.nowPlayingAlbum').innerHTML = albumName;
|
||||
context.querySelector('.nowPlayingArtist').innerHTML = artistsSeries;
|
||||
context.querySelector('.nowPlayingSongName').innerHTML = songName;
|
||||
} else if (item.Type == 'Episode') {
|
||||
if (item.SeasonName != null) {
|
||||
|
||||
@@ -84,7 +84,7 @@ function showNewJoinGroupSelection (button, user, apiClient) {
|
||||
actionsheet.show(menuOptions).then(function (id) {
|
||||
if (id == 'new-group') {
|
||||
apiClient.createSyncPlayGroup();
|
||||
} else {
|
||||
} else if (id) {
|
||||
apiClient.joinSyncPlayGroup({
|
||||
GroupId: id,
|
||||
PlayingItemId: playingItemId
|
||||
|
||||
@@ -212,6 +212,7 @@ class SyncPlayManager {
|
||||
if (!this.lastPlaybackWaiting) {
|
||||
this.lastPlaybackWaiting = new Date();
|
||||
}
|
||||
|
||||
events.trigger(this, 'waiting');
|
||||
}
|
||||
|
||||
@@ -288,6 +289,7 @@ class SyncPlayManager {
|
||||
player.setPlaybackRate(this.localPlayerPlaybackRate);
|
||||
this.localPlayerPlaybackRate = 1.0;
|
||||
}
|
||||
|
||||
this.currentPlayer = null;
|
||||
this.playbackRateSupported = false;
|
||||
}
|
||||
@@ -433,6 +435,7 @@ class SyncPlayManager {
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Get playing item id
|
||||
let playingItemId;
|
||||
try {
|
||||
@@ -619,6 +622,7 @@ class SyncPlayManager {
|
||||
if (this.currentPlayer) {
|
||||
this.currentPlayer.setPlaybackRate(1);
|
||||
}
|
||||
|
||||
this.clearSyncIcon();
|
||||
}
|
||||
|
||||
|
||||
@@ -70,8 +70,8 @@ define(['browser', 'dom', 'layoutManager', 'css!components/viewManager/viewConta
|
||||
|
||||
if (currentPage) {
|
||||
if (newViewInfo.hasScript && window.$) {
|
||||
view = $(view).appendTo(mainAnimatedPages)[0];
|
||||
mainAnimatedPages.removeChild(currentPage);
|
||||
view = $(view).appendTo(mainAnimatedPages)[0];
|
||||
} else {
|
||||
mainAnimatedPages.replaceChild(view, currentPage);
|
||||
}
|
||||
|
||||
@@ -114,14 +114,12 @@ define(['jQuery', 'loading', 'libraryMenu', 'globalize', 'connectionManager', 'e
|
||||
})[0];
|
||||
|
||||
var version = $('#selectVersion', page).val();
|
||||
if (installedPlugin) {
|
||||
if (installedPlugin.Version === version) {
|
||||
loading.hide();
|
||||
Dashboard.alert({
|
||||
message: globalize.translate('MessageAlreadyInstalled'),
|
||||
title: globalize.translate('HeaderPluginInstallation')
|
||||
});
|
||||
}
|
||||
if (installedPlugin && installedPlugin.Version === version) {
|
||||
loading.hide();
|
||||
Dashboard.alert({
|
||||
message: globalize.translate('MessageAlreadyInstalled'),
|
||||
title: globalize.translate('HeaderPluginInstallation')
|
||||
});
|
||||
} else {
|
||||
performInstallation(page, name, guid, version);
|
||||
}
|
||||
|
||||
@@ -104,7 +104,9 @@ define(['jQuery', 'loading', 'libraryMenu', 'globalize'], function ($, loading,
|
||||
$('#chkEnableSharing', page).prop('checked', user.Policy.EnablePublicSharing);
|
||||
$('#txtRemoteClientBitrateLimit', page).val(user.Policy.RemoteClientBitrateLimit / 1e6 || '');
|
||||
$('#txtLoginAttemptsBeforeLockout', page).val(user.Policy.LoginAttemptsBeforeLockout || '0');
|
||||
$('#selectSyncPlayAccess').val(user.Policy.SyncPlayAccess);
|
||||
if (ApiClient.isMinServerVersion('10.6.0')) {
|
||||
$('#selectSyncPlayAccess').val(user.Policy.SyncPlayAccess);
|
||||
}
|
||||
loading.hide();
|
||||
}
|
||||
|
||||
@@ -146,7 +148,9 @@ define(['jQuery', 'loading', 'libraryMenu', 'globalize'], function ($, loading,
|
||||
}).map(function (c) {
|
||||
return c.getAttribute('data-id');
|
||||
});
|
||||
user.Policy.SyncPlayAccess = page.querySelector('#selectSyncPlayAccess').value;
|
||||
if (ApiClient.isMinServerVersion('10.6.0')) {
|
||||
user.Policy.SyncPlayAccess = page.querySelector('#selectSyncPlayAccess').value;
|
||||
}
|
||||
ApiClient.updateUser(user).then(function () {
|
||||
ApiClient.updateUserPolicy(user.Id, user.Policy).then(function () {
|
||||
onSaveComplete(page, user);
|
||||
|
||||
@@ -251,7 +251,7 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti
|
||||
return 'Video' === m.Type;
|
||||
});
|
||||
|
||||
// This only makes sence on Video items
|
||||
// This only makes sense on Video items
|
||||
if (videoTracks.length) {
|
||||
var selected = -1 === selectedId ? ' selected' : '';
|
||||
select.innerHTML = '<option value="-1">' + globalize.translate('Off') + '</option>' + tracks.map(function (v) {
|
||||
@@ -259,7 +259,7 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti
|
||||
return '<option value="' + v.Index + '" ' + selected + '>' + v.DisplayTitle + '</option>';
|
||||
}).join('');
|
||||
|
||||
if (tracks.length > 1) {
|
||||
if (tracks.length > 0) {
|
||||
select.removeAttribute('disabled');
|
||||
} else {
|
||||
select.setAttribute('disabled', 'disabled');
|
||||
@@ -523,6 +523,14 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti
|
||||
});
|
||||
imageLoader.lazyImage(itemBackdropElement, imgUrl);
|
||||
hasbackdrop = true;
|
||||
} else if (item.ImageTags && item.ImageTags.Primary) {
|
||||
imgUrl = apiClient.getScaledImageUrl(item.Id, {
|
||||
type: 'Primary',
|
||||
maxWidth: dom.getScreenWidth(),
|
||||
tag: item.ImageTags.Primary
|
||||
});
|
||||
imageLoader.lazyImage(itemBackdropElement, imgUrl);
|
||||
hasbackdrop = true;
|
||||
} else {
|
||||
itemBackdropElement.style.backgroundImage = '';
|
||||
}
|
||||
|
||||
@@ -45,6 +45,10 @@ define(['playbackManager', 'dom', 'inputManager', 'datetime', 'itemHelper', 'med
|
||||
return null;
|
||||
}
|
||||
|
||||
function getOpenedDialog() {
|
||||
return document.querySelector('.dialogContainer .dialog.opened');
|
||||
}
|
||||
|
||||
return function (view, params) {
|
||||
function onVerticalSwipe(e, elem, data) {
|
||||
var player = currentPlayer;
|
||||
@@ -333,21 +337,15 @@ define(['playbackManager', 'dom', 'inputManager', 'datetime', 'itemHelper', 'med
|
||||
osdPoster.innerHTML = '';
|
||||
}
|
||||
|
||||
let osdLockCount = 0;
|
||||
let mouseIsDown = false;
|
||||
|
||||
function showOsd() {
|
||||
slideDownToShow(headerElement);
|
||||
showMainOsdControls();
|
||||
if (!osdLockCount) {
|
||||
startOsdHideTimer();
|
||||
}
|
||||
resetIdle();
|
||||
}
|
||||
|
||||
function hideOsd() {
|
||||
if (osdLockCount) {
|
||||
return;
|
||||
}
|
||||
|
||||
slideUpToHide(headerElement);
|
||||
hideMainOsdControls();
|
||||
}
|
||||
@@ -360,19 +358,6 @@ define(['playbackManager', 'dom', 'inputManager', 'datetime', 'itemHelper', 'med
|
||||
}
|
||||
}
|
||||
|
||||
function lockOsd() {
|
||||
osdLockCount++;
|
||||
stopOsdHideTimer();
|
||||
}
|
||||
|
||||
function unlockOsd() {
|
||||
osdLockCount--;
|
||||
// Restart hide timer if OSD is currently visible
|
||||
if (currentVisibleMenu && !osdLockCount) {
|
||||
startOsdHideTimer();
|
||||
}
|
||||
}
|
||||
|
||||
function startOsdHideTimer() {
|
||||
stopOsdHideTimer();
|
||||
osdHideTimeout = setTimeout(hideOsd, 3e3);
|
||||
@@ -444,6 +429,17 @@ define(['playbackManager', 'dom', 'inputManager', 'datetime', 'itemHelper', 'med
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Move all idle-related code to `inputManager` or `idleManager` or `idleHelper` (per dialog thing) and listen event from there.
|
||||
|
||||
function resetIdle() {
|
||||
// Restart hide timer if OSD is currently visible and there is no opened dialog
|
||||
if (currentVisibleMenu && !mouseIsDown && !getOpenedDialog()) {
|
||||
startOsdHideTimer();
|
||||
} else {
|
||||
stopOsdHideTimer();
|
||||
}
|
||||
}
|
||||
|
||||
function onPointerMove(e) {
|
||||
if ('mouse' === (e.pointerType || (layoutManager.mobile ? 'touch' : 'mouse'))) {
|
||||
var eventX = e.screenX || 0;
|
||||
@@ -960,7 +956,11 @@ define(['playbackManager', 'dom', 'inputManager', 'datetime', 'itemHelper', 'med
|
||||
stats: true,
|
||||
suboffset: showSubOffset,
|
||||
onOption: onSettingsOption
|
||||
}).finally(() => {
|
||||
resetIdle();
|
||||
});
|
||||
|
||||
setTimeout(resetIdle, 0);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -1029,7 +1029,11 @@ define(['playbackManager', 'dom', 'inputManager', 'datetime', 'itemHelper', 'med
|
||||
if (index !== currentIndex) {
|
||||
playbackManager.setAudioStreamIndex(index, player);
|
||||
}
|
||||
}).finally(() => {
|
||||
resetIdle();
|
||||
});
|
||||
|
||||
setTimeout(resetIdle, 0);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1073,7 +1077,11 @@ define(['playbackManager', 'dom', 'inputManager', 'datetime', 'itemHelper', 'med
|
||||
}
|
||||
|
||||
toggleSubtitleSync();
|
||||
}).finally(() => {
|
||||
resetIdle();
|
||||
});
|
||||
|
||||
setTimeout(resetIdle, 0);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1102,7 +1110,7 @@ define(['playbackManager', 'dom', 'inputManager', 'datetime', 'itemHelper', 'med
|
||||
var clickedElement;
|
||||
|
||||
function onKeyDown(e) {
|
||||
clickedElement = e.srcElement;
|
||||
clickedElement = e.target;
|
||||
|
||||
var key = keyboardnavigation.getKeyName(e);
|
||||
|
||||
@@ -1124,7 +1132,7 @@ define(['playbackManager', 'dom', 'inputManager', 'datetime', 'itemHelper', 'med
|
||||
case 'Escape':
|
||||
case 'Back':
|
||||
// Ignore key when some dialog is opened
|
||||
if (currentVisibleMenu === 'osd' && !document.querySelector('.dialogContainer')) {
|
||||
if (currentVisibleMenu === 'osd' && !getOpenedDialog()) {
|
||||
hideOsd();
|
||||
e.stopPropagation();
|
||||
}
|
||||
@@ -1216,28 +1224,35 @@ define(['playbackManager', 'dom', 'inputManager', 'datetime', 'itemHelper', 'med
|
||||
}
|
||||
|
||||
function onKeyDownCapture() {
|
||||
// Restart hide timer if OSD is currently visible
|
||||
if (currentVisibleMenu) {
|
||||
showOsd();
|
||||
}
|
||||
resetIdle();
|
||||
}
|
||||
|
||||
function onWindowMouseDown(e) {
|
||||
clickedElement = e.srcElement;
|
||||
lockOsd();
|
||||
clickedElement = e.target;
|
||||
mouseIsDown = true;
|
||||
resetIdle();
|
||||
}
|
||||
|
||||
function onWindowMouseUp() {
|
||||
unlockOsd();
|
||||
mouseIsDown = false;
|
||||
resetIdle();
|
||||
}
|
||||
|
||||
function onWindowTouchStart(e) {
|
||||
clickedElement = e.srcElement;
|
||||
lockOsd();
|
||||
clickedElement = e.target;
|
||||
mouseIsDown = true;
|
||||
resetIdle();
|
||||
}
|
||||
|
||||
function onWindowTouchEnd() {
|
||||
unlockOsd();
|
||||
mouseIsDown = false;
|
||||
resetIdle();
|
||||
}
|
||||
|
||||
function onWindowDragEnd() {
|
||||
// mousedown -> dragstart -> dragend !!! no mouseup :(
|
||||
mouseIsDown = false;
|
||||
resetIdle();
|
||||
}
|
||||
|
||||
function getImgUrl(item, chapter, index, maxWidth, apiClient) {
|
||||
@@ -1373,24 +1388,33 @@ define(['playbackManager', 'dom', 'inputManager', 'datetime', 'itemHelper', 'med
|
||||
inputManager.on(window, onInputCommand);
|
||||
document.addEventListener('keydown', onKeyDown);
|
||||
dom.addEventListener(document, 'keydown', onKeyDownCapture, {
|
||||
capture: true
|
||||
capture: true,
|
||||
passive: true
|
||||
});
|
||||
/* eslint-disable-next-line compat/compat */
|
||||
dom.addEventListener(window, window.PointerEvent ? 'pointerdown' : 'mousedown', onWindowMouseDown, {
|
||||
capture: true,
|
||||
passive: true
|
||||
});
|
||||
/* eslint-disable-next-line compat/compat */
|
||||
dom.addEventListener(window, window.PointerEvent ? 'pointerup' : 'mouseup', onWindowMouseUp, {
|
||||
capture: true,
|
||||
passive: true
|
||||
});
|
||||
dom.addEventListener(window, 'touchstart', onWindowTouchStart, {
|
||||
capture: true,
|
||||
passive: true
|
||||
});
|
||||
['touchend', 'touchcancel'].forEach((event) => {
|
||||
dom.addEventListener(window, event, onWindowTouchEnd, {
|
||||
capture: true,
|
||||
passive: true
|
||||
});
|
||||
});
|
||||
dom.addEventListener(window, 'dragend', onWindowDragEnd, {
|
||||
capture: true,
|
||||
passive: true
|
||||
});
|
||||
} catch (e) {
|
||||
require(['appRouter'], function(appRouter) {
|
||||
appRouter.goHome();
|
||||
@@ -1404,24 +1428,33 @@ define(['playbackManager', 'dom', 'inputManager', 'datetime', 'itemHelper', 'med
|
||||
|
||||
document.removeEventListener('keydown', onKeyDown);
|
||||
dom.removeEventListener(document, 'keydown', onKeyDownCapture, {
|
||||
capture: true
|
||||
capture: true,
|
||||
passive: true
|
||||
});
|
||||
/* eslint-disable-next-line compat/compat */
|
||||
dom.removeEventListener(window, window.PointerEvent ? 'pointerdown' : 'mousedown', onWindowMouseDown, {
|
||||
capture: true,
|
||||
passive: true
|
||||
});
|
||||
/* eslint-disable-next-line compat/compat */
|
||||
dom.removeEventListener(window, window.PointerEvent ? 'pointerup' : 'mouseup', onWindowMouseUp, {
|
||||
capture: true,
|
||||
passive: true
|
||||
});
|
||||
dom.removeEventListener(window, 'touchstart', onWindowTouchStart, {
|
||||
capture: true,
|
||||
passive: true
|
||||
});
|
||||
['touchend', 'touchcancel'].forEach((event) => {
|
||||
dom.removeEventListener(window, event, onWindowTouchEnd, {
|
||||
capture: true,
|
||||
passive: true
|
||||
});
|
||||
});
|
||||
dom.removeEventListener(window, 'dragend', onWindowDragEnd, {
|
||||
capture: true,
|
||||
passive: true
|
||||
});
|
||||
stopOsdHideTimer();
|
||||
headerElement.classList.remove('osdHeader');
|
||||
headerElement.classList.remove('osdHeader-hidden');
|
||||
|
||||
@@ -6,7 +6,7 @@ define(['browser', 'dom', 'css!./emby-checkbox', 'webcomponents'], function (bro
|
||||
function onKeyDown(e) {
|
||||
// Don't submit form on enter
|
||||
// Real (non-emulator) Tizen does nothing on Space
|
||||
if (e.keyCode === 13 || e.keyCode === 32) {
|
||||
if (e.keyCode === 13 || (e.keyCode === 32 && browser.tizen)) {
|
||||
e.preventDefault();
|
||||
|
||||
this.checked = !this.checked;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
define(['layoutManager', 'css!./emby-radio', 'webcomponents'], function (layoutManager) {
|
||||
define(['browser', 'layoutManager', 'css!./emby-radio', 'webcomponents'], function (browser, layoutManager) {
|
||||
'use strict';
|
||||
|
||||
var EmbyRadioPrototype = Object.create(HTMLInputElement.prototype);
|
||||
@@ -7,7 +7,7 @@ define(['layoutManager', 'css!./emby-radio', 'webcomponents'], function (layoutM
|
||||
|
||||
// Don't submit form on enter
|
||||
// Real (non-emulator) Tizen does nothing on Space
|
||||
if (e.keyCode === 13 || e.keyCode === 32) {
|
||||
if (e.keyCode === 13 || (e.keyCode === 32 && browser.tizen)) {
|
||||
e.preventDefault();
|
||||
|
||||
if (!this.checked) {
|
||||
|
||||
@@ -129,7 +129,7 @@
|
||||
animation: fadein 0.5s;
|
||||
width: 30%;
|
||||
height: 30%;
|
||||
background-image: url(assets/img/banner-light.png);
|
||||
background-image: url(assets/img/icon-transparent.png);
|
||||
background-position: center center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: contain;
|
||||
@@ -139,6 +139,14 @@
|
||||
-webkit-transform: translate(-50%, -50%);
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
|
||||
@media screen
|
||||
and (min-device-width: 992px)
|
||||
and (-webkit-min-device-pixel-ratio: 1) {
|
||||
.splashLogo {
|
||||
background-image: url(assets/img/banner-light.png);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -2,6 +2,7 @@ import connectionManager from 'connectionManager';
|
||||
import loading from 'loading';
|
||||
import keyboardnavigation from 'keyboardnavigation';
|
||||
import dialogHelper from 'dialogHelper';
|
||||
import dom from 'dom';
|
||||
import events from 'events';
|
||||
import 'css!./style';
|
||||
import 'material-icons';
|
||||
@@ -93,23 +94,22 @@ export class BookPlayer {
|
||||
|
||||
onWindowKeyUp(e) {
|
||||
let key = keyboardnavigation.getKeyName(e);
|
||||
let rendition = this._rendition;
|
||||
|
||||
// TODO: depending on the event this can be the document or the rendition itself
|
||||
let rendition = this._rendition || this;
|
||||
let book = rendition.book;
|
||||
|
||||
if (this._loaded === false) return;
|
||||
switch (key) {
|
||||
case 'l':
|
||||
case 'ArrowRight':
|
||||
case 'Right':
|
||||
if (this._loaded) {
|
||||
book.package.metadata.direction === 'rtl' ? rendition.prev() : rendition.next();
|
||||
}
|
||||
book.package.metadata.direction === 'rtl' ? rendition.prev() : rendition.next();
|
||||
break;
|
||||
case 'j':
|
||||
case 'ArrowLeft':
|
||||
case 'Left':
|
||||
if (this._loaded) {
|
||||
book.package.metadata.direction === 'rtl' ? rendition.next() : rendition.prev();
|
||||
}
|
||||
book.package.metadata.direction === 'rtl' ? rendition.next() : rendition.prev();
|
||||
break;
|
||||
case 'Escape':
|
||||
if (this._tocElement) {
|
||||
@@ -123,6 +123,25 @@ export class BookPlayer {
|
||||
}
|
||||
}
|
||||
|
||||
onTouchStart(e) {
|
||||
// TODO: depending on the event this can be the document or the rendition itself
|
||||
let rendition = this._rendition || this;
|
||||
let book = rendition.book;
|
||||
|
||||
// check that the event is from the book or the document
|
||||
if (!book || this._loaded === false) return;
|
||||
|
||||
// epubjs stores pages off the screen or something for preloading
|
||||
// get the modulus of the touch event to account for the increased width
|
||||
if (!e.touches || e.touches.length === 0) return;
|
||||
let touch = e.touches[0].clientX % dom.getWindowSize().innerWidth;
|
||||
if (touch < dom.getWindowSize().innerWidth / 2) {
|
||||
book.package.metadata.direction === 'rtl' ? rendition.next() : rendition.prev();
|
||||
} else {
|
||||
book.package.metadata.direction === 'rtl' ? rendition.prev() : rendition.next();
|
||||
}
|
||||
}
|
||||
|
||||
onDialogClosed() {
|
||||
this.stop();
|
||||
}
|
||||
@@ -139,8 +158,11 @@ export class BookPlayer {
|
||||
this.bindMediaElementEvents();
|
||||
|
||||
document.addEventListener('keyup', this.onWindowKeyUp);
|
||||
document.addEventListener('touchstart', this.onTouchStart);
|
||||
|
||||
// FIXME: I don't really get why document keyup event is not triggered when epub is in focus
|
||||
this._rendition.on('keyup', this.onWindowKeyUp);
|
||||
this._rendition.on('touchstart', this.onTouchStart);
|
||||
}
|
||||
|
||||
unbindMediaElementEvents() {
|
||||
@@ -155,9 +177,13 @@ export class BookPlayer {
|
||||
if (this._mediaElement) {
|
||||
this.unbindMediaElementEvents();
|
||||
}
|
||||
|
||||
document.removeEventListener('keyup', this.onWindowKeyUp);
|
||||
document.removeEventListener('touchstart', this.onTouchStart);
|
||||
|
||||
if (this._rendition) {
|
||||
this._rendition.off('keyup', this.onWindowKeyUp);
|
||||
this._rendition.off('touchstart', this.onTouchStart);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,13 +195,11 @@ export class BookPlayer {
|
||||
|
||||
createMediaElement() {
|
||||
let elem = this._mediaElement;
|
||||
|
||||
if (elem) {
|
||||
return elem;
|
||||
}
|
||||
|
||||
elem = document.getElementById('bookPlayer');
|
||||
|
||||
if (!elem) {
|
||||
elem = dialogHelper.createDialog({
|
||||
exitAnimationDuration: 400,
|
||||
@@ -185,6 +209,7 @@ export class BookPlayer {
|
||||
exitAnimation: 'fadeout',
|
||||
removeOnClose: true
|
||||
});
|
||||
|
||||
elem.id = 'bookPlayer';
|
||||
|
||||
let html = '';
|
||||
@@ -230,6 +255,7 @@ export class BookPlayer {
|
||||
let cancellationToken = {
|
||||
shouldCancel: false
|
||||
};
|
||||
|
||||
this._cancellationToken = cancellationToken;
|
||||
|
||||
return rendition.display().then(() => {
|
||||
@@ -253,7 +279,6 @@ export class BookPlayer {
|
||||
epubElem.style.display = 'block';
|
||||
rendition.on('relocated', (locations) => {
|
||||
this._progress = book.locations.percentageFromCfi(locations.start.cfi);
|
||||
|
||||
events.trigger(this, 'timeupdate');
|
||||
});
|
||||
|
||||
@@ -262,7 +287,7 @@ export class BookPlayer {
|
||||
return resolve();
|
||||
});
|
||||
}, () => {
|
||||
console.error('Failed to display epub');
|
||||
console.error('failed to display epub');
|
||||
return reject();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -804,6 +804,11 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa
|
||||
|
||||
if (screenfull.isEnabled) {
|
||||
screenfull.exit();
|
||||
} else {
|
||||
// iOS Safari
|
||||
if (document.webkitIsFullScreen && document.webkitCancelFullscreen) {
|
||||
document.webkitCancelFullscreen();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -135,7 +135,10 @@ define([], function () {
|
||||
var uaMatch = function (ua) {
|
||||
ua = ua.toLowerCase();
|
||||
|
||||
var match = /(edge)[ \/]([\w.]+)/.exec(ua) ||
|
||||
var match = /(edg)[ \/]([\w.]+)/.exec(ua) ||
|
||||
/(edga)[ \/]([\w.]+)/.exec(ua) ||
|
||||
/(edgios)[ \/]([\w.]+)/.exec(ua) ||
|
||||
/(edge)[ \/]([\w.]+)/.exec(ua) ||
|
||||
/(opera)[ \/]([\w.]+)/.exec(ua) ||
|
||||
/(opr)[ \/]([\w.]+)/.exec(ua) ||
|
||||
/(chrome)[ \/]([\w.]+)/.exec(ua) ||
|
||||
@@ -198,7 +201,9 @@ define([], function () {
|
||||
browser[matched.platform] = true;
|
||||
}
|
||||
|
||||
if (!browser.chrome && !browser.edge && !browser.opera && userAgent.toLowerCase().indexOf('webkit') !== -1) {
|
||||
browser.edgeChromium = browser.edg || browser.edga || browser.edgios;
|
||||
|
||||
if (!browser.chrome && !browser.edgeChromium && !browser.edge && !browser.opera && userAgent.toLowerCase().indexOf('webkit') !== -1) {
|
||||
browser.safari = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -144,6 +144,10 @@ define(['browser'], function (browser) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (browser.edgeChromium && browser.windows) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (browser.edgeUwp) {
|
||||
return true;
|
||||
}
|
||||
@@ -210,7 +214,7 @@ define(['browser'], function (browser) {
|
||||
supported = browser.tizen;
|
||||
break;
|
||||
case 'mov':
|
||||
supported = browser.tizen || browser.web0s || browser.chrome || browser.edgeUwp;
|
||||
supported = browser.tizen || browser.web0s || browser.chrome || browser.edgeChromium || browser.edgeUwp;
|
||||
videoCodecs.push('h264');
|
||||
break;
|
||||
case 'm2ts':
|
||||
@@ -710,33 +714,29 @@ define(['browser'], function (browser) {
|
||||
}
|
||||
}
|
||||
|
||||
profile.CodecProfiles.push({
|
||||
Type: 'Video',
|
||||
Codec: 'h264',
|
||||
Conditions: [
|
||||
{
|
||||
Condition: 'NotEquals',
|
||||
Property: 'IsAnamorphic',
|
||||
Value: 'true',
|
||||
IsRequired: false
|
||||
},
|
||||
{
|
||||
Condition: 'EqualsAny',
|
||||
Property: 'VideoProfile',
|
||||
Value: h264Profiles,
|
||||
IsRequired: false
|
||||
},
|
||||
{
|
||||
Condition: 'LessThanEqual',
|
||||
Property: 'VideoLevel',
|
||||
Value: maxH264Level.toString(),
|
||||
IsRequired: false
|
||||
}
|
||||
]
|
||||
});
|
||||
const h264CodecProfileConditions = [
|
||||
{
|
||||
Condition: 'NotEquals',
|
||||
Property: 'IsAnamorphic',
|
||||
Value: 'true',
|
||||
IsRequired: false
|
||||
},
|
||||
{
|
||||
Condition: 'EqualsAny',
|
||||
Property: 'VideoProfile',
|
||||
Value: h264Profiles,
|
||||
IsRequired: false
|
||||
},
|
||||
{
|
||||
Condition: 'LessThanEqual',
|
||||
Property: 'VideoLevel',
|
||||
Value: maxH264Level.toString(),
|
||||
IsRequired: false
|
||||
}
|
||||
];
|
||||
|
||||
if (!browser.edgeUwp && !browser.tizen && !browser.web0s) {
|
||||
profile.CodecProfiles[profile.CodecProfiles.length - 1].Conditions.push({
|
||||
h264CodecProfileConditions.push({
|
||||
Condition: 'NotEquals',
|
||||
Property: 'IsInterlaced',
|
||||
Value: 'true',
|
||||
@@ -745,7 +745,7 @@ define(['browser'], function (browser) {
|
||||
}
|
||||
|
||||
if (maxVideoWidth) {
|
||||
profile.CodecProfiles[profile.CodecProfiles.length - 1].Conditions.push({
|
||||
h264CodecProfileConditions.push({
|
||||
Condition: 'LessThanEqual',
|
||||
Property: 'Width',
|
||||
Value: maxVideoWidth.toString(),
|
||||
@@ -758,7 +758,7 @@ define(['browser'], function (browser) {
|
||||
var h264MaxVideoBitrate = globalMaxVideoBitrate;
|
||||
|
||||
if (h264MaxVideoBitrate) {
|
||||
profile.CodecProfiles[profile.CodecProfiles.length - 1].Conditions.push({
|
||||
h264CodecProfileConditions.push({
|
||||
Condition: 'LessThanEqual',
|
||||
Property: 'VideoBitrate',
|
||||
Value: h264MaxVideoBitrate,
|
||||
@@ -766,6 +766,33 @@ define(['browser'], function (browser) {
|
||||
});
|
||||
}
|
||||
|
||||
// On iOS 12.x, for TS container max h264 level is 4.2
|
||||
if (browser.iOS && browser.iOSVersion < 13) {
|
||||
const codecProfile = {
|
||||
Type: 'Video',
|
||||
Codec: 'h264',
|
||||
Container: 'ts',
|
||||
Conditions: h264CodecProfileConditions.filter((condition) => {
|
||||
return condition.Property !== 'VideoLevel';
|
||||
})
|
||||
};
|
||||
|
||||
codecProfile.Conditions.push({
|
||||
Condition: 'LessThanEqual',
|
||||
Property: 'VideoLevel',
|
||||
Value: '42',
|
||||
IsRequired: false
|
||||
});
|
||||
|
||||
profile.CodecProfiles.push(codecProfile);
|
||||
}
|
||||
|
||||
profile.CodecProfiles.push({
|
||||
Type: 'Video',
|
||||
Codec: 'h264',
|
||||
Conditions: h264CodecProfileConditions
|
||||
});
|
||||
|
||||
var globalVideoConditions = [];
|
||||
|
||||
if (globalMaxVideoBitrate) {
|
||||
|
||||
@@ -32,6 +32,11 @@ import browser from 'browser';
|
||||
case 'Safari iPad':
|
||||
case 'Safari iPhone':
|
||||
return baseUrl + 'safari.svg';
|
||||
case 'Edge Chromium':
|
||||
case 'Edge Chromium Android':
|
||||
case 'Edge Chromium iPad':
|
||||
case 'Edge Chromium iPhone':
|
||||
return baseUrl + 'edgechromium.svg';
|
||||
case 'Edge':
|
||||
return baseUrl + 'edge.svg';
|
||||
case 'Internet Explorer':
|
||||
|
||||
@@ -66,9 +66,12 @@ import appHost from 'apphost';
|
||||
if (!sourceElement) {
|
||||
sourceElement = document.activeElement || window;
|
||||
|
||||
const dlg = document.querySelector('.dialogContainer .dialog.opened');
|
||||
const dialogs = document.querySelectorAll('.dialogContainer .dialog.opened');
|
||||
|
||||
if (dlg && (!sourceElement || !dlg.contains(sourceElement))) {
|
||||
// Suppose the top open dialog is active
|
||||
const dlg = dialogs.length ? dialogs[dialogs.length - 1] : null;
|
||||
|
||||
if (dlg && !dlg.contains(sourceElement)) {
|
||||
sourceElement = dlg;
|
||||
}
|
||||
}
|
||||
@@ -201,6 +204,9 @@ import appHost from 'apphost';
|
||||
'rewind': () => {
|
||||
playbackManager.rewind();
|
||||
},
|
||||
'seek': () => {
|
||||
playbackManager.seekMs(options);
|
||||
},
|
||||
'togglefullscreen': () => {
|
||||
playbackManager.toggleFullscreen();
|
||||
},
|
||||
|
||||
@@ -89,7 +89,8 @@ define(['dom', 'layoutManager', 'inputManager', 'connectionManager', 'events', '
|
||||
|
||||
var policy = user.Policy ? user.Policy : user.localUser.Policy;
|
||||
|
||||
if (headerSyncButton && policy && policy.SyncPlayAccess !== 'None') {
|
||||
var apiClient = getCurrentApiClient();
|
||||
if (headerSyncButton && policy && policy.SyncPlayAccess !== 'None' && apiClient.isMinServerVersion('10.6.0')) {
|
||||
headerSyncButton.classList.remove('hide');
|
||||
}
|
||||
} else {
|
||||
@@ -967,8 +968,10 @@ define(['dom', 'layoutManager', 'inputManager', 'connectionManager', 'events', '
|
||||
updateUserInHeader();
|
||||
});
|
||||
events.on(playbackManager, 'playerchange', updateCastIcon);
|
||||
|
||||
events.on(syncPlayManager, 'enabled', onSyncPlayEnabled);
|
||||
events.on(syncPlayManager, 'syncing', onSyncPlaySyncing);
|
||||
|
||||
loadNavDrawer();
|
||||
return LibraryMenu;
|
||||
});
|
||||
|
||||
@@ -494,7 +494,7 @@ var AppInfo = {};
|
||||
if (appHost.supports('remotecontrol')) {
|
||||
list.push('plugins/sessionPlayer/plugin');
|
||||
|
||||
if (browser.chrome || browser.opera) {
|
||||
if (browser.chrome || browser.edgeChromium || browser.opera) {
|
||||
list.push('plugins/chromecastPlayer/plugin');
|
||||
}
|
||||
}
|
||||
@@ -623,6 +623,7 @@ var AppInfo = {};
|
||||
}
|
||||
|
||||
var localApiClient;
|
||||
let promise;
|
||||
|
||||
(function () {
|
||||
var urlArgs = 'v=' + (window.dashboardVersion || new Date().getDate());
|
||||
@@ -706,20 +707,12 @@ var AppInfo = {};
|
||||
onError: onRequireJsError
|
||||
});
|
||||
|
||||
require(['fetch']);
|
||||
require(['polyfill']);
|
||||
require(['fast-text-encoding']);
|
||||
require(['intersection-observer']);
|
||||
require(['classlist-polyfill']);
|
||||
|
||||
// Expose jQuery globally
|
||||
require(['jQuery'], function(jQuery) {
|
||||
window.$ = jQuery;
|
||||
window.jQuery = jQuery;
|
||||
});
|
||||
|
||||
require(['css!assets/css/site']);
|
||||
require(['jellyfin-noto']);
|
||||
promise = require(['fetch'])
|
||||
.then(() => require(['jQuery', 'polyfill', 'fast-text-encoding', 'intersection-observer', 'classlist-polyfill', 'css!assets/css/site', 'jellyfin-noto'], (jQuery) => {
|
||||
// Expose jQuery globally
|
||||
window.$ = jQuery;
|
||||
window.jQuery = jQuery;
|
||||
}));
|
||||
|
||||
// define styles
|
||||
// TODO determine which of these files can be moved to the components themselves
|
||||
@@ -1130,7 +1123,7 @@ var AppInfo = {};
|
||||
});
|
||||
})();
|
||||
|
||||
return onWebComponentsReady();
|
||||
promise.then(onWebComponentsReady);
|
||||
}();
|
||||
|
||||
pageClassOn('viewshow', 'standalonePage', function () {
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
<div id="videoOsdPage" data-role="page" class="page libraryPage" data-backbutton="true">
|
||||
<div class="pageContainer flex"></div>
|
||||
<div class="upNextContainer hide"></div>
|
||||
<div class="videoOsdBottom videoOsdBottom-maincontrols">
|
||||
<div class="osdPoster"></div>
|
||||
|
||||
@@ -6280,10 +6280,10 @@ isurl@^1.0.0-alpha5:
|
||||
has-to-string-tag-x "^1.2.0"
|
||||
is-object "^1.0.1"
|
||||
|
||||
jellyfin-apiclient@^1.3.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/jellyfin-apiclient/-/jellyfin-apiclient-1.4.0.tgz#d8fedc88cc177597290687be31e38de3cd0d035a"
|
||||
integrity sha512-v2lcSZwcbKh3YSrZkBwNM7tisxvUJHZawz0xpxIobEI6MHrQLo4oDdm1zHXN6Mku9uzbuBpbAV1tA6XJwVVTyA==
|
||||
jellyfin-apiclient@^1.4.1:
|
||||
version "1.4.1"
|
||||
resolved "https://registry.yarnpkg.com/jellyfin-apiclient/-/jellyfin-apiclient-1.4.1.tgz#5e544a19bc001b16669eb7ecf46bb7d652365e41"
|
||||
integrity sha512-BTTRucQ4tCLyiZ9kR9nAoxqxYp5/z+MCzkayy9vmMZ5C7jlVVsnxAXuuZjoa+AgXMjohXcM5Ci54myfJM1pRkA==
|
||||
|
||||
"jellyfin-noto@https://github.com/jellyfin/jellyfin-noto":
|
||||
version "1.0.3"
|
||||
|
||||
Reference in New Issue
Block a user