mirror of
https://github.com/jellyfin/jellyfin-web
synced 2025-03-30 19:56:21 +00:00
Merge remote-tracking branch 'upstream/master' into es6
With conflicts
This commit is contained in:
commit
3713091382
165 changed files with 4194 additions and 2714 deletions
|
@ -36,6 +36,14 @@ jobs:
|
|||
targetPath: '$(Build.SourcesDirectory)/deployment/dist'
|
||||
artifactName: 'jellyfin-web-$(BuildConfiguration)'
|
||||
|
||||
- task: SSH@0
|
||||
displayName: 'Create target directory on repository server'
|
||||
condition: or(startsWith(variables['Build.SourceBranch'], 'refs/tags'), startsWith(variables['Build.SourceBranch'], 'refs/heads/master'))
|
||||
inputs:
|
||||
sshEndpoint: repository
|
||||
runOptions: 'inline'
|
||||
inline: 'mkdir -p /srv/repository/incoming/azure/$(Build.BuildNumber)/$(BuildConfiguration)'
|
||||
|
||||
- task: CopyFilesOverSSH@0
|
||||
displayName: 'Upload artifacts to repository server'
|
||||
condition: or(startsWith(variables['Build.SourceBranch'], 'refs/tags'), startsWith(variables['Build.SourceBranch'], 'refs/heads/master'))
|
||||
|
|
|
@ -2,4 +2,4 @@ version: 1
|
|||
update_configs:
|
||||
- package_manager: "javascript"
|
||||
directory: "/"
|
||||
update_schedule: "weekly"
|
||||
update_schedule: "live"
|
||||
|
|
4
.github/CODEOWNERS
vendored
4
.github/CODEOWNERS
vendored
|
@ -1,4 +1,6 @@
|
|||
.ci @dkanada @EraYaN
|
||||
.github @jellyfin/core
|
||||
build.sh @joshuaboniface
|
||||
fedora @joshuaboniface
|
||||
debian @joshuaboniface
|
||||
.copr @joshuaboniface
|
||||
deployment @joshuaboniface
|
||||
|
|
|
@ -1,23 +1,20 @@
|
|||
---
|
||||
name: Bug report
|
||||
about: Create a bug report
|
||||
title: ''
|
||||
name: Bug Report
|
||||
about: You have noticed a general issue or regression, and would like to report it
|
||||
labels: bug
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
**Describe The Bug**
|
||||
<!-- A clear and concise description of what the bug is. -->
|
||||
|
||||
**To Reproduce**
|
||||
**Steps To Reproduce**
|
||||
<!-- Steps to reproduce the behavior: -->
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
4. See error
|
||||
|
||||
**Expected behavior**
|
||||
**Expected Behavior**
|
||||
<!-- A clear and concise description of what you expected to happen. -->
|
||||
|
||||
**Logs**
|
||||
|
@ -27,9 +24,9 @@ assignees: ''
|
|||
<!-- If applicable, add screenshots to help explain your problem. -->
|
||||
|
||||
**System (please complete the following information):**
|
||||
- OS: [e.g. Docker, Debian, Windows]
|
||||
- Platform: [e.g. Linux, Windows, iPhone, Tizen]
|
||||
- Browser: [e.g. Firefox, Chrome, Safari]
|
||||
- Jellyfin Version: [e.g. 10.0.1]
|
||||
- Jellyfin Version: [e.g. 10.6.0]
|
||||
|
||||
**Additional context**
|
||||
**Additional Context**
|
||||
<!-- Add any other context about the problem here. -->
|
22
.github/ISSUE_TEMPLATE/2-playback-issue.md
vendored
Normal file
22
.github/ISSUE_TEMPLATE/2-playback-issue.md
vendored
Normal file
|
@ -0,0 +1,22 @@
|
|||
---
|
||||
name: Playback Issue
|
||||
about: You have playback issues with some files
|
||||
labels: playback
|
||||
---
|
||||
|
||||
**Describe The Bug**
|
||||
<!-- A clear and concise description of what the bug is. -->
|
||||
|
||||
**Media Information**
|
||||
<!-- Please paste any ffprobe or MediaInfo logs. -->
|
||||
|
||||
**Screenshots**
|
||||
<!-- Add screenshots from the Playback Data and Media Info. -->
|
||||
|
||||
**System (please complete the following information):**
|
||||
- Platform: [e.g. Linux, Windows, iPhone, Tizen]
|
||||
- Browser: [e.g. Firefox, Chrome, Safari]
|
||||
- Jellyfin Version: [e.g. 10.6.0]
|
||||
|
||||
**Additional Context**
|
||||
<!-- Add any other context about the problem here. -->
|
13
.github/ISSUE_TEMPLATE/3-technical-discussion.md
vendored
Normal file
13
.github/ISSUE_TEMPLATE/3-technical-discussion.md
vendored
Normal file
|
@ -0,0 +1,13 @@
|
|||
---
|
||||
name: Technical Discussion
|
||||
about: You want to discuss technical aspects of changes you intend to make
|
||||
labels: enhancement
|
||||
---
|
||||
|
||||
<!-- Explain the change and the motivations behind it.
|
||||
|
||||
For example, if you plan to rely on a new dependency, explain why and what
|
||||
it brings to the project.
|
||||
|
||||
If you plan to make significant changes, go roughly over the steps you intend
|
||||
to take and how you would divide the change in PRs of a manageable size. -->
|
9
.github/ISSUE_TEMPLATE/4-meta-issue.md
vendored
Normal file
9
.github/ISSUE_TEMPLATE/4-meta-issue.md
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
---
|
||||
name: Meta Issue
|
||||
about: You want to track a number of other issues as part of a larger project
|
||||
labels: meta
|
||||
---
|
||||
|
||||
* [ ] Issue 1 [#123]
|
||||
* [ ] Issue 2 [#456]
|
||||
* [ ] ...
|
8
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
8
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Feature Request
|
||||
url: https://features.jellyfin.org/
|
||||
about: Please head over to our feature request hub to vote on or submit a feature.
|
||||
- name: Help Or Question
|
||||
url: https://matrix.to/#/#jellyfin-troubleshooting:matrix.org
|
||||
about: Please join the troubleshooting Matrix channel to get some help.
|
24
.github/SUPPORT.md
vendored
Normal file
24
.github/SUPPORT.md
vendored
Normal file
|
@ -0,0 +1,24 @@
|
|||
# Support
|
||||
|
||||
Jellyfin contributors have limited availability to address general support
|
||||
questions. Please make sure you are using the latest version of Jellyfin.
|
||||
|
||||
When looking for support or information, please first search for your
|
||||
question in these venues:
|
||||
|
||||
* [Jellyfin Forum](https://forum.jellyfin.org)
|
||||
* [Jellyfin Documentation](https://docs.jellyfin.org)
|
||||
* [Open or **closed** issues in the organization](https://github.com/issues?q=sort%3Aupdated-desc+org%3Ajellyfin+is%3Aissue+)
|
||||
|
||||
If you didn't find an answer in the resources above, contributors and other
|
||||
users are reachable through the following channels:
|
||||
|
||||
* #jellyfin on [Matrix](https://matrix.to/#/#jellyfin:matrix.org%22) or [IRC](https://webchat.freenode.net/#jellyfin)
|
||||
* #jellyfin-troubleshooting on [Matrix](https://matrix.to/#/#jellyfin-troubleshooting:matrix.org) or [IRC](https://webchat.freenode.net/#jellyfin-troubleshooting)
|
||||
* [/r/jellyfin on Reddit](https://www.reddit.com/r/jellyfin)
|
||||
|
||||
GitHub issues are for tracking enhancements and bugs, not general support.
|
||||
|
||||
The open source license grants you the freedom to use Jellyfin.
|
||||
It does not guarantee commitments of other people's time.
|
||||
Please be respectful and manage your expectations.
|
|
@ -184,7 +184,12 @@ function copy(query) {
|
|||
function injectBundle() {
|
||||
return src(options.injectBundle.query, { base: './src/' })
|
||||
.pipe(inject(
|
||||
src(['src/scripts/apploader.js'], { read: false }, { base: './src/' }), { relative: true }
|
||||
src(['src/scripts/apploader.js'], { read: false }, { base: './src/' }), {
|
||||
relative: true,
|
||||
transform: function (filepath) {
|
||||
return `<script src="${filepath}" defer></script>`;
|
||||
}
|
||||
}
|
||||
))
|
||||
.pipe(dest('dist/'))
|
||||
.pipe(browserSync.stream());
|
||||
|
|
30
package.json
30
package.json
|
@ -5,16 +5,16 @@
|
|||
"repository": "https://github.com/jellyfin/jellyfin-web",
|
||||
"license": "GPL-2.0-or-later",
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.10.3",
|
||||
"@babel/core": "^7.10.5",
|
||||
"@babel/plugin-proposal-class-properties": "^7.10.1",
|
||||
"@babel/plugin-proposal-private-methods": "^7.10.1",
|
||||
"@babel/plugin-transform-modules-amd": "^7.9.6",
|
||||
"@babel/plugin-transform-modules-amd": "^7.10.5",
|
||||
"@babel/polyfill": "^7.8.7",
|
||||
"@babel/preset-env": "^7.10.3",
|
||||
"autoprefixer": "^9.8.2",
|
||||
"autoprefixer": "^9.8.5",
|
||||
"babel-eslint": "^11.0.0-beta.2",
|
||||
"babel-loader": "^8.0.6",
|
||||
"browser-sync": "^2.26.7",
|
||||
"browser-sync": "^2.26.10",
|
||||
"copy-webpack-plugin": "^5.1.1",
|
||||
"css-loader": "^3.6.0",
|
||||
"cssnano": "^4.1.10",
|
||||
|
@ -57,16 +57,15 @@
|
|||
"blurhash": "^1.1.3",
|
||||
"classlist.js": "https://github.com/eligrey/classList.js/archive/1.2.20180112.tar.gz",
|
||||
"core-js": "^3.6.5",
|
||||
"date-fns": "^2.14.0",
|
||||
"document-register-element": "^1.14.3",
|
||||
"date-fns": "^2.15.0",
|
||||
"epubjs": "^0.3.85",
|
||||
"fast-text-encoding": "^1.0.3",
|
||||
"flv.js": "^1.5.0",
|
||||
"headroom.js": "^0.11.0",
|
||||
"hls.js": "^0.13.1",
|
||||
"hls.js": "^0.14.3",
|
||||
"howler": "^2.2.0",
|
||||
"intersection-observer": "^0.10.0",
|
||||
"jellyfin-apiclient": "^1.2.2",
|
||||
"intersection-observer": "^0.11.0",
|
||||
"jellyfin-apiclient": "^1.4.1",
|
||||
"jellyfin-noto": "https://github.com/jellyfin/jellyfin-noto",
|
||||
"jquery": "^3.5.1",
|
||||
"jstree": "^3.3.10",
|
||||
|
@ -77,11 +76,11 @@
|
|||
"query-string": "^6.13.1",
|
||||
"resize-observer-polyfill": "^1.5.1",
|
||||
"screenfull": "^5.0.2",
|
||||
"shaka-player": "^3.0.1",
|
||||
"shaka-player": "^2.5.13",
|
||||
"sortablejs": "^1.10.2",
|
||||
"swiper": "^5.4.5",
|
||||
"webcomponents.js": "^0.7.24",
|
||||
"whatwg-fetch": "^3.0.0"
|
||||
"whatwg-fetch": "^3.2.0"
|
||||
},
|
||||
"babel": {
|
||||
"presets": [
|
||||
|
@ -174,6 +173,7 @@
|
|||
"src/controllers/dashboard/metadataImages.js",
|
||||
"src/controllers/dashboard/metadatanfo.js",
|
||||
"src/controllers/dashboard/plugins/repositories.js",
|
||||
<<<<<<< HEAD
|
||||
"src/controllers/dashboard/streaming.js",
|
||||
"src/controllers/dashboard/mediaLibrary.js",
|
||||
"src/controllers/dashboard/networking.js",
|
||||
|
@ -230,6 +230,14 @@
|
|||
"src/elements/emby-button/paper-icon-button-light.js",
|
||||
"src/elements/emby-collapse/emby-collapse.js",
|
||||
"src/elements/emby-input/emby-input.js",
|
||||
=======
|
||||
"src/controllers/playback/nowplaying.js",
|
||||
"src/controllers/playback/videoosd.js",
|
||||
"src/controllers/user/display.js",
|
||||
"src/controllers/user/home.js",
|
||||
"src/controllers/user/playback.js",
|
||||
"src/controllers/user/subtitles.js",
|
||||
>>>>>>> upstream/master
|
||||
"src/plugins/bookPlayer/plugin.js",
|
||||
"src/plugins/bookPlayer/tableOfContents.js",
|
||||
"src/plugins/photoPlayer/plugin.js",
|
||||
|
|
|
@ -235,6 +235,15 @@ div[data-role=controlgroup] a.ui-btn-active {
|
|||
width: 50%;
|
||||
}
|
||||
|
||||
.localUsers .cardText-secondary {
|
||||
white-space: pre-wrap;
|
||||
height: 3em;
|
||||
}
|
||||
|
||||
.customCssContainer textarea {
|
||||
resize: none;
|
||||
}
|
||||
|
||||
@media all and (min-width: 70em) {
|
||||
.dashboardSections {
|
||||
-webkit-flex-wrap: wrap;
|
||||
|
|
|
@ -30,6 +30,10 @@
|
|||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.align-items-flex-end {
|
||||
align-items: flex-end;
|
||||
}
|
||||
|
||||
.justify-content-center {
|
||||
justify-content: center;
|
||||
}
|
||||
|
@ -38,6 +42,10 @@
|
|||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.justify-content-space-between {
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.flex-wrap-wrap {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
|
|
@ -1,8 +1,3 @@
|
|||
html {
|
||||
font-size: 82% !important;
|
||||
}
|
||||
|
||||
.formDialogFooter {
|
||||
position: static !important;
|
||||
margin: 0 -1em !important;
|
||||
}
|
||||
|
|
|
@ -24,10 +24,6 @@
|
|||
padding-top: 7em !important;
|
||||
}
|
||||
|
||||
.layout-mobile .libraryPage {
|
||||
padding-top: 4em !important;
|
||||
}
|
||||
|
||||
.itemDetailPage {
|
||||
padding-top: 0 !important;
|
||||
}
|
||||
|
@ -164,6 +160,7 @@
|
|||
display: flex;
|
||||
flex-direction: column;
|
||||
contain: layout style paint;
|
||||
transition: background ease-in-out 0.5s;
|
||||
}
|
||||
|
||||
.hiddenViewMenuBar .skinHeader {
|
||||
|
@ -178,6 +175,10 @@
|
|||
width: 100%;
|
||||
}
|
||||
|
||||
.layout-tv .sectionTabs {
|
||||
width: 55%;
|
||||
}
|
||||
|
||||
.selectedMediaFolder {
|
||||
background-color: #f2f2f2 !important;
|
||||
}
|
||||
|
@ -272,7 +273,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
@media all and (max-width: 84em) {
|
||||
@media all and (max-width: 100em) {
|
||||
.withSectionTabs .headerTop {
|
||||
padding-bottom: 0.55em;
|
||||
}
|
||||
|
@ -280,9 +281,13 @@
|
|||
.sectionTabs {
|
||||
font-size: 83.5%;
|
||||
}
|
||||
|
||||
.layout-tv .sectionTabs {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@media all and (min-width: 84em) {
|
||||
@media all and (min-width: 100em) {
|
||||
.headerTop {
|
||||
padding: 0.8em 0.8em;
|
||||
}
|
||||
|
@ -438,12 +443,14 @@
|
|||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
background-attachment: fixed;
|
||||
height: 50vh;
|
||||
height: 40vh;
|
||||
position: relative;
|
||||
animation: backdrop-fadein 800ms ease-in normal both;
|
||||
}
|
||||
|
||||
.layout-mobile .itemBackdrop {
|
||||
background-attachment: scroll;
|
||||
height: 26.5vh;
|
||||
}
|
||||
|
||||
.layout-desktop .itemBackdrop::after,
|
||||
|
@ -463,10 +470,20 @@
|
|||
.detailPageContent {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding-left: 2%;
|
||||
padding-left: 32.45vw;
|
||||
padding-right: 2%;
|
||||
}
|
||||
|
||||
.layout-mobile .detailPageContent {
|
||||
padding-left: 5%;
|
||||
padding-right: 5%;
|
||||
}
|
||||
|
||||
.layout-desktop .detailPageContent .emby-scroller,
|
||||
.layout-tv .detailPageContent .emby-scroller {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.layout-desktop .noBackdrop .detailPageContent,
|
||||
.layout-tv .noBackdrop .detailPageContent {
|
||||
margin-top: 2.5em;
|
||||
|
@ -477,6 +494,10 @@
|
|||
margin-top: 0;
|
||||
}
|
||||
|
||||
.detailSectionContent a {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.personBackdrop {
|
||||
background-size: contain;
|
||||
}
|
||||
|
@ -495,7 +516,23 @@
|
|||
|
||||
.parentName {
|
||||
display: block;
|
||||
margin-bottom: 0.5em;
|
||||
margin: 0 0 0;
|
||||
}
|
||||
|
||||
.layout-mobile .parentName {
|
||||
margin: 0.6em 0 0;
|
||||
}
|
||||
|
||||
.musicParentName {
|
||||
margin: 0.15em 0 0.2em;
|
||||
}
|
||||
|
||||
.layout-mobile .musicParentName {
|
||||
margin: -0.25em 0 0.25em;
|
||||
}
|
||||
|
||||
.layout-mobile .itemExternalLinks {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.mainDetailButtons {
|
||||
|
@ -503,8 +540,6 @@
|
|||
-webkit-box-align: center;
|
||||
-webkit-align-items: center;
|
||||
align-items: center;
|
||||
-webkit-flex-wrap: wrap;
|
||||
flex-wrap: wrap;
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
|
@ -520,6 +555,35 @@
|
|||
font-weight: 600;
|
||||
}
|
||||
|
||||
.itemName.originalTitle {
|
||||
margin: 0.2em 0 0.2em;
|
||||
}
|
||||
|
||||
.itemName.parentNameLast {
|
||||
margin: 0 0 0;
|
||||
}
|
||||
|
||||
.layout-mobile .itemName.parentNameLast {
|
||||
margin: 0.4em 0 0.4em;
|
||||
}
|
||||
|
||||
.layout-mobile h1.itemName,
|
||||
.layout-mobile h1.parentName {
|
||||
font-size: 1.6em;
|
||||
}
|
||||
|
||||
.itemName.parentNameLast.withOriginalTitle {
|
||||
margin: 0 0 0;
|
||||
}
|
||||
|
||||
.layout-mobile .itemName.parentNameLast.withOriginalTitle {
|
||||
margin: 0.6em 0 0;
|
||||
}
|
||||
|
||||
.layout-mobile .itemName.originalTitle {
|
||||
margin: 0.5em 0 0.5em;
|
||||
}
|
||||
|
||||
.nameContainer {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
@ -546,6 +610,19 @@
|
|||
text-align: center;
|
||||
}
|
||||
|
||||
.layout-mobile .mainDetailButtons {
|
||||
margin-top: 1em;
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
margin: 0.15em 0 0.2em;
|
||||
}
|
||||
|
||||
.layout-mobile .subtitle {
|
||||
margin: 0.2em 0 0.2em;
|
||||
}
|
||||
|
||||
.detailPagePrimaryContainer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
@ -556,7 +633,7 @@
|
|||
.layout-mobile .detailPagePrimaryContainer {
|
||||
display: block;
|
||||
position: relative;
|
||||
top: 0;
|
||||
padding: 0.5em 3.3% 0.5em;
|
||||
}
|
||||
|
||||
.layout-tv #itemDetailPage:not(.noBackdrop) .detailPagePrimaryContainer,
|
||||
|
@ -566,13 +643,14 @@
|
|||
padding-left: 32.45vw;
|
||||
}
|
||||
|
||||
.layout-desktop .detailSticky,
|
||||
.layout-tv .detailSticky {
|
||||
.layout-desktop .detailRibbon,
|
||||
.layout-tv .detailRibbon {
|
||||
margin-top: -7.2em;
|
||||
height: 7.18em;
|
||||
}
|
||||
|
||||
.layout-desktop .noBackdrop .detailSticky,
|
||||
.layout-tv .noBackdrop .detailSticky {
|
||||
.layout-desktop .noBackdrop .detailRibbon,
|
||||
.layout-tv .noBackdrop .detailRibbon {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
|
@ -584,6 +662,9 @@
|
|||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
text-align: left;
|
||||
min-width: 0;
|
||||
max-width: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.layout-mobile .infoText {
|
||||
|
@ -594,13 +675,29 @@
|
|||
margin: 1.25em 0;
|
||||
}
|
||||
|
||||
.detailImageContainer {
|
||||
position: relative;
|
||||
margin-top: -25vh;
|
||||
margin-bottom: 10vh;
|
||||
.layout-mobile .detailPageSecondaryContainer {
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
.layout-mobile .detailImageContainer {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.detailImageContainer .card {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
float: left;
|
||||
width: 25vw;
|
||||
z-index: 3;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
|
||||
.detailImageContainer .card.backdropCard {
|
||||
top: 35%;
|
||||
}
|
||||
|
||||
.detailImageContainer .card.squareCard {
|
||||
top: 40%;
|
||||
}
|
||||
|
||||
.layout-desktop .noBackdrop .detailImageContainer,
|
||||
|
@ -613,11 +710,11 @@
|
|||
}
|
||||
|
||||
.detailLogo {
|
||||
width: 30vw;
|
||||
height: 25vh;
|
||||
width: 25vw;
|
||||
height: 16vh;
|
||||
position: absolute;
|
||||
top: 10vh;
|
||||
right: 20vw;
|
||||
right: 25vw;
|
||||
background-size: contain;
|
||||
}
|
||||
|
||||
|
@ -657,14 +754,19 @@ div.itemDetailGalleryLink.defaultCardBackground {
|
|||
position: relative;
|
||||
}
|
||||
|
||||
.layout-desktop .detailPageWrapperContainer,
|
||||
.layout-tv .detailPageWrapperContainer {
|
||||
margin-top: 7.2em;
|
||||
.layout-desktop .itemBackdrop,
|
||||
.layout-tv .itemBackdrop {
|
||||
height: 40vh;
|
||||
}
|
||||
|
||||
.layout-tv #itemDetailPage:not(.noBackdrop) .detailPagePrimaryContainer,
|
||||
.layout-desktop #itemDetailPage:not(.noBackdrop) .detailPagePrimaryContainer {
|
||||
padding-left: 3.3%;
|
||||
.layout-desktop .detailPageWrapperContainer,
|
||||
.layout-tv .detailPageWrapperContainer {
|
||||
margin-top: 0.1em;
|
||||
}
|
||||
|
||||
.layout-desktop .detailImageContainer .card,
|
||||
.layout-tv .detailImageContainer .card {
|
||||
top: 10%;
|
||||
}
|
||||
|
||||
.btnPlaySimple {
|
||||
|
@ -680,12 +782,12 @@ div.itemDetailGalleryLink.defaultCardBackground {
|
|||
|
||||
.emby-button.detailFloatingButton {
|
||||
position: absolute;
|
||||
background-color: rgba(0, 0, 0, 0.5) !important;
|
||||
z-index: 1;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
z-index: 3;
|
||||
top: 100%;
|
||||
left: 90%;
|
||||
margin: -2.2em 0 0 -2.2em;
|
||||
padding: 0.4em !important;
|
||||
padding: 0.4em;
|
||||
color: rgba(255, 255, 255, 0.76);
|
||||
}
|
||||
|
||||
|
@ -695,16 +797,12 @@ div.itemDetailGalleryLink.defaultCardBackground {
|
|||
|
||||
@media all and (max-width: 62.5em) {
|
||||
.parentName {
|
||||
margin-bottom: 1em;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.itemDetailPage {
|
||||
padding-top: 0 !important;
|
||||
}
|
||||
|
||||
.detailimg-hidemobile {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media all and (min-width: 31.25em) {
|
||||
|
@ -820,21 +918,7 @@ div.itemDetailGalleryLink.defaultCardBackground {
|
|||
}
|
||||
}
|
||||
|
||||
@media all and (min-width: 62.5em) {
|
||||
.headerTop {
|
||||
padding-left: 0.8em;
|
||||
padding-right: 0.8em;
|
||||
}
|
||||
|
||||
.headerTabs {
|
||||
align-self: center;
|
||||
width: auto;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-top: -4.2em;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
@media all and (min-width: 100em) {
|
||||
.detailFloatingButton {
|
||||
display: none !important;
|
||||
}
|
||||
|
@ -868,6 +952,10 @@ div.itemDetailGalleryLink.defaultCardBackground {
|
|||
}
|
||||
}
|
||||
|
||||
.detailVerticalSection .emby-scrollbuttons {
|
||||
padding-top: 0.4em;
|
||||
}
|
||||
|
||||
.layout-tv .detailVerticalSection {
|
||||
margin-bottom: 3.4em !important;
|
||||
}
|
||||
|
@ -956,6 +1044,10 @@ div.itemDetailGalleryLink.defaultCardBackground {
|
|||
margin-bottom: 2.7em;
|
||||
}
|
||||
|
||||
.layout-mobile .verticalSection-extrabottompadding {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.sectionTitleButton,
|
||||
.sectionTitleIconButton {
|
||||
margin-right: 0 !important;
|
||||
|
@ -981,7 +1073,13 @@ div.itemDetailGalleryLink.defaultCardBackground {
|
|||
|
||||
div:not(.sectionTitleContainer-cards) > .sectionTitle-cards {
|
||||
margin: 0;
|
||||
padding-top: 1.25em;
|
||||
padding-top: 0.5em;
|
||||
padding-bottom: 0.2em;
|
||||
}
|
||||
|
||||
.layout-mobile :not(.sectionTitleContainer-cards) > .sectionTitle-cards {
|
||||
margin: 0;
|
||||
padding-top: 0.5em;
|
||||
}
|
||||
|
||||
.sectionTitleButton {
|
||||
|
@ -1134,6 +1232,12 @@ div:not(.sectionTitleContainer-cards) > .sectionTitle-cards {
|
|||
|
||||
.trackSelections .selectContainer .selectLabel {
|
||||
margin: 0 0.2em 0 0;
|
||||
line-height: 1.75;
|
||||
}
|
||||
|
||||
.layout-mobile .detailsGroupItem .label,
|
||||
.layout-mobile .trackSelections .selectContainer .selectLabel {
|
||||
flex-basis: 4.5em;
|
||||
}
|
||||
|
||||
.trackSelections .selectContainer .detailTrackSelect {
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
.hiddenScrollX,
|
||||
.layout-tv .scrollX {
|
||||
-ms-overflow-style: none;
|
||||
scrollbar-width: none;
|
||||
}
|
||||
|
||||
.hiddenScrollX-forced {
|
||||
|
@ -40,6 +41,7 @@
|
|||
.hiddenScrollY,
|
||||
.layout-tv .smoothScrollY {
|
||||
-ms-overflow-style: none;
|
||||
scrollbar-width: none;
|
||||
|
||||
/* Can't do this because it not only hides the scrollbar, but also prevents scrolling */
|
||||
|
||||
|
|
|
@ -5,6 +5,12 @@ html {
|
|||
height: 100%;
|
||||
}
|
||||
|
||||
.layout-mobile,
|
||||
.layout-tv {
|
||||
-webkit-touch-callout: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.clipForScreenReader {
|
||||
clip: rect(1px, 1px, 1px, 1px);
|
||||
clip-path: inset(50%);
|
||||
|
@ -18,7 +24,7 @@ html {
|
|||
|
||||
.material-icons {
|
||||
/* Fix font ligatures on older WebOS versions */
|
||||
-webkit-font-feature-settings: "liga";
|
||||
font-feature-settings: "liga";
|
||||
}
|
||||
|
||||
.backgroundContainer {
|
||||
|
@ -34,16 +40,6 @@ html {
|
|||
line-height: 1.35;
|
||||
}
|
||||
|
||||
.layout-mobile,
|
||||
.layout-tv {
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-user-select: none;
|
||||
-khtml-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
body {
|
||||
overflow-x: hidden;
|
||||
background-color: transparent !important;
|
||||
|
@ -133,3 +129,7 @@ div[data-role=page] {
|
|||
.hide-scroll {
|
||||
overflow-y: hidden;
|
||||
}
|
||||
|
||||
.w-100 {
|
||||
width: 100%;
|
||||
}
|
||||
|
|
|
@ -4,12 +4,6 @@
|
|||
// Use define from require.js not webpack's define
|
||||
var _define = window.define;
|
||||
|
||||
// document-register-element
|
||||
var docRegister = require('document-register-element');
|
||||
_define('document-register-element', function() {
|
||||
return docRegister;
|
||||
});
|
||||
|
||||
// fetch
|
||||
var fetch = require('whatwg-fetch');
|
||||
_define('fetch', function() {
|
||||
|
@ -65,12 +59,6 @@ _define('resize-observer-polyfill', function() {
|
|||
return resize;
|
||||
});
|
||||
|
||||
// shaka
|
||||
var shaka = require('shaka-player');
|
||||
_define('shaka', function() {
|
||||
return shaka;
|
||||
});
|
||||
|
||||
// swiper
|
||||
var swiper = require('swiper/js/swiper');
|
||||
require('swiper/css/swiper.min.css');
|
||||
|
@ -90,6 +78,12 @@ _define('webcomponents', function() {
|
|||
return webcomponents;
|
||||
});
|
||||
|
||||
// shaka
|
||||
var shaka = require('shaka-player');
|
||||
_define('shaka', function() {
|
||||
return shaka;
|
||||
});
|
||||
|
||||
// libass-wasm
|
||||
var libassWasm = require('libass-wasm');
|
||||
_define('JavascriptSubtitlesOctopus', function() {
|
||||
|
|
|
@ -16,7 +16,7 @@ function getOffsets(elems) {
|
|||
return results;
|
||||
}
|
||||
|
||||
for (let elem of elems) {
|
||||
for (const elem of elems) {
|
||||
let box = elem.getBoundingClientRect();
|
||||
|
||||
results.push({
|
||||
|
@ -135,7 +135,7 @@ export function show(options) {
|
|||
let renderIcon = false;
|
||||
let icons = [];
|
||||
let itemIcon;
|
||||
for (let item of options.items) {
|
||||
for (const item of options.items) {
|
||||
|
||||
itemIcon = item.icon || (item.selected ? 'check' : null);
|
||||
|
||||
|
|
|
@ -222,46 +222,13 @@ define(['loading', 'globalize', 'events', 'viewManager', 'skinManager', 'backdro
|
|||
}
|
||||
|
||||
function normalizeImageOptions(options) {
|
||||
var scaleFactor = browser.tv ? 0.8 : 1;
|
||||
|
||||
var setQuality;
|
||||
if (options.maxWidth) {
|
||||
options.maxWidth = Math.round(options.maxWidth * scaleFactor);
|
||||
if (options.maxWidth || options.width || options.maxHeight || options.height) {
|
||||
setQuality = true;
|
||||
}
|
||||
|
||||
if (options.width) {
|
||||
options.width = Math.round(options.width * scaleFactor);
|
||||
setQuality = true;
|
||||
}
|
||||
|
||||
if (options.maxHeight) {
|
||||
options.maxHeight = Math.round(options.maxHeight * scaleFactor);
|
||||
setQuality = true;
|
||||
}
|
||||
|
||||
if (options.height) {
|
||||
options.height = Math.round(options.height * scaleFactor);
|
||||
setQuality = true;
|
||||
}
|
||||
|
||||
if (setQuality) {
|
||||
var quality;
|
||||
var type = options.type || 'Primary';
|
||||
|
||||
if (browser.tv || browser.slow) {
|
||||
// TODO: wtf
|
||||
if (browser.chrome) {
|
||||
// webp support
|
||||
quality = type === 'Primary' ? 40 : 50;
|
||||
} else {
|
||||
quality = type === 'Backdrop' ? 60 : 50;
|
||||
}
|
||||
} else {
|
||||
quality = type === 'Backdrop' ? 70 : 90;
|
||||
}
|
||||
|
||||
options.quality = quality;
|
||||
if (setQuality && !options.quality) {
|
||||
options.quality = 90;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -167,8 +167,9 @@ button::-moz-focus-inner {
|
|||
position: relative;
|
||||
background-clip: content-box !important;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
/* This is only needed for scalable cards */
|
||||
.cardScalable .cardImageContainer {
|
||||
height: 100%;
|
||||
contain: strict;
|
||||
}
|
||||
|
|
|
@ -1310,7 +1310,7 @@ import 'programStyles';
|
|||
}
|
||||
|
||||
const mediaSourceCount = item.MediaSourceCount || 1;
|
||||
if (mediaSourceCount > 1) {
|
||||
if (mediaSourceCount > 1 && options.disableIndicators !== true) {
|
||||
innerCardFooter += '<div class="mediaSourceIndicator">' + mediaSourceCount + '</div>';
|
||||
}
|
||||
|
||||
|
@ -1391,34 +1391,44 @@ import 'programStyles';
|
|||
cardBoxClose = '</div>';
|
||||
cardScalableClose = '</div>';
|
||||
|
||||
let indicatorsHtml = '';
|
||||
if (options.disableIndicators !== true) {
|
||||
let indicatorsHtml = '';
|
||||
|
||||
if (options.missingIndicator !== false) {
|
||||
indicatorsHtml += indicators.getMissingIndicator(item);
|
||||
}
|
||||
if (options.missingIndicator !== false) {
|
||||
indicatorsHtml += indicators.getMissingIndicator(item);
|
||||
}
|
||||
|
||||
indicatorsHtml += indicators.getSyncIndicator(item);
|
||||
indicatorsHtml += indicators.getTimerIndicator(item);
|
||||
indicatorsHtml += indicators.getSyncIndicator(item);
|
||||
indicatorsHtml += indicators.getTimerIndicator(item);
|
||||
|
||||
indicatorsHtml += indicators.getTypeIndicator(item);
|
||||
indicatorsHtml += indicators.getTypeIndicator(item);
|
||||
|
||||
if (options.showGroupCount) {
|
||||
if (options.showGroupCount) {
|
||||
|
||||
indicatorsHtml += indicators.getChildCountIndicatorHtml(item, {
|
||||
minCount: 1
|
||||
});
|
||||
} else {
|
||||
indicatorsHtml += indicators.getPlayedIndicatorHtml(item);
|
||||
}
|
||||
indicatorsHtml += indicators.getChildCountIndicatorHtml(item, {
|
||||
minCount: 1
|
||||
});
|
||||
} else {
|
||||
indicatorsHtml += indicators.getPlayedIndicatorHtml(item);
|
||||
}
|
||||
|
||||
<<<<<<< HEAD
|
||||
if (item.Type === 'CollectionFolder' || item.CollectionType) {
|
||||
const refreshClass = item.RefreshProgress ? '' : ' class="hide"';
|
||||
indicatorsHtml += '<div is="emby-itemrefreshindicator"' + refreshClass + ' data-progress="' + (item.RefreshProgress || 0) + '" data-status="' + item.RefreshStatus + '"></div>';
|
||||
importRefreshIndicator();
|
||||
}
|
||||
=======
|
||||
if (item.Type === 'CollectionFolder' || item.CollectionType) {
|
||||
const refreshClass = item.RefreshProgress ? '' : ' class="hide"';
|
||||
indicatorsHtml += '<div is="emby-itemrefreshindicator"' + refreshClass + ' data-progress="' + (item.RefreshProgress || 0) + '" data-status="' + item.RefreshStatus + '"></div>';
|
||||
requireRefreshIndicator();
|
||||
}
|
||||
>>>>>>> upstream/master
|
||||
|
||||
if (indicatorsHtml) {
|
||||
cardImageContainerOpen += '<div class="cardIndicators">' + indicatorsHtml + '</div>';
|
||||
if (indicatorsHtml) {
|
||||
cardImageContainerOpen += '<div class="cardIndicators">' + indicatorsHtml + '</div>';
|
||||
}
|
||||
}
|
||||
|
||||
if (!imgUrl) {
|
||||
|
@ -1466,8 +1476,8 @@ import 'programStyles';
|
|||
|
||||
let additionalCardContent = '';
|
||||
|
||||
if (layoutManager.desktop) {
|
||||
additionalCardContent += getHoverMenuHtml(item, action);
|
||||
if (layoutManager.desktop && !options.disableHoverMenu) {
|
||||
additionalCardContent += getHoverMenuHtml(item, action, options);
|
||||
}
|
||||
|
||||
return '<' + tagName + ' data-index="' + index + '"' + timerAttributes + actionAttribute + ' data-isfolder="' + (item.IsFolder || false) + '" data-serverid="' + (item.ServerId || options.serverId) + '" data-id="' + (item.Id || item.ItemId) + '" data-type="' + item.Type + '"' + mediaTypeData + collectionTypeData + channelIdData + positionTicksData + collectionIdData + playlistIdData + contextData + parentIdData + ' data-prefix="' + prefix + '" class="' + className + '">' + cardImageContainerOpen + innerCardFooter + cardImageContainerClose + overlayButtons + additionalCardContent + cardScalableClose + outerCardFooter + cardBoxClose + '</' + tagName + '>';
|
||||
|
@ -1477,9 +1487,10 @@ import 'programStyles';
|
|||
* Generates HTML markup for the card overlay.
|
||||
* @param {object} item - Item used to generate the card overlay.
|
||||
* @param {string} action - Action assigned to the overlay.
|
||||
* @param {Array} options - Card builder options.
|
||||
* @returns {string} HTML markup of the card overlay.
|
||||
*/
|
||||
function getHoverMenuHtml(item, action) {
|
||||
function getHoverMenuHtml(item, action, options) {
|
||||
let html = '';
|
||||
|
||||
html += '<div class="cardOverlayContainer itemAction" data-action="' + action + '">';
|
||||
|
@ -1508,7 +1519,6 @@ import 'programStyles';
|
|||
}
|
||||
|
||||
html += '<button is="paper-icon-button-light" class="' + btnCssClass + '" data-action="menu"><span class="material-icons cardOverlayButtonIcon cardOverlayButtonIcon-hover more_vert"></span></button>';
|
||||
|
||||
html += '</div>';
|
||||
html += '</div>';
|
||||
|
||||
|
@ -1532,6 +1542,8 @@ import 'programStyles';
|
|||
case 'MusicArtist':
|
||||
case 'Person':
|
||||
return '<span class="cardImageIcon material-icons person"></span>';
|
||||
case 'Audio':
|
||||
return '<span class="cardImageIcon material-icons audiotrack"></span>';
|
||||
case 'Movie':
|
||||
return '<span class="cardImageIcon material-icons movie"></span>';
|
||||
case 'Series':
|
||||
|
@ -1540,6 +1552,12 @@ import 'programStyles';
|
|||
return '<span class="cardImageIcon material-icons book"></span>';
|
||||
case 'Folder':
|
||||
return '<span class="cardImageIcon material-icons folder"></span>';
|
||||
case 'BoxSet':
|
||||
return '<span class="cardImageIcon material-icons collections"></span>';
|
||||
case 'Playlist':
|
||||
return '<span class="cardImageIcon material-icons view_list"></span>';
|
||||
case 'PhotoAlbum':
|
||||
return '<span class="cardImageIcon material-icons photo_album"></span>';
|
||||
}
|
||||
|
||||
if (options && options.defaultCardImageIcon) {
|
||||
|
|
|
@ -25,7 +25,7 @@ import connectionManager from 'connectionManager';
|
|||
return void appRouter.showItem(items[0]);
|
||||
}
|
||||
|
||||
var url = 'itemdetails.html?id=' + itemId + '&serverId=' + serverId;
|
||||
var url = 'details?id=' + itemId + '&serverId=' + serverId;
|
||||
Dashboard.navigate(url);
|
||||
});
|
||||
e.stopPropagation();
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
define(['require', 'inputManager', 'browser', 'globalize', 'connectionManager', 'scrollHelper', 'serverNotifications', 'loading', 'datetime', 'focusManager', 'playbackManager', 'userSettings', 'imageLoader', 'events', 'layoutManager', 'itemShortcuts', 'dom', 'css!./guide.css', 'programStyles', 'material-icons', 'scrollStyles', 'emby-programcell', 'emby-button', 'paper-icon-button-light', 'emby-tabs', 'emby-scroller', 'flexStyles', 'registerElement'], function (require, inputManager, browser, globalize, connectionManager, scrollHelper, serverNotifications, loading, datetime, focusManager, playbackManager, userSettings, imageLoader, events, layoutManager, itemShortcuts, dom) {
|
||||
define(['require', 'inputManager', 'browser', 'globalize', 'connectionManager', 'scrollHelper', 'serverNotifications', 'loading', 'datetime', 'focusManager', 'playbackManager', 'userSettings', 'imageLoader', 'events', 'layoutManager', 'itemShortcuts', 'dom', 'css!./guide.css', 'programStyles', 'material-icons', 'scrollStyles', 'emby-programcell', 'emby-button', 'paper-icon-button-light', 'emby-tabs', 'emby-scroller', 'flexStyles', 'webcomponents'], function (require, inputManager, browser, globalize, connectionManager, scrollHelper, serverNotifications, loading, datetime, focusManager, playbackManager, userSettings, imageLoader, events, layoutManager, itemShortcuts, dom) {
|
||||
'use strict';
|
||||
|
||||
function showViewSettings(instance) {
|
||||
|
|
|
@ -12,7 +12,7 @@ import 'css!./style';
|
|||
fillImageElement(elem, source);
|
||||
}
|
||||
|
||||
async function itemBlurhashing(target, blurhashstr) {
|
||||
function itemBlurhashing(target, blurhashstr) {
|
||||
if (blurhash.isBlurhashValid(blurhashstr)) {
|
||||
// Although the default values recommended by Blurhash developers is 32x32, a size of 18x18 seems to be the sweet spot for us,
|
||||
// improving the performance and reducing the memory usage, while retaining almost full blur quality.
|
||||
|
@ -36,24 +36,18 @@ import 'css!./style';
|
|||
imgData.data.set(pixels);
|
||||
ctx.putImageData(imgData, 0, 0);
|
||||
|
||||
let child = target.appendChild(canvas);
|
||||
child.classList.add('blurhash-canvas');
|
||||
child.style.opacity = 1;
|
||||
if (userSettings.enableFastFadein()) {
|
||||
child.classList.add('lazy-blurhash-fadein-fast');
|
||||
} else {
|
||||
child.classList.add('lazy-blurhash-fadein');
|
||||
}
|
||||
requestAnimationFrame(() => {
|
||||
canvas.classList.add('blurhash-canvas');
|
||||
if (userSettings.enableFastFadein()) {
|
||||
canvas.classList.add('lazy-blurhash-fadein-fast');
|
||||
} else {
|
||||
canvas.classList.add('lazy-blurhash-fadein');
|
||||
}
|
||||
|
||||
target.classList.add('blurhashed');
|
||||
target.removeAttribute('data-blurhash');
|
||||
}
|
||||
}
|
||||
|
||||
function switchCanvas(elem) {
|
||||
let child = elem.getElementsByClassName('blurhash-canvas')[0];
|
||||
if (child) {
|
||||
child.style.opacity = elem.getAttribute('data-src') ? 1 : 0;
|
||||
target.parentNode.insertBefore(canvas, target);
|
||||
target.classList.add('blurhashed');
|
||||
target.removeAttribute('data-blurhash');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -66,23 +60,16 @@ import 'css!./style';
|
|||
|
||||
if (target) {
|
||||
source = target.getAttribute('data-src');
|
||||
var blurhashstr = target.getAttribute('data-blurhash');
|
||||
} else {
|
||||
source = entry;
|
||||
}
|
||||
|
||||
if (userSettings.enableBlurhash()) {
|
||||
if (!target.classList.contains('blurhashed', 'non-blurhashable') && blurhashstr) {
|
||||
itemBlurhashing(target, blurhashstr);
|
||||
} else if (!blurhashstr && !target.classList.contains('blurhashed')) {
|
||||
target.classList.add('non-blurhashable');
|
||||
}
|
||||
}
|
||||
|
||||
if (entry.intersectionRatio > 0) {
|
||||
if (source) fillImageElement(target, source);
|
||||
} else if (!source) {
|
||||
emptyImageElement(target);
|
||||
requestAnimationFrame(() => {
|
||||
emptyImageElement(target);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -94,29 +81,24 @@ import 'css!./style';
|
|||
let preloaderImg = new Image();
|
||||
preloaderImg.src = url;
|
||||
|
||||
// This is necessary here, so changing blurhash settings without reloading the page works
|
||||
if (!userSettings.enableBlurhash() || elem.classList.contains('non-blurhashable')) {
|
||||
elem.classList.add('lazy-hidden');
|
||||
}
|
||||
elem.classList.add('lazy-hidden');
|
||||
|
||||
preloaderImg.addEventListener('load', () => {
|
||||
if (elem.tagName !== 'IMG') {
|
||||
elem.style.backgroundImage = "url('" + url + "')";
|
||||
} else {
|
||||
elem.setAttribute('src', url);
|
||||
}
|
||||
elem.removeAttribute('data-src');
|
||||
requestAnimationFrame(() => {
|
||||
if (elem.tagName !== 'IMG') {
|
||||
elem.style.backgroundImage = "url('" + url + "')";
|
||||
} else {
|
||||
elem.setAttribute('src', url);
|
||||
}
|
||||
elem.removeAttribute('data-src');
|
||||
|
||||
if (elem.classList.contains('non-blurhashable') || !userSettings.enableBlurhash()) {
|
||||
elem.classList.remove('lazy-hidden');
|
||||
if (userSettings.enableFastFadein()) {
|
||||
elem.classList.add('lazy-image-fadein-fast');
|
||||
} else {
|
||||
elem.classList.add('lazy-image-fadein');
|
||||
}
|
||||
} else {
|
||||
switchCanvas(elem);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -132,15 +114,21 @@ import 'css!./style';
|
|||
}
|
||||
elem.setAttribute('data-src', url);
|
||||
|
||||
if (elem.classList.contains('non-blurhashable') || !userSettings.enableBlurhash()) {
|
||||
elem.classList.remove('lazy-image-fadein-fast', 'lazy-image-fadein');
|
||||
elem.classList.add('lazy-hidden');
|
||||
} else {
|
||||
switchCanvas(elem);
|
||||
}
|
||||
elem.classList.remove('lazy-image-fadein-fast', 'lazy-image-fadein');
|
||||
elem.classList.add('lazy-hidden');
|
||||
}
|
||||
|
||||
export function lazyChildren(elem) {
|
||||
if (userSettings.enableBlurhash()) {
|
||||
for (const lazyElem of elem.querySelectorAll('.lazy')) {
|
||||
const blurhashstr = lazyElem.getAttribute('data-blurhash');
|
||||
if (!lazyElem.classList.contains('blurhashed', 'non-blurhashable') && blurhashstr) {
|
||||
itemBlurhashing(lazyElem, blurhashstr);
|
||||
} else if (!blurhashstr && !lazyElem.classList.contains('blurhashed')) {
|
||||
lazyElem.classList.add('non-blurhashable');
|
||||
}
|
||||
}
|
||||
}
|
||||
lazyLoader.lazyChildren(elem, fillImage);
|
||||
}
|
||||
|
||||
|
@ -212,8 +200,15 @@ import 'css!./style';
|
|||
}
|
||||
}
|
||||
|
||||
export function setLazyImage(element, url) {
|
||||
element.classList.add('lazy');
|
||||
element.setAttribute('data-src', url);
|
||||
lazyImage(element);
|
||||
}
|
||||
|
||||
/* eslint-enable indent */
|
||||
export default {
|
||||
serLazyImage: setLazyImage,
|
||||
fillImages: fillImages,
|
||||
fillImage: fillImage,
|
||||
lazyImage: lazyImage,
|
||||
|
|
|
@ -12,12 +12,22 @@
|
|||
opacity: 0;
|
||||
}
|
||||
|
||||
@keyframes fadein {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.lazy-blurhash-fadein-fast {
|
||||
transition: opacity 0.2s;
|
||||
animation: fadein 0.1s;
|
||||
}
|
||||
|
||||
.lazy-blurhash-fadein {
|
||||
transition: opacity 0.7s;
|
||||
animation: fadein 0.4s;
|
||||
}
|
||||
|
||||
.blurhash-canvas {
|
||||
|
@ -28,6 +38,5 @@
|
|||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 100;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
|
|
@ -38,6 +38,23 @@ import actionsheet from 'actionsheet';
|
|||
}
|
||||
}
|
||||
|
||||
if (playbackManager.getCurrentPlayer() !== null) {
|
||||
if (options.stopPlayback) {
|
||||
commands.push({
|
||||
name: globalize.translate('StopPlayback'),
|
||||
id: 'stopPlayback',
|
||||
icon: 'stop'
|
||||
});
|
||||
}
|
||||
if (options.clearQueue) {
|
||||
commands.push({
|
||||
name: globalize.translate('ClearQueue'),
|
||||
id: 'clearQueue',
|
||||
icon: 'clear_all'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (playbackManager.canQueue(item)) {
|
||||
if (options.queue !== false) {
|
||||
commands.push({
|
||||
|
@ -54,13 +71,6 @@ import actionsheet from 'actionsheet';
|
|||
icon: 'playlist_add'
|
||||
});
|
||||
}
|
||||
|
||||
//if (options.queueAllFromHere) {
|
||||
// commands.push({
|
||||
// name: globalize.translate("QueueAllFromHere"),
|
||||
// id: "queueallfromhere"
|
||||
// });
|
||||
//}
|
||||
}
|
||||
|
||||
if (item.IsFolder || item.Type === 'MusicArtist' || item.Type === 'MusicGenre') {
|
||||
|
@ -298,10 +308,11 @@ import actionsheet from 'actionsheet';
|
|||
icon: 'album'
|
||||
});
|
||||
}
|
||||
|
||||
if (options.openArtist !== false && item.ArtistItems && item.ArtistItems.length) {
|
||||
// Show Album Artist by default, as a song can have multiple artists, which specific one would this option refer to?
|
||||
// Although some albums can have multiple artists, it's not as common as songs.
|
||||
if (options.openArtist !== false && item.AlbumArtists && item.AlbumArtists.length) {
|
||||
commands.push({
|
||||
name: globalize.translate('ViewArtist'),
|
||||
name: globalize.translate('ViewAlbumArtist'),
|
||||
id: 'artist',
|
||||
icon: 'person'
|
||||
});
|
||||
|
@ -441,6 +452,12 @@ import actionsheet from 'actionsheet';
|
|||
play(item, false, true, true);
|
||||
getResolveFunction(resolve, id)();
|
||||
break;
|
||||
case 'stopPlayback':
|
||||
playbackManager.stop();
|
||||
break;
|
||||
case 'clearQueue':
|
||||
playbackManager.clearQueue();
|
||||
break;
|
||||
case 'record':
|
||||
import('recordingCreator').then(({default: recordingCreator}) => {
|
||||
recordingCreator.show(itemId, serverId).then(getResolveFunction(resolve, id, true), getResolveFunction(resolve, id));
|
||||
|
@ -469,7 +486,7 @@ import actionsheet from 'actionsheet';
|
|||
getResolveFunction(resolve, id)();
|
||||
break;
|
||||
case 'artist':
|
||||
appRouter.showItem(item.ArtistItems[0].Id, item.ServerId);
|
||||
appRouter.showItem(item.AlbumArtists[0].Id, item.ServerId);
|
||||
getResolveFunction(resolve, id)();
|
||||
break;
|
||||
case 'playallfromhere':
|
||||
|
|
|
@ -1,14 +1,12 @@
|
|||
define(['apphost', 'globalize'], function (appHost, globalize) {
|
||||
'use strict';
|
||||
|
||||
function getDisplayName(item, options) {
|
||||
function getDisplayName(item, options = {}) {
|
||||
|
||||
if (!item) {
|
||||
throw new Error('null item passed into getDisplayName');
|
||||
}
|
||||
|
||||
options = options || {};
|
||||
|
||||
if (item.Type === 'Timer') {
|
||||
item = item.ProgramInfo || item;
|
||||
}
|
||||
|
|
|
@ -240,13 +240,19 @@ import 'cardStyle';
|
|||
html += '</div>';
|
||||
html += '</div>';
|
||||
|
||||
<<<<<<< HEAD
|
||||
let numLines = 2;
|
||||
=======
|
||||
var numLines = 3;
|
||||
>>>>>>> upstream/master
|
||||
if (currentItemType === 'MusicAlbum') {
|
||||
numLines++;
|
||||
}
|
||||
|
||||
const lines = [result.Name];
|
||||
|
||||
lines.push(result.SearchProviderName);
|
||||
|
||||
if (result.AlbumArtist) {
|
||||
lines.push(result.AlbumArtist.Name);
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
<<<<<<< HEAD
|
||||
/* eslint-disable indent */
|
||||
|
||||
/**
|
||||
|
@ -15,6 +16,10 @@ import datetime from 'datetime';
|
|||
import 'css!./listview';
|
||||
import 'emby-ratingbutton';
|
||||
import 'emby-playstatebutton';
|
||||
=======
|
||||
define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutManager', 'globalize', 'datetime', 'cardBuilder', 'css!./listview', 'emby-ratingbutton', 'emby-playstatebutton'], function (itemHelper, mediaInfo, indicators, connectionManager, layoutManager, globalize, datetime, cardBuilder) {
|
||||
'use strict';
|
||||
>>>>>>> upstream/master
|
||||
|
||||
function getIndex(item, options) {
|
||||
|
||||
|
@ -106,11 +111,8 @@ import 'emby-playstatebutton';
|
|||
itemId = item.ParentPrimaryImageItemId;
|
||||
}
|
||||
|
||||
let blurHashes = item.ImageBlurHashes || {};
|
||||
let blurhashstr = (blurHashes[options.type] || {})[options.tag];
|
||||
|
||||
if (itemId) {
|
||||
return { url: apiClient.getScaledImageUrl(itemId, options), blurhash: blurhashstr };
|
||||
return apiClient.getScaledImageUrl(itemId, options);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -126,24 +128,30 @@ import 'emby-playstatebutton';
|
|||
if (item.ChannelId && item.ChannelPrimaryImageTag) {
|
||||
options.tag = item.ChannelPrimaryImageTag;
|
||||
}
|
||||
let blurHashes = item.ImageBlurHashes || {};
|
||||
let blurhashstr = (blurHashes[options.type])[options.tag];
|
||||
|
||||
if (item.ChannelId) {
|
||||
return { url: apiClient.getScaledImageUrl(item.ChannelId, options), blurhash: blurhashstr };
|
||||
return apiClient.getScaledImageUrl(item.ChannelId, options);
|
||||
}
|
||||
}
|
||||
|
||||
function getTextLinesHtml(textlines, isLargeStyle) {
|
||||
<<<<<<< HEAD
|
||||
|
||||
let html = '';
|
||||
=======
|
||||
var html = '';
|
||||
>>>>>>> upstream/master
|
||||
|
||||
const largeTitleTagName = layoutManager.tv ? 'h2' : 'div';
|
||||
|
||||
<<<<<<< HEAD
|
||||
for (let i = 0, length = textlines.length; i < length; i++) {
|
||||
|
||||
const text = textlines[i];
|
||||
|
||||
=======
|
||||
for (const [i, text] of textlines.entries()) {
|
||||
>>>>>>> upstream/master
|
||||
if (!text) {
|
||||
continue;
|
||||
}
|
||||
|
@ -284,10 +292,8 @@ import 'emby-playstatebutton';
|
|||
}
|
||||
|
||||
if (options.image !== false) {
|
||||
let imgData = options.imageSource === 'channel' ? getChannelImageUrl(item, downloadWidth) : getImageUrl(item, downloadWidth);
|
||||
let imgUrl = imgData.url;
|
||||
let blurhash = imgData.blurhash;
|
||||
let imageClass = isLargeStyle ? 'listItemImage listItemImage-large' : 'listItemImage';
|
||||
var imgUrl = options.imageSource === 'channel' ? getChannelImageUrl(item, downloadWidth) : getImageUrl(item, downloadWidth);
|
||||
var imageClass = isLargeStyle ? 'listItemImage listItemImage-large' : 'listItemImage';
|
||||
|
||||
if (isLargeStyle && layoutManager.tv) {
|
||||
imageClass += ' listItemImage-large-tv';
|
||||
|
@ -299,6 +305,7 @@ import 'emby-playstatebutton';
|
|||
imageClass += ' itemAction';
|
||||
}
|
||||
|
||||
<<<<<<< HEAD
|
||||
const imageAction = playOnImageClick ? 'resume' : action;
|
||||
|
||||
let blurhashAttrib = '';
|
||||
|
@ -310,6 +317,14 @@ import 'emby-playstatebutton';
|
|||
html += `<div data-action="${imageAction}" class="${imageClass} lazy" data-src="${imgUrl}" ${blurhashAttrib} item-icon>`;
|
||||
} else {
|
||||
html += `<div class="${imageClass}">`;
|
||||
=======
|
||||
var imageAction = playOnImageClick ? 'link' : action;
|
||||
|
||||
if (imgUrl) {
|
||||
html += '<div data-action="' + imageAction + '" class="' + imageClass + ' lazy" data-src="' + imgUrl + '" item-icon>';
|
||||
} else {
|
||||
html += '<div class="' + imageClass + ' cardImageContainer ' + cardBuilder.getDefaultBackgroundClass(item.Name) + '">' + cardBuilder.getDefaultText(item, options);
|
||||
>>>>>>> upstream/master
|
||||
}
|
||||
|
||||
let indicatorsHtml = '';
|
||||
|
@ -449,8 +464,6 @@ import 'emby-playstatebutton';
|
|||
|
||||
html += `<div class="${cssClass}">`;
|
||||
|
||||
const moreIcon = 'more_vert';
|
||||
|
||||
html += getTextLinesHtml(textlines, isLargeStyle);
|
||||
|
||||
if (options.mediaInfo !== false) {
|
||||
|
@ -505,10 +518,13 @@ import 'emby-playstatebutton';
|
|||
html += '<button is="paper-icon-button-light" class="listItemButton itemAction" data-action="addtoplaylist"><span class="material-icons playlist_add"></span></button>';
|
||||
}
|
||||
|
||||
<<<<<<< HEAD
|
||||
if (options.moreButton !== false) {
|
||||
html += `<button is="paper-icon-button-light" class="listItemButton itemAction" data-action="menu"><span class="material-icons ${moreIcon}"></span></button>`;
|
||||
}
|
||||
|
||||
=======
|
||||
>>>>>>> upstream/master
|
||||
if (options.infoButton) {
|
||||
html += '<button is="paper-icon-button-light" class="listItemButton itemAction" data-action="link"><span class="material-icons info_outline"></span></button>';
|
||||
}
|
||||
|
@ -522,13 +538,26 @@ import 'emby-playstatebutton';
|
|||
const userData = item.UserData || {};
|
||||
const likes = userData.Likes == null ? '' : userData.Likes;
|
||||
|
||||
<<<<<<< HEAD
|
||||
if (itemHelper.canMarkPlayed(item)) {
|
||||
html += `<button is="emby-playstatebutton" type="button" class="listItemButton paper-icon-button-light" data-id="${item.Id}" data-serverid="${item.ServerId}" data-itemtype="${item.Type}" data-played="${userData.Played}"><span class="material-icons check"></span></button>`;
|
||||
}
|
||||
|
||||
if (itemHelper.canRate(item)) {
|
||||
html += `<button is="emby-ratingbutton" type="button" class="listItemButton paper-icon-button-light" data-id="${item.Id}" data-serverid="${item.ServerId}" data-itemtype="${item.Type}" data-likes="${likes}" data-isfavorite="${userData.IsFavorite}"><span class="material-icons favorite"></span></button>`;
|
||||
=======
|
||||
if (itemHelper.canMarkPlayed(item) && options.enablePlayedButton !== false) {
|
||||
html += '<button is="emby-playstatebutton" type="button" class="listItemButton paper-icon-button-light" data-id="' + item.Id + '" data-serverid="' + item.ServerId + '" data-itemtype="' + item.Type + '" data-played="' + (userData.Played) + '"><span class="material-icons check"></span></button>';
|
||||
}
|
||||
|
||||
if (itemHelper.canRate(item) && options.enableRatingButton !== false) {
|
||||
html += '<button is="emby-ratingbutton" type="button" class="listItemButton paper-icon-button-light" data-id="' + item.Id + '" data-serverid="' + item.ServerId + '" data-itemtype="' + item.Type + '" data-likes="' + likes + '" data-isfavorite="' + (userData.IsFavorite) + '"><span class="material-icons favorite"></span></button>';
|
||||
>>>>>>> upstream/master
|
||||
}
|
||||
}
|
||||
|
||||
if (options.moreButton !== false) {
|
||||
html += '<button is="paper-icon-button-light" class="listItemButton itemAction" data-action="menu"><span class="material-icons more_vert"></span></button>';
|
||||
}
|
||||
}
|
||||
html += '</div>';
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 11 KiB |
|
@ -1,10 +1,6 @@
|
|||
define(['components/loading/loadingLegacy', 'browser', 'css!./loading'], function (loadingLegacy, browser) {
|
||||
define(['css!./loading'], function () {
|
||||
'use strict';
|
||||
|
||||
if (browser.tizen || browser.operaTv || browser.chromecast || browser.orsay || browser.web0s || browser.ps4) {
|
||||
return loadingLegacy;
|
||||
}
|
||||
|
||||
var loadingElem;
|
||||
var layer1;
|
||||
var layer2;
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
.loading-spinner {
|
||||
margin-top: -3em;
|
||||
margin-left: -3em;
|
||||
width: 6em;
|
||||
height: 6em;
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
z-index: 9999999;
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
define(['require', 'css!./loadingLegacy'], function (require) {
|
||||
'use strict';
|
||||
|
||||
var loadingElem;
|
||||
|
||||
return {
|
||||
show: function () {
|
||||
var elem = loadingElem;
|
||||
if (!elem) {
|
||||
elem = document.createElement('img');
|
||||
elem.src = require.toUrl('.').split('?')[0] + '/loader.gif';
|
||||
|
||||
loadingElem = elem;
|
||||
elem.classList.add('loading-spinner');
|
||||
|
||||
document.body.appendChild(elem);
|
||||
}
|
||||
|
||||
elem.classList.remove('hide');
|
||||
},
|
||||
hide: function () {
|
||||
var elem = loadingElem;
|
||||
if (elem) {
|
||||
elem.classList.add('hide');
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
|
@ -41,6 +41,8 @@
|
|||
width: auto !important;
|
||||
height: auto !important;
|
||||
font-size: 1.4em;
|
||||
margin-right: 0.125em;
|
||||
color: #f2b01e;
|
||||
}
|
||||
|
||||
.mediaInfoCriticRating {
|
||||
|
|
|
@ -266,6 +266,43 @@ import 'flexStyles';
|
|||
});
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
const btnRemoveFromEditorList = dom.parentWithClass(e.target, 'btnRemoveFromEditorList');
|
||||
|
@ -291,7 +328,6 @@ import 'flexStyles';
|
|||
}
|
||||
|
||||
function init(context, apiClient) {
|
||||
|
||||
context.querySelector('.externalIds').addEventListener('click', function (e) {
|
||||
const btnOpenExternalId = dom.parentWithClass(e.target, 'btnOpenExternalId');
|
||||
if (btnOpenExternalId) {
|
||||
|
@ -315,13 +351,17 @@ import 'flexStyles';
|
|||
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 {
|
||||
|
@ -1107,6 +1147,7 @@ import 'flexStyles';
|
|||
elem.innerHTML = globalize.translateHtml(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>
|
||||
|
|
|
@ -56,8 +56,8 @@
|
|||
text-align: left;
|
||||
flex-grow: 1;
|
||||
font-size: 92%;
|
||||
margin-right: 2.4em;
|
||||
margin-left: 1em;
|
||||
margin-right: 1em;
|
||||
margin-left: 0.5em;
|
||||
}
|
||||
|
||||
.nowPlayingBarCenter {
|
||||
|
@ -114,8 +114,6 @@
|
|||
|
||||
.nowPlayingBarUserDataButtons {
|
||||
display: inline-block;
|
||||
margin-left: 1em;
|
||||
margin-right: 1em;
|
||||
}
|
||||
|
||||
.nowPlayingBarPositionSlider::-webkit-slider-thumb {
|
||||
|
@ -133,33 +131,50 @@
|
|||
.toggleRepeatButton {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media all and (max-width: 62em) {
|
||||
.nowPlayingBarCenter .nowPlayingBarCurrentTime {
|
||||
.nowPlayingBar .btnShuffleQueue {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media all and (max-width: 80em) {
|
||||
.nowPlayingBarCenter .nowPlayingBarCurrentTime,
|
||||
.nowPlayingBarCenter .stopButton {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.nowPlayingBarInfoContainer {
|
||||
width: 45%;
|
||||
}
|
||||
}
|
||||
|
||||
.layout-mobile .nowPlayingBarRight button:not(.playPauseButton, .nextTrackButton) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.layout-desktop .nowPlayingBarRight .playPauseButton,
|
||||
.layout-tv .nowPlayingBarRight .playPauseButton {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.layout-mobile .nowPlayingBarRight input,
|
||||
.layout-mobile .nowPlayingBarRight div {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@media all and (max-width: 56em) {
|
||||
.nowPlayingBarCenter {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media all and (min-width: 56em) {
|
||||
.nowPlayingBarRight .playPauseButton {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media all and (max-width: 36em) {
|
||||
@media all and (max-width: 60em) {
|
||||
.nowPlayingBarRight .nowPlayingBarVolumeSliderContainer {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.nowPlayingBarInfoContainer {
|
||||
width: 70%;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -62,7 +62,9 @@ import 'emby-ratingbutton';
|
|||
html += '<button is="paper-icon-button-light" class="playPauseButton mediaButton"><span class="material-icons pause"></span></button>';
|
||||
|
||||
html += '<button is="paper-icon-button-light" class="stopButton mediaButton"><span class="material-icons stop"></span></button>';
|
||||
html += '<button is="paper-icon-button-light" class="nextTrackButton mediaButton"><span class="material-icons skip_next"></span></button>';
|
||||
if (!layoutManager.mobile) {
|
||||
html += '<button is="paper-icon-button-light" class="nextTrackButton mediaButton"><span class="material-icons skip_next"></span></button>';
|
||||
}
|
||||
|
||||
html += '<div class="nowPlayingBarCurrentTime"></div>';
|
||||
html += '</div>';
|
||||
|
@ -76,12 +78,17 @@ import 'emby-ratingbutton';
|
|||
html += '</div>';
|
||||
|
||||
html += '<button is="paper-icon-button-light" class="toggleRepeatButton mediaButton"><span class="material-icons repeat"></span></button>';
|
||||
html += '<button is="paper-icon-button-light" class="btnShuffleQueue mediaButton"><span class="material-icons shuffle"></span></button>';
|
||||
|
||||
html += '<div class="nowPlayingBarUserDataButtons">';
|
||||
html += '</div>';
|
||||
|
||||
html += '<button is="paper-icon-button-light" class="playPauseButton mediaButton"><span class="material-icons pause"></span></button>';
|
||||
html += '<button is="paper-icon-button-light" class="btnToggleContextMenu"><span class="material-icons more_vert"></span></button>';
|
||||
if (layoutManager.mobile) {
|
||||
html += '<button is="paper-icon-button-light" class="nextTrackButton mediaButton"><span class="material-icons skip_next"></span></button>';
|
||||
} else {
|
||||
html += '<button is="paper-icon-button-light" class="btnToggleContextMenu mediaButton"><span class="material-icons more_vert"></span></button>';
|
||||
}
|
||||
|
||||
html += '</div>';
|
||||
html += '</div>';
|
||||
|
@ -132,8 +139,13 @@ import 'emby-ratingbutton';
|
|||
nowPlayingImageElement = elem.querySelector('.nowPlayingImage');
|
||||
nowPlayingTextElement = elem.querySelector('.nowPlayingBarText');
|
||||
nowPlayingUserData = elem.querySelector('.nowPlayingBarUserDataButtons');
|
||||
|
||||
positionSlider = elem.querySelector('.nowPlayingBarPositionSlider');
|
||||
muteButton = elem.querySelector('.muteButton');
|
||||
playPauseButtons = elem.querySelectorAll('.playPauseButton');
|
||||
toggleRepeatButton = elem.querySelector('.toggleRepeatButton');
|
||||
volumeSlider = elem.querySelector('.nowPlayingBarVolumeSlider');
|
||||
volumeSliderContainer = elem.querySelector('.nowPlayingBarVolumeSliderContainer');
|
||||
|
||||
muteButton.addEventListener('click', function () {
|
||||
|
||||
if (currentPlayer) {
|
||||
|
@ -149,7 +161,6 @@ import 'emby-ratingbutton';
|
|||
}
|
||||
});
|
||||
|
||||
playPauseButtons = elem.querySelectorAll('.playPauseButton');
|
||||
playPauseButtons.forEach((button) => {
|
||||
button.addEventListener('click', onPlayPauseClick);
|
||||
});
|
||||
|
@ -161,54 +172,59 @@ import 'emby-ratingbutton';
|
|||
}
|
||||
});
|
||||
|
||||
elem.querySelector('.previousTrackButton').addEventListener('click', function () {
|
||||
elem.querySelector('.previousTrackButton').addEventListener('click', function (e) {
|
||||
if (currentPlayer) {
|
||||
if (lastPlayerState.NowPlayingItem.MediaType === 'Audio' && (currentPlayer._currentTime >= 5 || !playbackManager.previousTrack(currentPlayer))) {
|
||||
// Cancel this event if doubleclick is fired
|
||||
if (e.detail > 1 && playbackManager.previousTrack(currentPlayer)) {
|
||||
return;
|
||||
}
|
||||
playbackManager.seekPercent(0, currentPlayer);
|
||||
// This is done automatically by playbackManager, however, setting this here gives instant visual feedback.
|
||||
// TODO: Check why seekPercentage doesn't reflect the changes inmmediately, so we can remove this workaround.
|
||||
positionSlider.value = 0;
|
||||
} else {
|
||||
playbackManager.previousTrack(currentPlayer);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
elem.querySelector('.previousTrackButton').addEventListener('dblclick', function () {
|
||||
if (currentPlayer) {
|
||||
playbackManager.previousTrack(currentPlayer);
|
||||
}
|
||||
});
|
||||
|
||||
elem.querySelector('.btnShuffleQueue').addEventListener('click', function () {
|
||||
if (currentPlayer) {
|
||||
playbackManager.toggleQueueShuffleMode();
|
||||
}
|
||||
});
|
||||
|
||||
toggleRepeatButton = elem.querySelector('.toggleRepeatButton');
|
||||
toggleRepeatButton.addEventListener('click', function () {
|
||||
|
||||
if (currentPlayer) {
|
||||
|
||||
switch (playbackManager.getRepeatMode(currentPlayer)) {
|
||||
case 'RepeatAll':
|
||||
playbackManager.setRepeatMode('RepeatOne', currentPlayer);
|
||||
break;
|
||||
case 'RepeatOne':
|
||||
playbackManager.setRepeatMode('RepeatNone', currentPlayer);
|
||||
break;
|
||||
default:
|
||||
playbackManager.setRepeatMode('RepeatAll', currentPlayer);
|
||||
break;
|
||||
}
|
||||
switch (playbackManager.getRepeatMode()) {
|
||||
case 'RepeatAll':
|
||||
playbackManager.setRepeatMode('RepeatOne');
|
||||
break;
|
||||
case 'RepeatOne':
|
||||
playbackManager.setRepeatMode('RepeatNone');
|
||||
break;
|
||||
case 'RepeatNone':
|
||||
playbackManager.setRepeatMode('RepeatAll');
|
||||
}
|
||||
});
|
||||
|
||||
toggleRepeatButtonIcon = toggleRepeatButton.querySelector('.material-icons');
|
||||
|
||||
volumeSlider = elem.querySelector('.nowPlayingBarVolumeSlider');
|
||||
volumeSliderContainer = elem.querySelector('.nowPlayingBarVolumeSliderContainer');
|
||||
volumeSliderContainer.classList.toggle('hide', appHost.supports('physicalvolumecontrol'));
|
||||
|
||||
if (appHost.supports('physicalvolumecontrol')) {
|
||||
volumeSliderContainer.classList.add('hide');
|
||||
} else {
|
||||
volumeSliderContainer.classList.remove('hide');
|
||||
}
|
||||
|
||||
function setVolume() {
|
||||
volumeSlider.addEventListener('input', (e) => {
|
||||
if (currentPlayer) {
|
||||
currentPlayer.setVolume(this.value);
|
||||
currentPlayer.setVolume(e.target.value);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
volumeSlider.addEventListener('change', setVolume);
|
||||
volumeSlider.addEventListener('mousemove', setVolume);
|
||||
volumeSlider.addEventListener('touchmove', setVolume);
|
||||
|
||||
positionSlider = elem.querySelector('.nowPlayingBarPositionSlider');
|
||||
positionSlider.addEventListener('change', function () {
|
||||
|
||||
if (currentPlayer) {
|
||||
|
@ -277,6 +293,11 @@ import 'emby-ratingbutton';
|
|||
parentContainer.insertAdjacentHTML('afterbegin', getNowPlayingBarHtml());
|
||||
nowPlayingBarElement = parentContainer.querySelector('.nowPlayingBar');
|
||||
|
||||
if (layoutManager.mobile) {
|
||||
hideButton(nowPlayingBarElement.querySelector('.btnShuffleQueue'));
|
||||
hideButton(nowPlayingBarElement.querySelector('.nowPlayingBarCenter'));
|
||||
}
|
||||
|
||||
if (browser.safari && browser.slow) {
|
||||
// Not handled well here. The wrong elements receive events, bar doesn't update quickly enough, etc.
|
||||
nowPlayingBarElement.classList.add('noMediaProgress');
|
||||
|
@ -329,7 +350,8 @@ import 'emby-ratingbutton';
|
|||
toggleRepeatButton.classList.remove('hide');
|
||||
}
|
||||
|
||||
updateRepeatModeDisplay(playState.RepeatMode);
|
||||
updateRepeatModeDisplay(playbackManager.getRepeatMode());
|
||||
onQueueShuffleModeChange();
|
||||
|
||||
updatePlayerVolumeState(playState.IsMuted, playState.VolumeLevel);
|
||||
|
||||
|
@ -349,32 +371,39 @@ import 'emby-ratingbutton';
|
|||
|
||||
function updateRepeatModeDisplay(repeatMode) {
|
||||
toggleRepeatButtonIcon.classList.remove('repeat', 'repeat_one');
|
||||
const cssClass = 'buttonActive';
|
||||
|
||||
if (repeatMode === 'RepeatAll') {
|
||||
toggleRepeatButtonIcon.classList.add('repeat');
|
||||
toggleRepeatButton.classList.add('repeatButton-active');
|
||||
} else if (repeatMode === 'RepeatOne') {
|
||||
toggleRepeatButtonIcon.classList.add('repeat_one');
|
||||
toggleRepeatButton.classList.add('repeatButton-active');
|
||||
} else {
|
||||
toggleRepeatButtonIcon.classList.add('repeat');
|
||||
toggleRepeatButton.classList.remove('repeatButton-active');
|
||||
switch (repeatMode) {
|
||||
case 'RepeatAll':
|
||||
toggleRepeatButtonIcon.classList.add('repeat');
|
||||
toggleRepeatButton.classList.add(cssClass);
|
||||
break;
|
||||
case 'RepeatOne':
|
||||
toggleRepeatButtonIcon.classList.add('repeat_one');
|
||||
toggleRepeatButton.classList.add(cssClass);
|
||||
break;
|
||||
case 'RepeatNone':
|
||||
default:
|
||||
toggleRepeatButtonIcon.classList.add('repeat');
|
||||
toggleRepeatButton.classList.remove(cssClass);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function updateTimeDisplay(positionTicks, runtimeTicks, bufferedRanges) {
|
||||
|
||||
// See bindEvents for why this is necessary
|
||||
if (positionSlider && !positionSlider.dragging) {
|
||||
if (runtimeTicks) {
|
||||
<<<<<<< HEAD
|
||||
|
||||
let pct = positionTicks / runtimeTicks;
|
||||
=======
|
||||
var pct = positionTicks / runtimeTicks;
|
||||
>>>>>>> upstream/master
|
||||
pct *= 100;
|
||||
|
||||
positionSlider.value = pct;
|
||||
|
||||
} else {
|
||||
|
||||
positionSlider.value = 0;
|
||||
}
|
||||
}
|
||||
|
@ -384,9 +413,13 @@ import 'emby-ratingbutton';
|
|||
}
|
||||
|
||||
if (currentTimeElement) {
|
||||
<<<<<<< HEAD
|
||||
|
||||
let timeText = positionTicks == null ? '--:--' : datetime.getDisplayRunningTime(positionTicks);
|
||||
|
||||
=======
|
||||
var timeText = positionTicks == null ? '--:--' : datetime.getDisplayRunningTime(positionTicks);
|
||||
>>>>>>> upstream/master
|
||||
if (runtimeTicks) {
|
||||
timeText += ' / ' + datetime.getDisplayRunningTime(runtimeTicks);
|
||||
}
|
||||
|
@ -428,11 +461,7 @@ import 'emby-ratingbutton';
|
|||
// See bindEvents for why this is necessary
|
||||
if (volumeSlider) {
|
||||
|
||||
if (showVolumeSlider) {
|
||||
volumeSliderContainer.classList.remove('hide');
|
||||
} else {
|
||||
volumeSliderContainer.classList.add('hide');
|
||||
}
|
||||
volumeSliderContainer.classList.toggle('hide', !showVolumeSlider);
|
||||
|
||||
if (!volumeSlider.dragging) {
|
||||
volumeSlider.value = volumeLevel || 0;
|
||||
|
@ -440,15 +469,6 @@ import 'emby-ratingbutton';
|
|||
}
|
||||
}
|
||||
|
||||
function getTextActionButton(item, text) {
|
||||
|
||||
if (!text) {
|
||||
text = itemHelper.getDisplayName(item);
|
||||
}
|
||||
|
||||
return `<a>${text}</a>`;
|
||||
}
|
||||
|
||||
function seriesImageUrl(item, options) {
|
||||
|
||||
if (!item) {
|
||||
|
@ -520,6 +540,7 @@ import 'emby-ratingbutton';
|
|||
|
||||
const nowPlayingItem = state.NowPlayingItem;
|
||||
|
||||
<<<<<<< HEAD
|
||||
const textLines = nowPlayingItem ? nowPlayingHelper.getNowPlayingNames(nowPlayingItem) : [];
|
||||
if (textLines.length > 1) {
|
||||
textLines[1].secondary = true;
|
||||
|
@ -536,6 +557,31 @@ import 'emby-ratingbutton';
|
|||
return `<div ${cssClass}>${nowPlayingText}</div>`;
|
||||
|
||||
}).join('');
|
||||
=======
|
||||
var textLines = nowPlayingItem ? nowPlayingHelper.getNowPlayingNames(nowPlayingItem) : [];
|
||||
nowPlayingTextElement.innerHTML = '';
|
||||
if (textLines) {
|
||||
let itemText = document.createElement('div');
|
||||
let secondaryText = document.createElement('div');
|
||||
secondaryText.classList.add('nowPlayingBarSecondaryText');
|
||||
if (textLines.length > 1) {
|
||||
textLines[1].secondary = true;
|
||||
if (textLines[1].text) {
|
||||
let text = document.createElement('a');
|
||||
text.innerHTML = textLines[1].text;
|
||||
secondaryText.appendChild(text);
|
||||
}
|
||||
}
|
||||
|
||||
if (textLines[0].text) {
|
||||
let text = document.createElement('a');
|
||||
text.innerHTML = textLines[0].text;
|
||||
itemText.appendChild(text);
|
||||
}
|
||||
nowPlayingTextElement.appendChild(itemText);
|
||||
nowPlayingTextElement.appendChild(secondaryText);
|
||||
}
|
||||
>>>>>>> upstream/master
|
||||
|
||||
const imgHeight = 70;
|
||||
|
||||
|
@ -553,8 +599,12 @@ import 'emby-ratingbutton';
|
|||
|
||||
if (url) {
|
||||
imageLoader.lazyImage(nowPlayingImageElement, url);
|
||||
nowPlayingImageElement.style.display = null;
|
||||
nowPlayingTextElement.style.marginLeft = null;
|
||||
} else {
|
||||
nowPlayingImageElement.style.backgroundImage = '';
|
||||
nowPlayingImageElement.style.display = 'none';
|
||||
nowPlayingTextElement.style.marginLeft = '1em';
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -563,6 +613,7 @@ import 'emby-ratingbutton';
|
|||
|
||||
const apiClient = connectionManager.getApiClient(nowPlayingItem.ServerId);
|
||||
apiClient.getItem(apiClient.getCurrentUserId(), nowPlayingItem.Id).then(function (item) {
|
||||
<<<<<<< HEAD
|
||||
const userData = item.UserData || {};
|
||||
const likes = userData.Likes == null ? '' : userData.Likes;
|
||||
const contextButton = document.querySelector('.btnToggleContextMenu');
|
||||
|
@ -578,8 +629,32 @@ import 'emby-ratingbutton';
|
|||
item: item,
|
||||
user: user
|
||||
}, options ));
|
||||
=======
|
||||
var userData = item.UserData || {};
|
||||
var likes = userData.Likes == null ? '' : userData.Likes;
|
||||
if (!layoutManager.mobile) {
|
||||
let contextButton = nowPlayingBarElement.querySelector('.btnToggleContextMenu');
|
||||
// We remove the previous event listener by replacing the item in each update event
|
||||
let contextButtonClone = contextButton.cloneNode(true);
|
||||
contextButton.parentNode.replaceChild(contextButtonClone, contextButton);
|
||||
contextButton = nowPlayingBarElement.querySelector('.btnToggleContextMenu');
|
||||
let options = {
|
||||
play: false,
|
||||
queue: false,
|
||||
clearQueue: true,
|
||||
positionTo: contextButton
|
||||
};
|
||||
apiClient.getCurrentUser().then(function (user) {
|
||||
contextButton.addEventListener('click', function () {
|
||||
itemContextMenu.show(Object.assign({
|
||||
item: item,
|
||||
user: user
|
||||
}, options));
|
||||
});
|
||||
>>>>>>> upstream/master
|
||||
});
|
||||
});
|
||||
}
|
||||
nowPlayingUserData.innerHTML = '<button is="emby-ratingbutton" type="button" class="listItemButton mediaButton paper-icon-button-light" data-id="' + item.Id + '" data-serverid="' + item.ServerId + '" data-itemtype="' + item.Type + '" data-likes="' + likes + '" data-isfavorite="' + (userData.IsFavorite) + '"><span class="material-icons favorite"></span></button>';
|
||||
});
|
||||
}
|
||||
} else {
|
||||
|
@ -589,25 +664,49 @@ import 'emby-ratingbutton';
|
|||
|
||||
function onPlaybackStart(e, state) {
|
||||
console.debug('nowplaying event: ' + e.type);
|
||||
<<<<<<< HEAD
|
||||
|
||||
const player = this;
|
||||
|
||||
=======
|
||||
var player = this;
|
||||
>>>>>>> upstream/master
|
||||
onStateChanged.call(player, e, state);
|
||||
}
|
||||
|
||||
function onRepeatModeChange(e) {
|
||||
|
||||
function onRepeatModeChange() {
|
||||
if (!isEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
<<<<<<< HEAD
|
||||
const player = this;
|
||||
=======
|
||||
updateRepeatModeDisplay(playbackManager.getRepeatMode());
|
||||
}
|
||||
|
||||
updateRepeatModeDisplay(playbackManager.getRepeatMode(player));
|
||||
function onQueueShuffleModeChange() {
|
||||
if (!isEnabled) {
|
||||
return;
|
||||
}
|
||||
>>>>>>> upstream/master
|
||||
|
||||
let shuffleMode = playbackManager.getQueueShuffleMode();
|
||||
let context = nowPlayingBarElement;
|
||||
const cssClass = 'buttonActive';
|
||||
let toggleShuffleButton = context.querySelector('.btnShuffleQueue');
|
||||
switch (shuffleMode) {
|
||||
case 'Shuffle':
|
||||
toggleShuffleButton.classList.add(cssClass);
|
||||
break;
|
||||
case 'Sorted':
|
||||
default:
|
||||
toggleShuffleButton.classList.remove(cssClass);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function showNowPlayingBar() {
|
||||
|
||||
if (!isVisibilityAllowed) {
|
||||
hideNowPlayingBar();
|
||||
return;
|
||||
|
@ -711,6 +810,7 @@ import 'emby-ratingbutton';
|
|||
events.off(player, 'playbackstart', onPlaybackStart);
|
||||
events.off(player, 'statechange', onPlaybackStart);
|
||||
events.off(player, 'repeatmodechange', onRepeatModeChange);
|
||||
events.off(player, 'shufflequeuemodechange', onQueueShuffleModeChange);
|
||||
events.off(player, 'playbackstop', onPlaybackStopped);
|
||||
events.off(player, 'volumechange', onVolumeChanged);
|
||||
events.off(player, 'pause', onPlayPauseStateChanged);
|
||||
|
@ -759,6 +859,7 @@ import 'emby-ratingbutton';
|
|||
events.on(player, 'playbackstart', onPlaybackStart);
|
||||
events.on(player, 'statechange', onPlaybackStart);
|
||||
events.on(player, 'repeatmodechange', onRepeatModeChange);
|
||||
events.on(player, 'shufflequeuemodechange', onQueueShuffleModeChange);
|
||||
events.on(player, 'playbackstop', onPlaybackStopped);
|
||||
events.on(player, 'volumechange', onVolumeChanged);
|
||||
events.on(player, 'pause', onPlayPauseStateChanged);
|
||||
|
|
|
@ -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) {
|
||||
|
@ -43,12 +40,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 +60,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
|
||||
|
@ -2097,6 +2080,7 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla
|
|||
state.PlayState.IsMuted = player.isMuted();
|
||||
state.PlayState.IsPaused = player.paused();
|
||||
state.PlayState.RepeatMode = self.getRepeatMode(player);
|
||||
state.PlayState.ShuffleMode = self.getQueueShuffleMode(player);
|
||||
state.PlayState.MaxStreamingBitrate = self.getMaxStreamingBitrate(player);
|
||||
|
||||
state.PlayState.PositionTicks = getCurrentTicks(player);
|
||||
|
@ -2877,11 +2861,11 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla
|
|||
}
|
||||
};
|
||||
|
||||
self.queue = function (options, player) {
|
||||
self.queue = function (options, player = this._currentPlayer) {
|
||||
queue(options, '', player);
|
||||
};
|
||||
|
||||
self.queueNext = function (options, player) {
|
||||
self.queueNext = function (options, player = this._currentPlayer) {
|
||||
queue(options, 'next', player);
|
||||
};
|
||||
|
||||
|
@ -2969,6 +2953,7 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla
|
|||
} else {
|
||||
self._playQueueManager.queue(items);
|
||||
}
|
||||
events.trigger(player, 'playlistitemadd');
|
||||
}
|
||||
|
||||
function onPlayerProgressInterval() {
|
||||
|
@ -3304,6 +3289,11 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla
|
|||
sendProgressUpdate(player, 'repeatmodechange');
|
||||
}
|
||||
|
||||
function onShuffleQueueModeChange() {
|
||||
var player = this;
|
||||
sendProgressUpdate(player, 'shufflequeuemodechange');
|
||||
}
|
||||
|
||||
function onPlaylistItemMove(e) {
|
||||
var player = this;
|
||||
sendProgressUpdate(player, 'playlistitemmove', true);
|
||||
|
@ -3358,6 +3348,7 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla
|
|||
events.on(player, 'unpause', onPlaybackUnpause);
|
||||
events.on(player, 'volumechange', onPlaybackVolumeChange);
|
||||
events.on(player, 'repeatmodechange', onRepeatModeChange);
|
||||
events.on(player, 'shufflequeuemodechange', onShuffleQueueModeChange);
|
||||
events.on(player, 'playlistitemmove', onPlaylistItemMove);
|
||||
events.on(player, 'playlistitemremove', onPlaylistItemRemove);
|
||||
events.on(player, 'playlistitemadd', onPlaylistItemAdd);
|
||||
|
@ -3370,6 +3361,7 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla
|
|||
events.on(player, 'unpause', onPlaybackUnpause);
|
||||
events.on(player, 'volumechange', onPlaybackVolumeChange);
|
||||
events.on(player, 'repeatmodechange', onRepeatModeChange);
|
||||
events.on(player, 'shufflequeuemodechange', onShuffleQueueModeChange);
|
||||
events.on(player, 'playlistitemmove', onPlaylistItemMove);
|
||||
events.on(player, 'playlistitemremove', onPlaylistItemRemove);
|
||||
events.on(player, 'playlistitemadd', onPlaylistItemAdd);
|
||||
|
@ -3655,6 +3647,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;
|
||||
|
@ -3702,7 +3702,6 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla
|
|||
};
|
||||
|
||||
PlaybackManager.prototype.stop = function (player) {
|
||||
|
||||
player = player || this._currentPlayer;
|
||||
|
||||
if (player) {
|
||||
|
@ -3811,7 +3810,7 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla
|
|||
});
|
||||
};
|
||||
|
||||
PlaybackManager.prototype.shuffle = function (shuffleItem, player, queryOptions) {
|
||||
PlaybackManager.prototype.shuffle = function (shuffleItem, player) {
|
||||
|
||||
player = player || this._currentPlayer;
|
||||
if (player && player.shuffle) {
|
||||
|
@ -3878,6 +3877,7 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla
|
|||
'GoToSearch',
|
||||
'DisplayMessage',
|
||||
'SetRepeatMode',
|
||||
'SetShuffleQueue',
|
||||
'PlayMediaSource',
|
||||
'PlayTrailers'
|
||||
];
|
||||
|
@ -3911,9 +3911,7 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla
|
|||
return info ? info.supportedCommands : [];
|
||||
};
|
||||
|
||||
PlaybackManager.prototype.setRepeatMode = function (value, player) {
|
||||
|
||||
player = player || this._currentPlayer;
|
||||
PlaybackManager.prototype.setRepeatMode = function (value, player = this._currentPlayer) {
|
||||
if (player && !enableLocalPlaylistManagement(player)) {
|
||||
return player.setRepeatMode(value);
|
||||
}
|
||||
|
@ -3922,9 +3920,7 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla
|
|||
events.trigger(player, 'repeatmodechange');
|
||||
};
|
||||
|
||||
PlaybackManager.prototype.getRepeatMode = function (player) {
|
||||
|
||||
player = player || this._currentPlayer;
|
||||
PlaybackManager.prototype.getRepeatMode = function (player = this._currentPlayer) {
|
||||
if (player && !enableLocalPlaylistManagement(player)) {
|
||||
return player.getRepeatMode();
|
||||
}
|
||||
|
@ -3932,6 +3928,52 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla
|
|||
return this._playQueueManager.getRepeatMode();
|
||||
};
|
||||
|
||||
PlaybackManager.prototype.setQueueShuffleMode = function (value, player = this._currentPlayer) {
|
||||
if (player && !enableLocalPlaylistManagement(player)) {
|
||||
return player.setQueueShuffleMode(value);
|
||||
}
|
||||
|
||||
this._playQueueManager.setShuffleMode(value);
|
||||
events.trigger(player, 'shufflequeuemodechange');
|
||||
};
|
||||
|
||||
PlaybackManager.prototype.getQueueShuffleMode = function (player = this._currentPlayer) {
|
||||
if (player && !enableLocalPlaylistManagement(player)) {
|
||||
return player.getQueueShuffleMode();
|
||||
}
|
||||
|
||||
return this._playQueueManager.getShuffleMode();
|
||||
};
|
||||
|
||||
PlaybackManager.prototype.toggleQueueShuffleMode = function (player = this._currentPlayer) {
|
||||
let currentvalue;
|
||||
if (player && !enableLocalPlaylistManagement(player)) {
|
||||
currentvalue = player.getQueueShuffleMode();
|
||||
switch (currentvalue) {
|
||||
case 'Shuffle':
|
||||
player.setQueueShuffleMode('Sorted');
|
||||
break;
|
||||
case 'Sorted':
|
||||
player.setQueueShuffleMode('Shuffle');
|
||||
break;
|
||||
default:
|
||||
throw new TypeError('current value for shufflequeue is invalid');
|
||||
}
|
||||
} else {
|
||||
this._playQueueManager.toggleShuffleMode();
|
||||
}
|
||||
events.trigger(player, 'shufflequeuemodechange');
|
||||
};
|
||||
|
||||
PlaybackManager.prototype.clearQueue = function (clearCurrentItem = false, player = this._currentPlayer) {
|
||||
if (player && !enableLocalPlaylistManagement(player)) {
|
||||
return player.clearQueue(clearCurrentItem);
|
||||
}
|
||||
|
||||
this._playQueueManager.clearPlaylist(clearCurrentItem);
|
||||
events.trigger(player, 'playlistitemremove');
|
||||
};
|
||||
|
||||
PlaybackManager.prototype.trySetActiveDeviceName = function (name) {
|
||||
|
||||
name = normalizeName(name);
|
||||
|
@ -4000,6 +4042,9 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla
|
|||
case 'SetRepeatMode':
|
||||
this.setRepeatMode(cmd.Arguments.RepeatMode, player);
|
||||
break;
|
||||
case 'SetShuffleQueue':
|
||||
this.setQueueShuffleMode(cmd.Arguments.ShuffleMode, player);
|
||||
break;
|
||||
case 'VolumeUp':
|
||||
this.volumeUp(player);
|
||||
break;
|
||||
|
|
|
@ -24,8 +24,10 @@ define([], function () {
|
|||
|
||||
function PlayQueueManager() {
|
||||
|
||||
this._sortedPlaylist = [];
|
||||
this._playlist = [];
|
||||
this._repeatMode = 'RepeatNone';
|
||||
this._shuffleMode = 'Sorted';
|
||||
}
|
||||
|
||||
PlayQueueManager.prototype.getPlaylist = function () {
|
||||
|
@ -56,6 +58,40 @@ define([], function () {
|
|||
}
|
||||
};
|
||||
|
||||
PlayQueueManager.prototype.shufflePlaylist = function () {
|
||||
this._sortedPlaylist = [];
|
||||
for (const item of this._playlist) {
|
||||
this._sortedPlaylist.push(item);
|
||||
}
|
||||
const currentPlaylistItem = this._playlist.splice(this.getCurrentPlaylistIndex(), 1)[0];
|
||||
|
||||
for (let i = this._playlist.length - 1; i > 0; i--) {
|
||||
const j = Math.floor(Math.random() * i);
|
||||
const temp = this._playlist[i];
|
||||
this._playlist[i] = this._playlist[j];
|
||||
this._playlist[j] = temp;
|
||||
}
|
||||
this._playlist.unshift(currentPlaylistItem);
|
||||
this._shuffleMode = 'Shuffle';
|
||||
};
|
||||
|
||||
PlayQueueManager.prototype.sortShuffledPlaylist = function () {
|
||||
this._playlist = [];
|
||||
for (let item of this._sortedPlaylist) {
|
||||
this._playlist.push(item);
|
||||
}
|
||||
this._sortedPlaylist = [];
|
||||
this._shuffleMode = 'Sorted';
|
||||
};
|
||||
|
||||
PlayQueueManager.prototype.clearPlaylist = function (clearCurrentItem = false) {
|
||||
const currentPlaylistItem = this._playlist.splice(this.getCurrentPlaylistIndex(), 1)[0];
|
||||
this._playlist = [];
|
||||
if (!clearCurrentItem) {
|
||||
this._playlist.push(currentPlaylistItem);
|
||||
}
|
||||
};
|
||||
|
||||
function arrayInsertAt(destArray, pos, arrayToInsert) {
|
||||
var args = [];
|
||||
args.push(pos); // where to insert
|
||||
|
@ -116,9 +152,7 @@ define([], function () {
|
|||
|
||||
PlayQueueManager.prototype.removeFromPlaylist = function (playlistItemIds) {
|
||||
|
||||
var playlist = this.getPlaylist();
|
||||
|
||||
if (playlist.length <= playlistItemIds.length) {
|
||||
if (this._playlist.length <= playlistItemIds.length) {
|
||||
return {
|
||||
result: 'empty'
|
||||
};
|
||||
|
@ -127,8 +161,12 @@ define([], function () {
|
|||
var currentPlaylistItemId = this.getCurrentPlaylistItemId();
|
||||
var isCurrentIndex = playlistItemIds.indexOf(currentPlaylistItemId) !== -1;
|
||||
|
||||
this._playlist = playlist.filter(function (item) {
|
||||
return playlistItemIds.indexOf(item.PlaylistItemId) === -1;
|
||||
this._sortedPlaylist = this._sortedPlaylist.filter(function (item) {
|
||||
return !playlistItemIds.includes(item.PlaylistItemId);
|
||||
});
|
||||
|
||||
this._playlist = this._playlist.filter(function (item) {
|
||||
return !playlistItemIds.includes(item.PlaylistItemId);
|
||||
});
|
||||
|
||||
return {
|
||||
|
@ -176,21 +214,56 @@ define([], function () {
|
|||
|
||||
PlayQueueManager.prototype.reset = function () {
|
||||
|
||||
this._sortedPlaylist = [];
|
||||
this._playlist = [];
|
||||
this._currentPlaylistItemId = null;
|
||||
this._repeatMode = 'RepeatNone';
|
||||
this._shuffleMode = 'Sorted';
|
||||
};
|
||||
|
||||
PlayQueueManager.prototype.setRepeatMode = function (value) {
|
||||
|
||||
this._repeatMode = value;
|
||||
const repeatModes = ['RepeatOne', 'RepeatAll', 'RepeatNone'];
|
||||
if (repeatModes.includes(value)) {
|
||||
this._repeatMode = value;
|
||||
} else {
|
||||
throw new TypeError('invalid value provided for setRepeatMode');
|
||||
}
|
||||
};
|
||||
|
||||
PlayQueueManager.prototype.getRepeatMode = function () {
|
||||
|
||||
return this._repeatMode;
|
||||
};
|
||||
|
||||
PlayQueueManager.prototype.setShuffleMode = function (value) {
|
||||
switch (value) {
|
||||
case 'Shuffle':
|
||||
this.shufflePlaylist();
|
||||
break;
|
||||
case 'Sorted':
|
||||
this.sortShuffledPlaylist();
|
||||
break;
|
||||
default:
|
||||
throw new TypeError('invalid value provided to setShuffleMode');
|
||||
}
|
||||
};
|
||||
|
||||
PlayQueueManager.prototype.toggleShuffleMode = function () {
|
||||
switch (this._shuffleMode) {
|
||||
case 'Shuffle':
|
||||
this.setShuffleMode('Sorted');
|
||||
break;
|
||||
case 'Sorted':
|
||||
this.setShuffleMode('Shuffle');
|
||||
break;
|
||||
default:
|
||||
throw new TypeError('current value for shufflequeue is invalid');
|
||||
}
|
||||
};
|
||||
|
||||
PlayQueueManager.prototype.getShuffleMode = function () {
|
||||
return this._shuffleMode;
|
||||
};
|
||||
|
||||
PlayQueueManager.prototype.getNextItemInfo = function () {
|
||||
|
||||
var newIndex;
|
||||
|
|
|
@ -415,7 +415,8 @@ import 'css!./playerstats';
|
|||
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'
|
||||
|
|
|
@ -157,43 +157,110 @@
|
|||
}
|
||||
|
||||
.nowPlayingSecondaryButtons {
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: flex;
|
||||
-webkit-box-align: center;
|
||||
-webkit-align-items: center;
|
||||
align-items: center;
|
||||
-webkit-flex-wrap: wrap;
|
||||
flex-wrap: wrap;
|
||||
-webkit-box-pack: end;
|
||||
-webkit-justify-content: flex-end;
|
||||
justify-content: flex-end;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.layout-mobile .playlistSectionButtonTransparent {
|
||||
background: rgba(0, 0, 0, 0) !important;
|
||||
}
|
||||
|
||||
.layout-mobile .playlistSection .playlist,
|
||||
.layout-mobile .playlistSection .contextMenu {
|
||||
position: absolute;
|
||||
top: 12.2em;
|
||||
bottom: 4.2em;
|
||||
overflow: scroll;
|
||||
padding: 0 1em;
|
||||
display: inline-block;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.layout-mobile .playlistSectionButton {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
height: 4.2em;
|
||||
right: 0;
|
||||
padding-left: 7.3%;
|
||||
padding-right: 7.3%;
|
||||
}
|
||||
|
||||
.layout-desktop .playlistSectionButton,
|
||||
.layout-tv .playlistSectionButton {
|
||||
background: none;
|
||||
}
|
||||
|
||||
.layout-desktop .nowPlayingPlaylist,
|
||||
.layout-tv .nowPlayingPlaylist {
|
||||
background: none;
|
||||
}
|
||||
|
||||
.layout-mobile .playlistSectionButton .btnTogglePlaylist {
|
||||
font-size: larger;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.layout-mobile .playlistSectionButton .btnSavePlaylist {
|
||||
margin: 0;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.layout-mobile .playlistSectionButton .volumecontrol {
|
||||
margin: 0;
|
||||
padding-right: 0;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.layout-mobile .playlistSectionButton .btnToggleContextMenu {
|
||||
font-size: larger;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.layout-mobile .nowPlayingSecondaryButtons .btnShuffleQueue {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.layout-mobile .nowPlayingSecondaryButtons .volumecontrol {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.layout-mobile .nowPlayingSecondaryButtons .btnRepeat {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.layout-desktop .nowPlayingInfoButtons .btnRepeat,
|
||||
.layout-tv .nowPlayingInfoButtons .btnRepeat {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.layout-desktop .nowPlayingInfoButtons .btnShuffleQueue,
|
||||
.layout-tv .nowPlayingInfoButtons .btnShuffleQueue {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.layout-desktop .playlistSectionButton .volumecontrol,
|
||||
.layout-tv .playlistSectionButton .volumecontrol {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.nowPlayingInfoControls .nowPlayingPageUserDataButtonsTitle {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.layout-mobile .nowPlayingPageUserDataButtons {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@media all and (min-width: 63em) {
|
||||
.nowPlayingPage {
|
||||
padding: 8em 0 0 0 !important;
|
||||
}
|
||||
|
||||
.nowPlayingSecondaryButtons {
|
||||
-webkit-box-flex: 1;
|
||||
-webkit-flex-grow: 1;
|
||||
flex-grow: 1;
|
||||
-webkit-box-pack: end;
|
||||
-webkit-justify-content: flex-end;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.nowPlayingPageUserDataButtonsTitle {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.playlistSectionButton,
|
||||
.nowPlayingPlaylist,
|
||||
.nowPlayingContextMenu {
|
||||
background: unset !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media all and (min-width: 80em) {
|
||||
|
@ -202,7 +269,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
@media all and (orientation: portrait) and (max-width: 47em) {
|
||||
@media all and (orientation: portrait) and (max-width: 43em) {
|
||||
.remoteControlContent {
|
||||
padding-left: 7.3% !important;
|
||||
padding-right: 7.3% !important;
|
||||
|
@ -211,6 +278,10 @@
|
|||
flex-direction: column;
|
||||
}
|
||||
|
||||
.layout-desktop .nowPlayingPageUserDataButtons {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.nowPlayingInfoContainer {
|
||||
-webkit-box-orient: vertical !important;
|
||||
-webkit-box-direction: normal !important;
|
||||
|
@ -280,6 +351,7 @@
|
|||
.nowPlayingInfoControls .nowPlayingPageUserDataButtonsTitle {
|
||||
width: 20%;
|
||||
font-size: large;
|
||||
display: unset;
|
||||
}
|
||||
|
||||
.nowPlayingInfoControls .nowPlayingPageUserDataButtonsTitle button {
|
||||
|
@ -290,7 +362,7 @@
|
|||
border-radius: 0;
|
||||
}
|
||||
|
||||
.nowPlayingInfoButtons .btnRewind {
|
||||
.nowPlayingInfoButtons .btnRepeat {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
margin-left: 0;
|
||||
|
@ -298,7 +370,7 @@
|
|||
font-size: smaller;
|
||||
}
|
||||
|
||||
.nowPlayingInfoButtons .btnFastForward {
|
||||
.nowPlayingInfoButtons .btnShuffleQueue {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
margin-right: 0;
|
||||
|
@ -342,250 +414,6 @@
|
|||
width: auto;
|
||||
}
|
||||
|
||||
#nowPlayingPage .playlistSection .playlist,
|
||||
#nowPlayingPage .playlistSection .contextMenu {
|
||||
position: absolute;
|
||||
top: 12.2em;
|
||||
bottom: 4.2em;
|
||||
overflow: scroll;
|
||||
padding: 0 1em;
|
||||
display: inline-block;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.playlistSectionButton {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
height: 4.2em;
|
||||
right: 0;
|
||||
padding-left: 7.3%;
|
||||
padding-right: 7.3%;
|
||||
}
|
||||
|
||||
.playlistSectionButton .btnTogglePlaylist {
|
||||
font-size: larger;
|
||||
margin: 0;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.playlistSectionButton .btnSavePlaylist {
|
||||
margin: 0;
|
||||
padding-right: 0;
|
||||
-webkit-box-flex: 1;
|
||||
-webkit-flex-grow: 1;
|
||||
flex-grow: 1;
|
||||
-webkit-box-pack: end;
|
||||
-webkit-justify-content: flex-end;
|
||||
justify-content: flex-end;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.playlistSectionButton .btnToggleContextMenu {
|
||||
font-size: larger;
|
||||
margin: 0;
|
||||
padding-right: 0;
|
||||
-webkit-box-flex: 1;
|
||||
-webkit-flex-grow: 1;
|
||||
flex-grow: 1;
|
||||
-webkit-box-pack: end;
|
||||
-webkit-justify-content: flex-end;
|
||||
justify-content: flex-end;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.playlistSectionButton .volumecontrol {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.remoteControlSection {
|
||||
margin: 0;
|
||||
padding: 0 0 4.2em 0;
|
||||
}
|
||||
|
||||
.nowPlayingButtonsContainer {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
|
||||
@media all and (orientation: landscape) and (max-width: 63em) {
|
||||
.remoteControlContent {
|
||||
padding-left: 4.3% !important;
|
||||
padding-right: 4.3% !important;
|
||||
display: flex;
|
||||
height: 100%;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.nowPlayingInfoContainer {
|
||||
-webkit-box-orient: horizontal !important;
|
||||
-webkit-box-direction: normal !important;
|
||||
-webkit-flex-direction: row !important;
|
||||
flex-direction: row !important;
|
||||
-webkit-box-align: center;
|
||||
-webkit-align-items: center;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
height: calc(100% - 4.2em);
|
||||
}
|
||||
|
||||
.nowPlayingPageTitle {
|
||||
/* text-align: center; */
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.nowPlayingInfoContainerMedia {
|
||||
text-align: left !important;
|
||||
width: 80%;
|
||||
}
|
||||
|
||||
.nowPlayingPositionSliderContainer {
|
||||
margin: 0.2em 1em 0.2em 1em;
|
||||
}
|
||||
|
||||
.nowPlayingInfoButtons {
|
||||
/* margin: 1.5em 0 0 0; */
|
||||
-webkit-box-pack: center;
|
||||
-webkit-justify-content: center;
|
||||
justify-content: center;
|
||||
font-size: x-large;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.nowPlayingPageImageContainer {
|
||||
width: 30%;
|
||||
margin: auto 1em auto auto;
|
||||
}
|
||||
|
||||
.nowPlayingPageImageContainerNoAlbum .cardImageContainer .cardImageIcon {
|
||||
font-size: 12em;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.nowPlayingInfoControls {
|
||||
margin: 0.5em 0 1em 0;
|
||||
width: 100%;
|
||||
-webkit-box-pack: start !important;
|
||||
-webkit-justify-content: start !important;
|
||||
justify-content: start !important;
|
||||
}
|
||||
|
||||
.nowPlayingSecondaryButtons {
|
||||
-webkit-box-flex: 1;
|
||||
-webkit-flex-grow: 1;
|
||||
flex-grow: 1;
|
||||
-webkit-box-pack: center;
|
||||
-webkit-justify-content: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.nowPlayingInfoControls .nowPlayingPageUserDataButtonsTitle {
|
||||
width: 20%;
|
||||
font-size: large;
|
||||
}
|
||||
|
||||
.nowPlayingInfoControls .nowPlayingPageUserDataButtonsTitle button {
|
||||
padding-top: 0;
|
||||
padding-right: 0;
|
||||
margin-right: 0;
|
||||
float: right;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.paper-icon-button-light:hover {
|
||||
color: #fff !important;
|
||||
background-color: transparent !important;
|
||||
}
|
||||
|
||||
.btnPlayPause {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
font-size: 1.7em;
|
||||
}
|
||||
|
||||
.btnPlayPause:hover {
|
||||
background-color: transparent !important;
|
||||
}
|
||||
|
||||
.nowPlayingPageImage {
|
||||
/* width: inherit; */
|
||||
overflow-y: hidden;
|
||||
overflow: hidden;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.nowPlayingPageImage.nowPlayingPageImageAudio {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.nowPlayingPageImageContainer.nowPlayingPageImagePoster {
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.nowPlayingPageImageContainer.nowPlayingPageImagePoster img {
|
||||
height: 100%;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
#nowPlayingPage .playlistSection .playlist,
|
||||
#nowPlayingPage .playlistSection .contextMenu {
|
||||
position: absolute;
|
||||
top: 7.2em;
|
||||
bottom: 4.2em;
|
||||
overflow: scroll;
|
||||
padding: 0 1em;
|
||||
display: inline-block;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.playlistSectionButton {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
height: 4.2em;
|
||||
right: 0;
|
||||
padding-left: 4.3%;
|
||||
padding-right: 4.3%;
|
||||
}
|
||||
|
||||
.playlistSectionButton .btnTogglePlaylist {
|
||||
font-size: larger;
|
||||
margin: 0;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.playlistSectionButton .btnSavePlaylist {
|
||||
margin: 0;
|
||||
padding-right: 0;
|
||||
-webkit-box-flex: 1;
|
||||
-webkit-flex-grow: 1;
|
||||
flex-grow: 1;
|
||||
-webkit-box-pack: end;
|
||||
-webkit-justify-content: flex-end;
|
||||
justify-content: flex-end;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.playlistSectionButton .btnToggleContextMenu {
|
||||
font-size: larger;
|
||||
margin: 0;
|
||||
padding-right: 0;
|
||||
-webkit-box-flex: 1;
|
||||
-webkit-flex-grow: 1;
|
||||
flex-grow: 1;
|
||||
-webkit-box-pack: end;
|
||||
-webkit-justify-content: flex-end;
|
||||
justify-content: flex-end;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.playlistSectionButton .volumecontrol {
|
||||
width: 100%;
|
||||
}
|
||||
|
@ -627,6 +455,10 @@
|
|||
background-image: url(../../assets/img/equalizer.gif) !important;
|
||||
}
|
||||
|
||||
.playlistIndexIndicatorImage > * {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.hideVideoButtons .videoButton {
|
||||
display: none;
|
||||
}
|
||||
|
@ -636,7 +468,6 @@
|
|||
}
|
||||
|
||||
@media all and (max-width: 63em) {
|
||||
.nowPlayingSecondaryButtons .nowPlayingPageUserDataButtons,
|
||||
.nowPlayingSecondaryButtons .repeatToggleButton,
|
||||
.nowPlayingInfoButtons .playlist .listItemMediaInfo,
|
||||
.nowPlayingInfoButtons .btnStop {
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
define(['browser', 'datetime', 'backdrop', 'libraryBrowser', 'listView', 'imageLoader', 'playbackManager', 'nowPlayingHelper', 'events', 'connectionManager', 'apphost', 'globalize', 'layoutManager', 'userSettings', 'cardBuilder', 'cardStyle', 'emby-itemscontainer', 'css!./remotecontrol.css', 'emby-ratingbutton'], function (browser, datetime, backdrop, libraryBrowser, listView, imageLoader, playbackManager, nowPlayingHelper, events, connectionManager, appHost, globalize, layoutManager, userSettings, cardBuilder) {
|
||||
define(['browser', 'datetime', 'backdrop', 'libraryBrowser', 'listView', 'imageLoader', 'playbackManager', 'nowPlayingHelper', 'events', 'connectionManager', 'apphost', 'globalize', 'layoutManager', 'userSettings', 'cardBuilder', 'itemContextMenu', 'cardStyle', 'emby-itemscontainer', 'css!./remotecontrol.css', 'emby-ratingbutton'], function (browser, datetime, backdrop, libraryBrowser, listView, imageLoader, playbackManager, nowPlayingHelper, events, connectionManager, appHost, globalize, layoutManager, userSettings, cardBuilder, itemContextMenu) {
|
||||
'use strict';
|
||||
var showMuteButton = true;
|
||||
var showVolumeSlider = true;
|
||||
|
||||
function showAudioMenu(context, player, button, item) {
|
||||
var currentIndex = playbackManager.getAudioStreamIndex(player);
|
||||
|
@ -118,30 +120,41 @@ define(['browser', 'datetime', 'backdrop', 'libraryBrowser', 'listView', 'imageL
|
|||
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 artistName;
|
||||
if (item.ArtistItems != null) {
|
||||
artistName = item.ArtistItems[0].Name;
|
||||
context.querySelector('.nowPlayingAlbum').innerHTML = '<a class="button-link emby-button" is="emby-linkbutton" href="itemdetails.html?id=' + item.AlbumId + `&serverId=${nowPlayingServerId}">${albumName}</a>`;
|
||||
context.querySelector('.nowPlayingArtist').innerHTML = '<a class="button-link emby-button" is="emby-linkbutton" href="itemdetails.html?id=' + item.ArtistItems[0].Id + `&serverId=${nowPlayingServerId}">${artistName}</a>`;
|
||||
context.querySelector('.contextMenuAlbum').innerHTML = '<a class="button-link emby-button" is="emby-linkbutton" href="itemdetails.html?id=' + item.AlbumId + `&serverId=${nowPlayingServerId}"><span class="actionsheetMenuItemIcon listItemIcon listItemIcon-transparent material-icons album"></span> ` + globalize.translate('ViewAlbum') + '</a>';
|
||||
context.querySelector('.contextMenuArtist').innerHTML = '<a class="button-link emby-button" is="emby-linkbutton" href="itemdetails.html?id=' + item.ArtistItems[0].Id + `&serverId=${nowPlayingServerId}"><span class="actionsheetMenuItemIcon listItemIcon listItemIcon-transparent material-icons person"></span> ` + globalize.translate('ViewArtist') + '</a>';
|
||||
} else {
|
||||
artistName = item.Artists;
|
||||
context.querySelector('.nowPlayingAlbum').innerHTML = albumName;
|
||||
context.querySelector('.nowPlayingArtist').innerHTML = artistName;
|
||||
for (const artist of item.ArtistItems) {
|
||||
let artistName = artist.Name;
|
||||
let artistId = artist.Id;
|
||||
artistsSeries += `<a class="button-link emby-button" is="emby-linkbutton" href="details?id=${artistId}&serverId=${nowPlayingServerId}">${artistName}</a>`;
|
||||
if (artist !== item.ArtistItems.slice(-1)[0]) {
|
||||
artistsSeries += ', ';
|
||||
}
|
||||
}
|
||||
} else if (item.Artists) {
|
||||
// For some reason, Chromecast Player doesn't return a item.ArtistItems object, so we need to fallback
|
||||
// to normal item.Artists item.
|
||||
// TODO: Normalise fields returned by all the players
|
||||
for (const artist of item.Artists) {
|
||||
artistsSeries += `<a>${artist}</a>`;
|
||||
if (artist !== item.Artists.slice(-1)[0]) {
|
||||
artistsSeries += ', ';
|
||||
}
|
||||
}
|
||||
}
|
||||
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>`;
|
||||
}
|
||||
context.querySelector('.nowPlayingSongName').innerHTML = songName;
|
||||
} else if (item.Type == 'Episode') {
|
||||
if (item.SeasonName != null) {
|
||||
var seasonName = item.SeasonName;
|
||||
context.querySelector('.nowPlayingSeason').innerHTML = '<a class="button-link emby-button" is="emby-linkbutton" href="itemdetails.html?id=' + item.SeasonId + `&serverId=${nowPlayingServerId}">${seasonName}</a>`;
|
||||
context.querySelector('.nowPlayingSeason').innerHTML = '<a class="button-link emby-button" is="emby-linkbutton" href="details?id=' + item.SeasonId + `&serverId=${nowPlayingServerId}">${seasonName}</a>`;
|
||||
}
|
||||
if (item.SeriesName != null) {
|
||||
var seriesName = item.SeriesName;
|
||||
if (item.SeriesId != null) {
|
||||
context.querySelector('.nowPlayingSerie').innerHTML = '<a class="button-link emby-button" is="emby-linkbutton" href="itemdetails.html?id=' + item.SeriesId + `&serverId=${nowPlayingServerId}">${seriesName}</a>`;
|
||||
context.querySelector('.nowPlayingSerie').innerHTML = '<a class="button-link emby-button" is="emby-linkbutton" href="details?id=' + item.SeriesId + `&serverId=${nowPlayingServerId}">${seriesName}</a>`;
|
||||
} else {
|
||||
context.querySelector('.nowPlayingSerie').innerHTML = seriesName;
|
||||
}
|
||||
|
@ -163,11 +176,38 @@ define(['browser', 'datetime', 'backdrop', 'libraryBrowser', 'listView', 'imageL
|
|||
maxHeight: 300 * 2
|
||||
}) : null;
|
||||
|
||||
console.debug('updateNowPlayingInfo');
|
||||
let contextButton = context.querySelector('.btnToggleContextMenu');
|
||||
// We remove the previous event listener by replacing the item in each update event
|
||||
const autoFocusContextButton = document.activeElement === contextButton;
|
||||
let contextButtonClone = contextButton.cloneNode(true);
|
||||
contextButton.parentNode.replaceChild(contextButtonClone, contextButton);
|
||||
contextButton = context.querySelector('.btnToggleContextMenu');
|
||||
if (autoFocusContextButton) {
|
||||
contextButton.focus();
|
||||
}
|
||||
const stopPlayback = !!layoutManager.mobile;
|
||||
var options = {
|
||||
play: false,
|
||||
queue: false,
|
||||
stopPlayback: stopPlayback,
|
||||
clearQueue: true,
|
||||
openAlbum: false,
|
||||
positionTo: contextButton
|
||||
};
|
||||
var apiClient = connectionManager.getApiClient(item.ServerId);
|
||||
apiClient.getItem(apiClient.getCurrentUserId(), item.Id).then(function (fullItem) {
|
||||
apiClient.getCurrentUser().then(function (user) {
|
||||
contextButton.addEventListener('click', function () {
|
||||
itemContextMenu.show(Object.assign({
|
||||
item: fullItem,
|
||||
user: user
|
||||
}, options));
|
||||
});
|
||||
});
|
||||
});
|
||||
setImageUrl(context, state, url);
|
||||
if (item) {
|
||||
backdrop.setBackdrops([item]);
|
||||
var apiClient = connectionManager.getApiClient(item.ServerId);
|
||||
apiClient.getItem(apiClient.getCurrentUserId(), item.Id).then(function (fullItem) {
|
||||
var userData = fullItem.UserData || {};
|
||||
var likes = null == userData.Likes ? '' : userData.Likes;
|
||||
|
@ -219,20 +259,16 @@ define(['browser', 'datetime', 'backdrop', 'libraryBrowser', 'listView', 'imageL
|
|||
|
||||
var currentImgUrl;
|
||||
return function () {
|
||||
function toggleRepeat(player) {
|
||||
if (player) {
|
||||
switch (playbackManager.getRepeatMode(player)) {
|
||||
case 'RepeatNone':
|
||||
playbackManager.setRepeatMode('RepeatAll', player);
|
||||
break;
|
||||
|
||||
case 'RepeatAll':
|
||||
playbackManager.setRepeatMode('RepeatOne', player);
|
||||
break;
|
||||
|
||||
case 'RepeatOne':
|
||||
playbackManager.setRepeatMode('RepeatNone', player);
|
||||
}
|
||||
function toggleRepeat() {
|
||||
switch (playbackManager.getRepeatMode()) {
|
||||
case 'RepeatAll':
|
||||
playbackManager.setRepeatMode('RepeatOne');
|
||||
break;
|
||||
case 'RepeatOne':
|
||||
playbackManager.setRepeatMode('RepeatNone');
|
||||
break;
|
||||
case 'RepeatNone':
|
||||
playbackManager.setRepeatMode('RepeatAll');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -275,8 +311,13 @@ define(['browser', 'datetime', 'backdrop', 'libraryBrowser', 'listView', 'imageL
|
|||
buttonVisible(context.querySelector('.btnStop'), null != item);
|
||||
buttonVisible(context.querySelector('.btnNextTrack'), null != item);
|
||||
buttonVisible(context.querySelector('.btnPreviousTrack'), null != item);
|
||||
buttonVisible(context.querySelector('.btnRewind'), null != item);
|
||||
buttonVisible(context.querySelector('.btnFastForward'), null != item);
|
||||
if (layoutManager.mobile) {
|
||||
buttonVisible(context.querySelector('.btnRewind'), false);
|
||||
buttonVisible(context.querySelector('.btnFastForward'), false);
|
||||
} else {
|
||||
buttonVisible(context.querySelector('.btnRewind'), null != item);
|
||||
buttonVisible(context.querySelector('.btnFastForward'), null != item);
|
||||
}
|
||||
var positionSlider = context.querySelector('.nowPlayingPositionSlider');
|
||||
|
||||
if (positionSlider && item && item.RunTimeTicks) {
|
||||
|
@ -300,7 +341,8 @@ define(['browser', 'datetime', 'backdrop', 'libraryBrowser', 'listView', 'imageL
|
|||
context.classList.add('hideVideoButtons');
|
||||
}
|
||||
|
||||
updateRepeatModeDisplay(playState.RepeatMode);
|
||||
updateRepeatModeDisplay(playbackManager.getRepeatMode());
|
||||
onShuffleQueueModeChange(false);
|
||||
updateNowPlayingInfo(context, state);
|
||||
}
|
||||
|
||||
|
@ -316,25 +358,32 @@ define(['browser', 'datetime', 'backdrop', 'libraryBrowser', 'listView', 'imageL
|
|||
|
||||
function updateRepeatModeDisplay(repeatMode) {
|
||||
var context = dlg;
|
||||
var toggleRepeatButton = context.querySelector('.repeatToggleButton');
|
||||
let toggleRepeatButtons = context.querySelectorAll('.repeatToggleButton');
|
||||
const cssClass = 'buttonActive';
|
||||
let innHtml = '<span class="material-icons repeat"></span>';
|
||||
let repeatOn = true;
|
||||
|
||||
if ('RepeatAll' == repeatMode) {
|
||||
toggleRepeatButton.innerHTML = "<span class='material-icons repeat'></span>";
|
||||
toggleRepeatButton.classList.add('repeatButton-active');
|
||||
} else if ('RepeatOne' == repeatMode) {
|
||||
toggleRepeatButton.innerHTML = "<span class='material-icons repeat_one'></span>";
|
||||
toggleRepeatButton.classList.add('repeatButton-active');
|
||||
} else {
|
||||
toggleRepeatButton.innerHTML = "<span class='material-icons repeat'></span>";
|
||||
toggleRepeatButton.classList.remove('repeatButton-active');
|
||||
switch (repeatMode) {
|
||||
case 'RepeatAll':
|
||||
break;
|
||||
case 'RepeatOne':
|
||||
innHtml = '<span class="material-icons repeat_one"></span>';
|
||||
break;
|
||||
case 'RepeatNone':
|
||||
default:
|
||||
repeatOn = false;
|
||||
break;
|
||||
}
|
||||
|
||||
for (const toggleRepeatButton of toggleRepeatButtons) {
|
||||
toggleRepeatButton.classList.toggle(cssClass, repeatOn);
|
||||
toggleRepeatButton.innerHTML = innHtml;
|
||||
}
|
||||
}
|
||||
|
||||
function updatePlayerVolumeState(context, isMuted, volumeLevel) {
|
||||
var view = context;
|
||||
var supportedCommands = currentPlayerSupportedCommands;
|
||||
var showMuteButton = true;
|
||||
var showVolumeSlider = true;
|
||||
|
||||
if (-1 === supportedCommands.indexOf('Mute')) {
|
||||
showMuteButton = false;
|
||||
|
@ -362,24 +411,21 @@ define(['browser', 'datetime', 'backdrop', 'libraryBrowser', 'listView', 'imageL
|
|||
buttonMuteIcon.classList.add('volume_up');
|
||||
}
|
||||
|
||||
if (showMuteButton) {
|
||||
buttonMute.classList.remove('hide');
|
||||
if (!showMuteButton && !showVolumeSlider) {
|
||||
context.querySelector('.volumecontrol').classList.add('hide');
|
||||
} else {
|
||||
buttonMute.classList.add('hide');
|
||||
}
|
||||
buttonMute.classList.toggle('hide', !showMuteButton);
|
||||
|
||||
var nowPlayingVolumeSlider = context.querySelector('.nowPlayingVolumeSlider');
|
||||
var nowPlayingVolumeSliderContainer = context.querySelector('.nowPlayingVolumeSliderContainer');
|
||||
var nowPlayingVolumeSlider = context.querySelector('.nowPlayingVolumeSlider');
|
||||
var nowPlayingVolumeSliderContainer = context.querySelector('.nowPlayingVolumeSliderContainer');
|
||||
|
||||
if (nowPlayingVolumeSlider) {
|
||||
if (showVolumeSlider) {
|
||||
nowPlayingVolumeSliderContainer.classList.remove('hide');
|
||||
} else {
|
||||
nowPlayingVolumeSliderContainer.classList.add('hide');
|
||||
}
|
||||
if (nowPlayingVolumeSlider) {
|
||||
|
||||
if (!nowPlayingVolumeSlider.dragging) {
|
||||
nowPlayingVolumeSlider.value = volumeLevel || 0;
|
||||
nowPlayingVolumeSliderContainer.classList.toggle('hide', !showVolumeSlider);
|
||||
|
||||
if (!nowPlayingVolumeSlider.dragging) {
|
||||
nowPlayingVolumeSlider.value = volumeLevel || 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -420,11 +466,21 @@ define(['browser', 'datetime', 'backdrop', 'libraryBrowser', 'listView', 'imageL
|
|||
function loadPlaylist(context, player) {
|
||||
getPlaylistItems(player).then(function (items) {
|
||||
var html = '';
|
||||
let favoritesEnabled = true;
|
||||
if (layoutManager.mobile) {
|
||||
if (items.length > 0) {
|
||||
context.querySelector('.btnTogglePlaylist').classList.remove('hide');
|
||||
} else {
|
||||
context.querySelector('.btnTogglePlaylist').classList.add('hide');
|
||||
}
|
||||
favoritesEnabled = false;
|
||||
}
|
||||
|
||||
html += listView.getListViewHtml({
|
||||
items: items,
|
||||
smallIcon: true,
|
||||
action: 'setplaylistindex',
|
||||
enableUserDataButtons: false,
|
||||
enableUserDataButtons: favoritesEnabled,
|
||||
rightButtons: [{
|
||||
icon: 'remove_circle_outline',
|
||||
title: globalize.translate('ButtonRemove'),
|
||||
|
@ -433,18 +489,21 @@ define(['browser', 'datetime', 'backdrop', 'libraryBrowser', 'listView', 'imageL
|
|||
dragHandle: true
|
||||
});
|
||||
|
||||
if (items.length) {
|
||||
context.querySelector('.btnTogglePlaylist').classList.remove('hide');
|
||||
} else {
|
||||
context.querySelector('.btnTogglePlaylist').classList.add('hide');
|
||||
var itemsContainer = context.querySelector('.playlist');
|
||||
let focusedItemPlaylistId = itemsContainer.querySelector('button:focus');
|
||||
itemsContainer.innerHTML = html;
|
||||
if (focusedItemPlaylistId !== null) {
|
||||
focusedItemPlaylistId = focusedItemPlaylistId.getAttribute('data-playlistitemid');
|
||||
const newFocusedItem = itemsContainer.querySelector(`button[data-playlistitemid="${focusedItemPlaylistId}"]`);
|
||||
if (newFocusedItem !== null) {
|
||||
newFocusedItem.focus();
|
||||
}
|
||||
}
|
||||
|
||||
var itemsContainer = context.querySelector('.playlist');
|
||||
itemsContainer.innerHTML = html;
|
||||
var playlistItemId = playbackManager.getCurrentPlaylistItemId(player);
|
||||
|
||||
if (playlistItemId) {
|
||||
var img = itemsContainer.querySelector('.listItem[data-playlistItemId="' + playlistItemId + '"] .listItemImage');
|
||||
var img = itemsContainer.querySelector(`.listItem[data-playlistItemId="${playlistItemId}"] .listItemImage`);
|
||||
|
||||
if (img) {
|
||||
img.classList.remove('lazy');
|
||||
|
@ -453,9 +512,6 @@ define(['browser', 'datetime', 'backdrop', 'libraryBrowser', 'listView', 'imageL
|
|||
}
|
||||
|
||||
imageLoader.lazyChildren(itemsContainer);
|
||||
context.querySelector('.playlist').classList.add('hide');
|
||||
context.querySelector('.contextMenu').classList.add('hide');
|
||||
context.querySelector('.btnSavePlaylist').classList.add('hide');
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -465,9 +521,31 @@ define(['browser', 'datetime', 'backdrop', 'libraryBrowser', 'listView', 'imageL
|
|||
onStateChanged.call(player, e, state);
|
||||
}
|
||||
|
||||
function onRepeatModeChange(e) {
|
||||
var player = this;
|
||||
updateRepeatModeDisplay(playbackManager.getRepeatMode(player));
|
||||
function onRepeatModeChange() {
|
||||
updateRepeatModeDisplay(playbackManager.getRepeatMode());
|
||||
}
|
||||
|
||||
function onShuffleQueueModeChange(updateView = true) {
|
||||
let shuffleMode = playbackManager.getQueueShuffleMode(this);
|
||||
let context = dlg;
|
||||
const cssClass = 'buttonActive';
|
||||
let shuffleButtons = context.querySelectorAll('.btnShuffleQueue');
|
||||
|
||||
for (let shuffleButton of shuffleButtons) {
|
||||
switch (shuffleMode) {
|
||||
case 'Shuffle':
|
||||
shuffleButton.classList.add(cssClass);
|
||||
break;
|
||||
case 'Sorted':
|
||||
default:
|
||||
shuffleButton.classList.remove(cssClass);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (updateView) {
|
||||
onPlaylistUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
function onPlaylistUpdate(e) {
|
||||
|
@ -476,14 +554,18 @@ define(['browser', 'datetime', 'backdrop', 'libraryBrowser', 'listView', 'imageL
|
|||
|
||||
function onPlaylistItemRemoved(e, info) {
|
||||
var context = dlg;
|
||||
var playlistItemIds = info.playlistItemIds;
|
||||
if (info !== undefined) {
|
||||
var playlistItemIds = info.playlistItemIds;
|
||||
|
||||
for (var i = 0, length = playlistItemIds.length; i < length; i++) {
|
||||
var listItem = context.querySelector('.listItem[data-playlistItemId="' + playlistItemIds[i] + '"]');
|
||||
for (var i = 0, length = playlistItemIds.length; i < length; i++) {
|
||||
var listItem = context.querySelector('.listItem[data-playlistItemId="' + playlistItemIds[i] + '"]');
|
||||
|
||||
if (listItem) {
|
||||
listItem.parentNode.removeChild(listItem);
|
||||
if (listItem) {
|
||||
listItem.parentNode.removeChild(listItem);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
onPlaylistUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -493,7 +575,6 @@ define(['browser', 'datetime', 'backdrop', 'libraryBrowser', 'listView', 'imageL
|
|||
|
||||
if (!state.NextMediaType) {
|
||||
updatePlayerState(player, dlg, {});
|
||||
loadPlaylist(dlg);
|
||||
Emby.Page.back();
|
||||
}
|
||||
}
|
||||
|
@ -505,7 +586,7 @@ define(['browser', 'datetime', 'backdrop', 'libraryBrowser', 'listView', 'imageL
|
|||
function onStateChanged(event, state) {
|
||||
var player = this;
|
||||
updatePlayerState(player, dlg, state);
|
||||
loadPlaylist(dlg, player);
|
||||
onPlaylistUpdate();
|
||||
}
|
||||
|
||||
function onTimeUpdate(e) {
|
||||
|
@ -531,8 +612,10 @@ define(['browser', 'datetime', 'backdrop', 'libraryBrowser', 'listView', 'imageL
|
|||
events.off(player, 'playbackstart', onPlaybackStart);
|
||||
events.off(player, 'statechange', onStateChanged);
|
||||
events.off(player, 'repeatmodechange', onRepeatModeChange);
|
||||
events.off(player, 'playlistitemremove', onPlaylistUpdate);
|
||||
events.off(player, 'shufflequeuemodechange', onShuffleQueueModeChange);
|
||||
events.off(player, 'playlistitemremove', onPlaylistItemRemoved);
|
||||
events.off(player, 'playlistitemmove', onPlaylistUpdate);
|
||||
events.off(player, 'playlistitemadd', onPlaylistUpdate);
|
||||
events.off(player, 'playbackstop', onPlaybackStopped);
|
||||
events.off(player, 'volumechange', onVolumeChanged);
|
||||
events.off(player, 'pause', onPlayPauseStateChanged);
|
||||
|
@ -551,8 +634,10 @@ define(['browser', 'datetime', 'backdrop', 'libraryBrowser', 'listView', 'imageL
|
|||
events.on(player, 'playbackstart', onPlaybackStart);
|
||||
events.on(player, 'statechange', onStateChanged);
|
||||
events.on(player, 'repeatmodechange', onRepeatModeChange);
|
||||
events.on(player, 'shufflequeuemodechange', onShuffleQueueModeChange);
|
||||
events.on(player, 'playlistitemremove', onPlaylistItemRemoved);
|
||||
events.on(player, 'playlistitemmove', onPlaylistUpdate);
|
||||
events.on(player, 'playlistitemadd', onPlaylistUpdate);
|
||||
events.on(player, 'playbackstop', onPlaybackStopped);
|
||||
events.on(player, 'volumechange', onVolumeChanged);
|
||||
events.on(player, 'pause', onPlayPauseStateChanged);
|
||||
|
@ -568,7 +653,7 @@ define(['browser', 'datetime', 'backdrop', 'libraryBrowser', 'listView', 'imageL
|
|||
function onBtnCommandClick() {
|
||||
if (currentPlayer) {
|
||||
if (this.classList.contains('repeatToggleButton')) {
|
||||
toggleRepeat(currentPlayer);
|
||||
toggleRepeat();
|
||||
} else {
|
||||
playbackManager.sendCommand({
|
||||
Name: this.getAttribute('data-command')
|
||||
|
@ -603,6 +688,7 @@ define(['browser', 'datetime', 'backdrop', 'libraryBrowser', 'listView', 'imageL
|
|||
|
||||
function bindEvents(context) {
|
||||
var btnCommand = context.querySelectorAll('.btnCommand');
|
||||
var positionSlider = context.querySelector('.nowPlayingPositionSlider');
|
||||
|
||||
for (var i = 0, length = btnCommand.length; i < length; i++) {
|
||||
btnCommand[i].addEventListener('click', onBtnCommandClick);
|
||||
|
@ -650,12 +736,37 @@ define(['browser', 'datetime', 'backdrop', 'libraryBrowser', 'listView', 'imageL
|
|||
playbackManager.fastForward(currentPlayer);
|
||||
}
|
||||
});
|
||||
context.querySelector('.btnPreviousTrack').addEventListener('click', function () {
|
||||
for (const shuffleButton of context.querySelectorAll('.btnShuffleQueue')) {
|
||||
shuffleButton.addEventListener('click', function () {
|
||||
if (currentPlayer) {
|
||||
playbackManager.toggleQueueShuffleMode(currentPlayer);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
context.querySelector('.btnPreviousTrack').addEventListener('click', function (e) {
|
||||
if (currentPlayer) {
|
||||
if (lastPlayerState.NowPlayingItem.MediaType === 'Audio' && (currentPlayer._currentTime >= 5 || !playbackManager.previousTrack(currentPlayer))) {
|
||||
// Cancel this event if doubleclick is fired
|
||||
if (e.detail > 1 && playbackManager.previousTrack(currentPlayer)) {
|
||||
return;
|
||||
}
|
||||
playbackManager.seekPercent(0, currentPlayer);
|
||||
// This is done automatically by playbackManager. However, setting this here gives instant visual feedback.
|
||||
// TODO: Check why seekPercentage doesn't reflect the changes inmmediately, so we can remove this workaround.
|
||||
positionSlider.value = 0;
|
||||
} else {
|
||||
playbackManager.previousTrack(currentPlayer);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
context.querySelector('.btnPreviousTrack').addEventListener('dblclick', function () {
|
||||
if (currentPlayer) {
|
||||
playbackManager.previousTrack(currentPlayer);
|
||||
}
|
||||
});
|
||||
context.querySelector('.nowPlayingPositionSlider').addEventListener('change', function () {
|
||||
positionSlider.addEventListener('change', function () {
|
||||
var value = this.value;
|
||||
|
||||
if (currentPlayer) {
|
||||
|
@ -664,7 +775,7 @@ define(['browser', 'datetime', 'backdrop', 'libraryBrowser', 'listView', 'imageL
|
|||
}
|
||||
});
|
||||
|
||||
context.querySelector('.nowPlayingPositionSlider').getBubbleText = function (value) {
|
||||
positionSlider.getBubbleText = function (value) {
|
||||
var state = lastPlayerState;
|
||||
|
||||
if (!state || !state.NowPlayingItem || !currentRuntimeTicks) {
|
||||
|
@ -677,13 +788,10 @@ define(['browser', 'datetime', 'backdrop', 'libraryBrowser', 'listView', 'imageL
|
|||
return datetime.getDisplayRunningTime(ticks);
|
||||
};
|
||||
|
||||
function setVolume() {
|
||||
playbackManager.setVolume(this.value, currentPlayer);
|
||||
}
|
||||
context.querySelector('.nowPlayingVolumeSlider').addEventListener('input', (e) => {
|
||||
playbackManager.setVolume(e.target.value, currentPlayer);
|
||||
});
|
||||
|
||||
context.querySelector('.nowPlayingVolumeSlider').addEventListener('change', setVolume);
|
||||
context.querySelector('.nowPlayingVolumeSlider').addEventListener('mousemove', setVolume);
|
||||
context.querySelector('.nowPlayingVolumeSlider').addEventListener('touchmove', setVolume);
|
||||
context.querySelector('.buttonMute').addEventListener('click', function () {
|
||||
playbackManager.toggleMute(currentPlayer);
|
||||
});
|
||||
|
@ -701,21 +809,19 @@ define(['browser', 'datetime', 'backdrop', 'libraryBrowser', 'listView', 'imageL
|
|||
if (context.querySelector('.playlist').classList.contains('hide')) {
|
||||
context.querySelector('.playlist').classList.remove('hide');
|
||||
context.querySelector('.btnSavePlaylist').classList.remove('hide');
|
||||
context.querySelector('.contextMenu').classList.add('hide');
|
||||
context.querySelector('.volumecontrol').classList.add('hide');
|
||||
if (layoutManager.mobile) {
|
||||
context.querySelector('.playlistSectionButton').classList.remove('playlistSectionButtonTransparent');
|
||||
}
|
||||
} else {
|
||||
context.querySelector('.playlist').classList.add('hide');
|
||||
context.querySelector('.btnSavePlaylist').classList.add('hide');
|
||||
context.querySelector('.volumecontrol').classList.remove('hide');
|
||||
}
|
||||
});
|
||||
context.querySelector('.btnToggleContextMenu').addEventListener('click', function () {
|
||||
if (context.querySelector('.contextMenu').classList.contains('hide')) {
|
||||
context.querySelector('.contextMenu').classList.remove('hide');
|
||||
context.querySelector('.btnSavePlaylist').classList.add('hide');
|
||||
context.querySelector('.playlist').classList.add('hide');
|
||||
} else {
|
||||
context.querySelector('.contextMenu').classList.add('hide');
|
||||
if (showMuteButton || showVolumeSlider) {
|
||||
context.querySelector('.volumecontrol').classList.remove('hide');
|
||||
}
|
||||
if (layoutManager.mobile) {
|
||||
context.querySelector('.playlistSectionButton').classList.add('playlistSectionButtonTransparent');
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -764,16 +870,24 @@ define(['browser', 'datetime', 'backdrop', 'libraryBrowser', 'listView', 'imageL
|
|||
}
|
||||
|
||||
function init(ownerView, context) {
|
||||
let contextmenuHtml = `<button id="toggleContextMenu" is="paper-icon-button-light" class="btnToggleContextMenu" title=${globalize.translate('ButtonToggleContextMenu')}><span class="material-icons more_vert"></span></button>`;
|
||||
let volumecontrolHtml = '<div class="volumecontrol flex align-items-center flex-wrap-wrap justify-content-center">';
|
||||
volumecontrolHtml += `<button is="paper-icon-button-light" class="buttonMute autoSize" title=${globalize.translate('Mute')}><span class="xlargePaperIconButton material-icons volume_up"></span></button>`;
|
||||
volumecontrolHtml += '<div class="sliderContainer nowPlayingVolumeSliderContainer"><input is="emby-slider" type="range" step="1" min="0" max="100" value="0" class="nowPlayingVolumeSlider"/></div>';
|
||||
volumecontrolHtml += '</div>';
|
||||
let optionsSection = context.querySelector('.playlistSectionButton');
|
||||
if (!layoutManager.mobile) {
|
||||
context.querySelector('.nowPlayingSecondaryButtons').innerHTML += volumecontrolHtml;
|
||||
context.querySelector('.playlistSectionButton').innerHTML += contextmenuHtml;
|
||||
context.querySelector('.nowPlayingSecondaryButtons').insertAdjacentHTML('beforeend', volumecontrolHtml);
|
||||
optionsSection.classList.remove('align-items-center', 'justify-content-center');
|
||||
optionsSection.classList.add('align-items-right', 'justify-content-flex-end');
|
||||
context.querySelector('.playlist').classList.remove('hide');
|
||||
context.querySelector('.btnSavePlaylist').classList.remove('hide');
|
||||
context.classList.add('padded-bottom');
|
||||
} else {
|
||||
context.querySelector('.playlistSectionButton').innerHTML += volumecontrolHtml + contextmenuHtml;
|
||||
optionsSection.querySelector('.btnTogglePlaylist').insertAdjacentHTML('afterend', volumecontrolHtml);
|
||||
optionsSection.classList.add('playlistSectionButtonTransparent');
|
||||
context.querySelector('.btnTogglePlaylist').classList.remove('hide');
|
||||
context.querySelector('.playlistSectionButton').classList.remove('justify-content-center');
|
||||
context.querySelector('.playlistSectionButton').classList.add('justify-content-space-between');
|
||||
}
|
||||
|
||||
bindEvents(context);
|
||||
|
|
|
@ -474,7 +474,7 @@ import 'emby-button';
|
|||
showTitle: true,
|
||||
overlayText: false,
|
||||
centerText: true,
|
||||
action: 'play'
|
||||
overlayPlayButton: true
|
||||
|
||||
});
|
||||
|
||||
|
|
|
@ -224,6 +224,7 @@ define(['dialogHelper', 'inputManager', 'connectionManager', 'layoutManager', 'f
|
|||
});
|
||||
|
||||
inputManager.on(window, onInputCommand);
|
||||
/* eslint-disable-next-line compat/compat */
|
||||
document.addEventListener((window.PointerEvent ? 'pointermove' : 'mousemove'), onPointerMove);
|
||||
|
||||
dialog.addEventListener('close', onDialogClosed);
|
||||
|
@ -489,6 +490,7 @@ define(['dialogHelper', 'inputManager', 'connectionManager', 'layoutManager', 'f
|
|||
}
|
||||
|
||||
inputManager.off(window, onInputCommand);
|
||||
/* eslint-disable-next-line compat/compat */
|
||||
document.removeEventListener((window.PointerEvent ? 'pointermove' : 'mousemove'), onPointerMove);
|
||||
// Shows page scrollbar
|
||||
document.body.classList.remove('hide-scroll');
|
||||
|
|
|
@ -1,12 +1,18 @@
|
|||
.subtitleSync {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.subtitleSyncContainer {
|
||||
width: 40%;
|
||||
margin-left: 30%;
|
||||
margin-right: 30%;
|
||||
min-width: 18em;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
height: 4.2em;
|
||||
background: rgba(28, 28, 28, 0.8);
|
||||
border-radius: 0.3em;
|
||||
color: #fff;
|
||||
position: absolute;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.subtitleSync-closeButton {
|
||||
|
|
|
@ -65,6 +65,9 @@ define(['playbackManager', 'layoutManager', 'text!./subtitlesync.template.html',
|
|||
event.preventDefault();
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: TV layout will require special handling for navigation keys. But now field is not focusable
|
||||
event.stopPropagation();
|
||||
});
|
||||
|
||||
subtitleSyncTextField.blur = function() {
|
||||
|
@ -87,14 +90,6 @@ define(['playbackManager', 'layoutManager', 'text!./subtitlesync.template.html',
|
|||
getOffsetFromPercentage(this.value));
|
||||
});
|
||||
|
||||
subtitleSyncSlider.addEventListener('touchmove', function () {
|
||||
// set new offset
|
||||
playbackManager.setSubtitleOffset(getOffsetFromPercentage(this.value), player);
|
||||
// synchronize with textField value
|
||||
subtitleSyncTextField.updateOffset(
|
||||
getOffsetFromPercentage(this.value));
|
||||
});
|
||||
|
||||
subtitleSyncSlider.getBubbleHtml = function (value) {
|
||||
var newOffset = getOffsetFromPercentage(value);
|
||||
return '<h1 class="sliderBubbleText">' +
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
<div class="subtitleSyncContainer">
|
||||
<button type="button" is="paper-icon-button-light" class="subtitleSync-closeButton"><span class="material-icons close"></span></button>
|
||||
<div class="subtitleSyncTextField" contenteditable="true" spellcheck="false">0s</div>
|
||||
<div class="sliderContainer subtitleSyncSliderContainer">
|
||||
<input is="emby-slider" type="range" step="1" min="0" max="100" value="50" class="subtitleSyncSlider" />
|
||||
<div class="subtitleSync">
|
||||
<div class="subtitleSyncContainer">
|
||||
<button type="button" is="paper-icon-button-light" class="subtitleSync-closeButton"><span class="material-icons close"></span></button>
|
||||
<div class="subtitleSyncTextField" contenteditable="true" spellcheck="false">0s</div>
|
||||
<div class="sliderContainer subtitleSyncSliderContainer">
|
||||
<input is="emby-slider" type="range" step="1" min="0" max="100" value="50" class="subtitleSyncSlider" data-slider-keep-progress="true" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -37,7 +37,7 @@ function showNewJoinGroupSelection (button, user, apiClient) {
|
|||
console.debug('No item is currently playing.');
|
||||
}
|
||||
|
||||
apiClient.sendSyncPlayCommand(sessionId, 'ListGroups').then(function (response) {
|
||||
apiClient.getSyncPlayGroups().then(function (response) {
|
||||
response.json().then(function (groups) {
|
||||
var menuItems = groups.map(function (group) {
|
||||
return {
|
||||
|
@ -83,9 +83,9 @@ function showNewJoinGroupSelection (button, user, apiClient) {
|
|||
|
||||
actionsheet.show(menuOptions).then(function (id) {
|
||||
if (id == 'new-group') {
|
||||
apiClient.sendSyncPlayCommand(sessionId, 'NewGroup');
|
||||
} else {
|
||||
apiClient.sendSyncPlayCommand(sessionId, 'JoinGroup', {
|
||||
apiClient.createSyncPlayGroup();
|
||||
} else if (id) {
|
||||
apiClient.joinSyncPlayGroup({
|
||||
GroupId: id,
|
||||
PlayingItemId: playingItemId
|
||||
});
|
||||
|
@ -140,7 +140,7 @@ function showLeaveGroupSelection (button, user, apiClient) {
|
|||
|
||||
actionsheet.show(menuOptions).then(function (id) {
|
||||
if (id == 'leave-group') {
|
||||
apiClient.sendSyncPlayCommand(sessionId, 'LeaveGroup');
|
||||
apiClient.leaveSyncPlayGroup();
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.error('SyncPlay: unexpected error showing group menu:', error);
|
||||
|
|
|
@ -139,7 +139,7 @@ class SyncPlayManager {
|
|||
return;
|
||||
}
|
||||
|
||||
apiClient.sendSyncPlayCommand(sessionId, 'UpdatePing', {
|
||||
apiClient.sendSyncPlayPing({
|
||||
Ping: ping
|
||||
});
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -447,7 +450,7 @@ class SyncPlayManager {
|
|||
if (!success) {
|
||||
console.warning('Error reporting playback state to server. Joining group will fail.');
|
||||
}
|
||||
apiClient.sendSyncPlayCommand(sessionId, 'JoinGroup', {
|
||||
apiClient.joinSyncPlayGroup({
|
||||
GroupId: groupId,
|
||||
PlayingItemId: playingItemId
|
||||
});
|
||||
|
@ -619,6 +622,7 @@ class SyncPlayManager {
|
|||
if (this.currentPlayer) {
|
||||
this.currentPlayer.setPlaybackRate(1);
|
||||
}
|
||||
|
||||
this.clearSyncIcon();
|
||||
}
|
||||
|
||||
|
@ -658,8 +662,7 @@ class SyncPlayManager {
|
|||
*/
|
||||
playRequest (player) {
|
||||
var apiClient = connectionManager.currentApiClient();
|
||||
var sessionId = getActivePlayerId();
|
||||
apiClient.sendSyncPlayCommand(sessionId, 'PlayRequest');
|
||||
apiClient.requestSyncPlayStart();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -667,8 +670,7 @@ class SyncPlayManager {
|
|||
*/
|
||||
pauseRequest (player) {
|
||||
var apiClient = connectionManager.currentApiClient();
|
||||
var sessionId = getActivePlayerId();
|
||||
apiClient.sendSyncPlayCommand(sessionId, 'PauseRequest');
|
||||
apiClient.requestSyncPlayPause();
|
||||
// Pause locally as well, to give the user some little control
|
||||
playbackManager._localUnpause(player);
|
||||
}
|
||||
|
@ -678,8 +680,7 @@ class SyncPlayManager {
|
|||
*/
|
||||
seekRequest (PositionTicks, player) {
|
||||
var apiClient = connectionManager.currentApiClient();
|
||||
var sessionId = getActivePlayerId();
|
||||
apiClient.sendSyncPlayCommand(sessionId, 'SeekRequest', {
|
||||
apiClient.requestSyncPlaySeek({
|
||||
PositionTicks: PositionTicks
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
<<<<<<< HEAD
|
||||
import appHost from 'apphost';
|
||||
import appSettings from 'appSettings';
|
||||
import dom from 'dom';
|
||||
|
@ -8,6 +9,10 @@ import browser from 'browser';
|
|||
import globalize from 'globalize';
|
||||
import 'cardStyle';
|
||||
import 'emby-checkbox';
|
||||
=======
|
||||
define(['apphost', 'appSettings', 'dom', 'connectionManager', 'loading', 'layoutManager', 'libraryMenu', 'browser', 'globalize', 'cardStyle', 'emby-checkbox'], function (appHost, appSettings, dom, connectionManager, loading, layoutManager, libraryMenu, browser, globalize) {
|
||||
'use strict';
|
||||
>>>>>>> upstream/master
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
|
@ -16,6 +21,7 @@ import 'emby-checkbox';
|
|||
function authenticateUserByName(page, apiClient, username, password) {
|
||||
loading.show();
|
||||
apiClient.authenticateUserByName(username, password).then(function (result) {
|
||||
<<<<<<< HEAD
|
||||
const user = result.User;
|
||||
const serverId = getParameterByName('serverid');
|
||||
let newUrl;
|
||||
|
@ -26,9 +32,13 @@ import 'emby-checkbox';
|
|||
newUrl = 'home.html';
|
||||
}
|
||||
|
||||
=======
|
||||
var user = result.User;
|
||||
>>>>>>> upstream/master
|
||||
loading.hide();
|
||||
|
||||
Dashboard.onServerChanged(user.Id, result.AccessToken, apiClient);
|
||||
Dashboard.navigate(newUrl);
|
||||
Dashboard.navigate('home.html');
|
||||
}, function (response) {
|
||||
page.querySelector('#txtManualName').value = '';
|
||||
page.querySelector('#txtManualPassword').value = '';
|
||||
|
@ -204,6 +214,7 @@ import 'emby-checkbox';
|
|||
});
|
||||
view.addEventListener('viewshow', function (e) {
|
||||
loading.show();
|
||||
libraryMenu.setTransparentMenu(true);
|
||||
|
||||
if (!appHost.supports('multiserver')) {
|
||||
view.querySelector('.btnSelectServer').classList.add('hide');
|
||||
|
@ -225,6 +236,14 @@ import 'emby-checkbox';
|
|||
view.querySelector('.disclaimer').textContent = options.LoginDisclaimer || '';
|
||||
});
|
||||
});
|
||||
<<<<<<< HEAD
|
||||
}
|
||||
|
||||
/* eslint-enable indent */
|
||||
=======
|
||||
view.addEventListener('viewhide', function (e) {
|
||||
libraryMenu.setTransparentMenu(false);
|
||||
});
|
||||
};
|
||||
});
|
||||
>>>>>>> upstream/master
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
<<<<<<< HEAD
|
||||
import loading from 'loading';
|
||||
import appRouter from 'appRouter';
|
||||
import layoutManager from 'layoutManager';
|
||||
|
@ -19,6 +20,12 @@ import 'emby-button';
|
|||
/* eslint-disable indent */
|
||||
|
||||
const enableFocusTransform = !browser.slow && !browser.edge;
|
||||
=======
|
||||
define(['loading', 'appRouter', 'layoutManager', 'libraryMenu', 'appSettings', 'apphost', 'focusManager', 'connectionManager', 'globalize', 'actionsheet', 'dom', 'browser', 'material-icons', 'flexStyles', 'emby-scroller', 'emby-itemscontainer', 'cardStyle', 'emby-button'], function (loading, appRouter, layoutManager, libraryMenu, appSettings, appHost, focusManager, connectionManager, globalize, actionSheet, dom, browser) {
|
||||
'use strict';
|
||||
|
||||
var enableFocusTransform = !browser.slow && !browser.edge;
|
||||
>>>>>>> upstream/master
|
||||
|
||||
function renderSelectServerItems(view, servers) {
|
||||
const items = servers.map(function (server) {
|
||||
|
@ -200,6 +207,7 @@ import 'emby-button';
|
|||
view.addEventListener('viewshow', function (e) {
|
||||
const isRestored = e.detail.isRestored;
|
||||
appRouter.setTitle(null);
|
||||
libraryMenu.setTransparentMenu(true);
|
||||
|
||||
if (!isRestored) {
|
||||
loadServers();
|
||||
|
|
|
@ -189,6 +189,7 @@ import 'emby-itemscontainer';
|
|||
function reloadSystemInfo(view, apiClient) {
|
||||
apiClient.getSystemInfo().then(function (systemInfo) {
|
||||
view.querySelector('#serverName').innerHTML = globalize.translate('DashboardServerName', systemInfo.ServerName);
|
||||
<<<<<<< HEAD
|
||||
let localizedVersion = globalize.translate('DashboardVersionNumber', systemInfo.Version);
|
||||
|
||||
if (systemInfo.SystemUpdateLevel !== 'Release') {
|
||||
|
@ -196,6 +197,9 @@ import 'emby-itemscontainer';
|
|||
}
|
||||
|
||||
view.querySelector('#versionNumber').innerHTML = localizedVersion;
|
||||
=======
|
||||
view.querySelector('#versionNumber').innerHTML = globalize.translate('DashboardVersionNumber', systemInfo.Version);
|
||||
>>>>>>> upstream/master
|
||||
view.querySelector('#operatingSystem').innerHTML = globalize.translate('DashboardOperatingSystem', systemInfo.OperatingSystem);
|
||||
view.querySelector('#architecture').innerHTML = globalize.translate('DashboardArchitecture', systemInfo.SystemArchitecture);
|
||||
|
||||
|
|
|
@ -170,7 +170,7 @@ import 'emby-itemrefreshindicator';
|
|||
showType: false,
|
||||
showLocations: false,
|
||||
showMenu: false,
|
||||
showNameWithIcon: true
|
||||
showNameWithIcon: false
|
||||
});
|
||||
|
||||
for (let i = 0; i < virtualFolders.length; i++) {
|
||||
|
@ -185,7 +185,7 @@ import 'emby-itemrefreshindicator';
|
|||
$('.btnCardMenu', divVirtualFolders).on('click', function () {
|
||||
showCardMenu(page, this, virtualFolders);
|
||||
});
|
||||
divVirtualFolders.querySelector('.addLibrary').addEventListener('click', function () {
|
||||
divVirtualFolders.querySelector('#addLibrary').addEventListener('click', function () {
|
||||
addVirtualFolder(page);
|
||||
});
|
||||
$('.editLibrary', divVirtualFolders).on('click', function () {
|
||||
|
@ -256,7 +256,12 @@ import 'emby-itemrefreshindicator';
|
|||
style += 'min-width:33.3%;';
|
||||
}
|
||||
|
||||
html += '<div class="card backdropCard scalableCard backdropCard-scalable" style="' + style + '" data-index="' + index + '" data-id="' + virtualFolder.ItemId + '">';
|
||||
if (virtualFolder.Locations.length == 0) {
|
||||
html += '<div id="addLibrary" class="card backdropCard scalableCard backdropCard-scalable" style="' + style + '" data-index="' + index + '" data-id="' + virtualFolder.ItemId + '">';
|
||||
} else {
|
||||
html += '<div class="card backdropCard scalableCard backdropCard-scalable" style="' + style + '" data-index="' + index + '" data-id="' + virtualFolder.ItemId + '">';
|
||||
}
|
||||
|
||||
html += '<div class="cardBox visualCardBox">';
|
||||
html += '<div class="cardScalable visualCardBox-cardScalable">';
|
||||
html += '<div class="cardPadder cardPadder-backdrop"></div>';
|
||||
|
|
|
@ -105,7 +105,9 @@ import globalize from 'globalize';
|
|||
$('#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();
|
||||
}
|
||||
|
||||
|
@ -147,7 +149,9 @@ import globalize from 'globalize';
|
|||
}).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);
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
<div id="itemDetailPage" data-role="page" class="page libraryPage itemDetailPage noSecondaryNavPage selfBackdropPage noBackdrop" data-backbutton="true">
|
||||
<div id="itemDetailPage" data-role="page" class="page libraryPage itemDetailPage noSecondaryNavPage selfBackdropPage" data-backbutton="true">
|
||||
<div id="itemBackdrop" class="itemBackdrop">
|
||||
<button is="emby-button" type="button" class="btnPlay detailFloatingButton hide fab autoSize" title="${ButtonPlay}" data-mode="resume">
|
||||
<span class="material-icons play_arrow"></span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="detailLogo"></div>
|
||||
|
@ -15,94 +12,75 @@
|
|||
</div>
|
||||
|
||||
<div class="mainDetailButtons">
|
||||
<button is="emby-button" type="button" class="button-flat btnResume hide detailButton detailButtonHideonMobile" data-mode="resume">
|
||||
<button is="emby-button" type="button" class="button-flat btnResume hide detailButton" title="${ButtonResume}" data-mode="resume">
|
||||
<div class="detailButton-content">
|
||||
<span class="material-icons detailButton-icon play_arrow"></span>
|
||||
<div class="detailButton-text">${ButtonResume}</div>
|
||||
</div>
|
||||
</button>
|
||||
|
||||
<button is="emby-button" type="button" class="button-flat btnPlay hide detailButton detailButtonHideonMobile" data-mode="play">
|
||||
<button is="emby-button" type="button" class="button-flat btnPlay hide detailButton" title="${ButtonPlay}" data-mode="play">
|
||||
<div class="detailButton-content">
|
||||
<span class="material-icons detailButton-icon play_arrow"></span>
|
||||
<div class="detailButton-text">${ButtonPlay}</div>
|
||||
</div>
|
||||
</button>
|
||||
|
||||
<button is="emby-button" type="button" class="button-flat btnDownload hide detailButton">
|
||||
<button is="emby-button" type="button" class="button-flat btnDownload hide detailButton" title="${ButtonDownload}">
|
||||
<div class="detailButton-content">
|
||||
<span class="material-icons detailButton-icon get_app"></span>
|
||||
<div class="detailButton-text">${ButtonDownload}</div>
|
||||
</div>
|
||||
</button>
|
||||
|
||||
<button is="emby-button" type="button" class="button-flat btnPlayTrailer hide detailButton">
|
||||
<button is="emby-button" type="button" class="button-flat btnPlayTrailer hide detailButton" title="${ButtonTrailer}">
|
||||
<div class="detailButton-content">
|
||||
<span class="material-icons detailButton-icon theaters"></span>
|
||||
<div class="detailButton-text">${ButtonTrailer}</div>
|
||||
</div>
|
||||
</button>
|
||||
|
||||
<button is="emby-button" type="button" class="button-flat btnInstantMix hide detailButton">
|
||||
<button is="emby-button" type="button" class="button-flat btnInstantMix hide detailButton" title="${HeaderInstantMix}">
|
||||
<div class="detailButton-content">
|
||||
<span class="material-icons detailButton-icon explore"></span>
|
||||
<div class="detailButton-text">${HeaderInstantMix}</div>
|
||||
</div>
|
||||
</button>
|
||||
|
||||
<button is="emby-button" type="button" class="button-flat btnShuffle hide detailButton">
|
||||
<button is="emby-button" type="button" class="button-flat btnShuffle hide detailButton" title="${ButtonShuffle}">
|
||||
<div class="detailButton-content">
|
||||
<span class="material-icons detailButton-icon shuffle"></span>
|
||||
<div class="detailButton-text">${ButtonShuffle}</div>
|
||||
</div>
|
||||
</button>
|
||||
|
||||
<button is="emby-button" type="button" class="button-flat btnCancelSeriesTimer hide detailButton">
|
||||
<button is="emby-button" type="button" class="button-flat btnCancelSeriesTimer hide detailButton" title="${CancelSeries}">
|
||||
<div class="detailButton-content">
|
||||
<span class="material-icons detailButton-icon delete"></span>
|
||||
<div class="detailButton-text">${CancelSeries}</div>
|
||||
</div>
|
||||
</button>
|
||||
|
||||
<button is="emby-button" type="button" class="button-flat btnCancelTimer hide detailButton">
|
||||
<button is="emby-button" type="button" class="button-flat btnCancelTimer hide detailButton" title="${StopRecording}">
|
||||
<div class="detailButton-content">
|
||||
<span class="material-icons detailButton-icon stop"></span>
|
||||
<div class="detailButton-text">${StopRecording}</div>
|
||||
</div>
|
||||
</button>
|
||||
|
||||
<button is="emby-button" type="button" class="button-flat btnDeleteItem hide detailButton">
|
||||
<div class="detailButton-content">
|
||||
<span class="material-icons detailButton-icon delete"></span>
|
||||
<div class="detailButton-text">${Delete}</div>
|
||||
</div>
|
||||
</button>
|
||||
|
||||
<button is="emby-playstatebutton" type="button" class="button-flat btnPlaystate hide detailButton">
|
||||
<button is="emby-playstatebutton" type="button" class="button-flat btnPlaystate hide detailButton" title="">
|
||||
<div class="detailButton-content">
|
||||
<span class="material-icons detailButton-icon check"></span>
|
||||
<div class="detailButton-text button-text"></div>
|
||||
</div>
|
||||
</button>
|
||||
|
||||
<button is="emby-ratingbutton" type="button" class="button-flat btnUserRating hide detailButton">
|
||||
<button is="emby-ratingbutton" type="button" class="button-flat btnUserRating hide detailButton" title="${Rate}">
|
||||
<div class="detailButton-content">
|
||||
<span class="material-icons detailButton-icon favorite"></span>
|
||||
<div class="detailButton-text button-text">${Rate}</div>
|
||||
</div>
|
||||
</button>
|
||||
|
||||
<button is="emby-button" type="button" class="button-flat btnSplitVersions hide detailButton">
|
||||
<button is="emby-button" type="button" class="button-flat btnSplitVersions hide detailButton" title="${ButtonSplit}">
|
||||
<div class="detailButton-content">
|
||||
<span class="material-icons detailButton-icon call_split"></span>
|
||||
<div class="detailButton-text">${ButtonSplit}</div>
|
||||
</div>
|
||||
</button>
|
||||
|
||||
<button is="emby-button" type="button" class="button-flat btnMoreCommands hide detailButton">
|
||||
<button is="emby-button" type="button" class="button-flat btnMoreCommands hide detailButton" title="${ButtonMore}">
|
||||
<div class="detailButton-content">
|
||||
<span class="material-icons detailButton-icon more_vert"></span>
|
||||
<div class="detailButton-text">${ButtonMore}</div>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
|
@ -110,7 +88,7 @@
|
|||
<div class="detailPageSecondaryContainer">
|
||||
<div class="detailImageContainer padded-left"></div>
|
||||
<div class="detailPageContent">
|
||||
<div class="detailPagePrimaryContent padded-left padded-right">
|
||||
<div class="detailPagePrimaryContent padded-right">
|
||||
<div class="detailSection">
|
||||
<div class="itemMiscInfo nativeName hide"></div>
|
||||
|
||||
|
@ -124,6 +102,11 @@
|
|||
<div class="directorsLabel label"></div>
|
||||
<div class="directors content"></div>
|
||||
</div>
|
||||
|
||||
<div class="detailsGroupItem writersGroup hide">
|
||||
<div class="writersLabel label"></div>
|
||||
<div class="writers content"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form class="trackSelections hide focuscontainer-x">
|
||||
|
@ -164,15 +147,15 @@
|
|||
</div>
|
||||
|
||||
<div class="seriesTimerScheduleSection verticalSection detailVerticalSection hide" style="margin-top:-3em;">
|
||||
<h2 class="sectionTitle padded-left">${HeaderSchedule}</h2>
|
||||
<div class="seriesTimerSchedule padded-left padded-right"></div>
|
||||
<h2 class="sectionTitle">${HeaderSchedule}</h2>
|
||||
<div class="seriesTimerSchedule padded-right"></div>
|
||||
</div>
|
||||
|
||||
<div class="collectionItems"></div>
|
||||
<div class="collectionItems hide"></div>
|
||||
|
||||
<div class="nextUpSection verticalSection detailVerticalSection hide">
|
||||
<h2 class="sectionTitle sectionTitle-cards padded-left">${HeaderNextUp}</h2>
|
||||
<div is="emby-itemscontainer" class="nextUpItems vertical-wrap padded-left padded-right"></div>
|
||||
<h2 class="sectionTitle sectionTitle-cards">${HeaderNextUp}</h2>
|
||||
<div is="emby-itemscontainer" class="nextUpItems vertical-wrap padded-right"></div>
|
||||
</div>
|
||||
|
||||
<div class="programGuideSection hide verticalSection detailVerticalSection">
|
||||
|
@ -180,64 +163,64 @@
|
|||
</div>
|
||||
|
||||
<div id="childrenCollapsible" class="hide verticalSection detailVerticalSection">
|
||||
<h2 class="childrenSectionHeader sectionTitle sectionTitle-cards padded-left">
|
||||
<h2 class="childrenSectionHeader sectionTitle sectionTitle-cards hide">
|
||||
<span id="childrenTitle"></span>
|
||||
</h2>
|
||||
<div id="childrenContent">
|
||||
<div is="emby-itemscontainer" class="childrenItemsContainer itemsContainer padded-left padded-right" style="text-align: left;"></div>
|
||||
<div is="emby-itemscontainer" class="childrenItemsContainer itemsContainer padded-right" style="text-align: left;"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="additionalPartsCollapsible" class="verticalSection detailVerticalSection hide">
|
||||
<h2 class="sectionTitle sectionTitle-cards padded-left padded-right">${HeaderAdditionalParts}</h2>
|
||||
<div id="additionalPartsContent" is="emby-itemscontainer" class="itemsContainer vertical-wrap padded-left padded-right"></div>
|
||||
<h2 class="sectionTitle sectionTitle-cards padded-right">${HeaderAdditionalParts}</h2>
|
||||
<div id="additionalPartsContent" is="emby-itemscontainer" class="itemsContainer vertical-wrap padded-right"></div>
|
||||
</div>
|
||||
|
||||
<div class="verticalSection itemVerticalSection moreFromSeasonSection hide">
|
||||
<h2 class="sectionTitle sectionTitle-cards padded-left padded-right"></h2>
|
||||
<div class="verticalSection detailVerticalSection moreFromSeasonSection hide">
|
||||
<h2 class="sectionTitle sectionTitle-cards padded-right"></h2>
|
||||
<div is="emby-scroller" class="padded-top-focusscale padded-bottom-focusscale" data-centerfocus="true">
|
||||
<div is="emby-itemscontainer" class="scrollSlider focuscontainer-x itemsContainer"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="verticalSection itemVerticalSection moreFromArtistSection hide">
|
||||
<h2 class="sectionTitle sectionTitle-cards padded-left padded-right"></h2>
|
||||
<div class="verticalSection detailVerticalSection moreFromArtistSection hide">
|
||||
<h2 class="sectionTitle sectionTitle-cards padded-right"></h2>
|
||||
<div is="emby-scroller" class="padded-top-focusscale padded-bottom-focusscale" data-centerfocus="true">
|
||||
<div is="emby-itemscontainer" class="scrollSlider focuscontainer-x itemsContainer"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="castCollapsible" class="verticalSection detailVerticalSection hide">
|
||||
<h2 id="peopleHeader" class="sectionTitle sectionTitle-cards padded-left padded-right">${HeaderCastCrew}</h2>
|
||||
<h2 id="peopleHeader" class="sectionTitle sectionTitle-cards padded-right">${HeaderCastCrew}</h2>
|
||||
<div is="emby-scroller" class="padded-top-focusscale padded-bottom-focusscale" data-centerfocus="true">
|
||||
<div id="castContent" is="emby-itemscontainer" class="scrollSlider focuscontainer-x itemsContainer"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="seriesScheduleSection" class="verticalSection detailVerticalSection hide">
|
||||
<h2 class="sectionTitle padded-left padded-right">${HeaderUpcomingOnTV}</h2>
|
||||
<div id="seriesScheduleList" is="emby-itemscontainer" class="itemsContainer vertical-list padded-left padded-right"></div>
|
||||
<h2 class="sectionTitle padded-right">${HeaderUpcomingOnTV}</h2>
|
||||
<div id="seriesScheduleList" is="emby-itemscontainer" class="itemsContainer vertical-list padded-right"></div>
|
||||
</div>
|
||||
|
||||
<div id="specialsCollapsible" class="verticalSection detailVerticalSection hide">
|
||||
<h2 class="sectionTitle sectionTitle-cards padded-left padded-right">${HeaderSpecialFeatures}</h2>
|
||||
<div id="specialsContent" is="emby-itemscontainer" class="itemsContainer vertical-wrap padded-left padded-right"></div>
|
||||
<h2 class="sectionTitle sectionTitle-cards padded-right">${HeaderSpecialFeatures}</h2>
|
||||
<div id="specialsContent" is="emby-itemscontainer" class="itemsContainer vertical-wrap padded-right"></div>
|
||||
</div>
|
||||
|
||||
<div id="musicVideosCollapsible" class="verticalSection detailVerticalSection hide">
|
||||
<h2 class="sectionTitle sectionTitle-cards padded-left padded-right">${HeaderMusicVideos}</h2>
|
||||
<div id="musicVideosContent" is="emby-itemscontainer" class="itemsContainer vertical-wrap padded-left padded-right"></div>
|
||||
<h2 class="sectionTitle sectionTitle-cards padded-right">${HeaderMusicVideos}</h2>
|
||||
<div id="musicVideosContent" is="emby-itemscontainer" class="itemsContainer vertical-wrap padded-right"></div>
|
||||
</div>
|
||||
|
||||
<div id="scenesCollapsible" class="verticalSection itemVerticalSection verticalSection-extrabottompadding hide">
|
||||
<h2 class="sectionTitle sectionTitle-cards padded-left padded-right">${HeaderScenes}</h2>
|
||||
<div id="scenesCollapsible" class="verticalSection detailVerticalSection verticalSection-extrabottompadding hide">
|
||||
<h2 class="sectionTitle sectionTitle-cards padded-right">${HeaderScenes}</h2>
|
||||
<div is="emby-scroller" class="padded-top-focusscale padded-bottom-focusscale" data-centerfocus="true">
|
||||
<div id="scenesContent" is="emby-itemscontainer" class="scrollSlider focuscontainer-x itemsContainer"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="similarCollapsible" class="verticalSection itemVerticalSection verticalSection-extrabottompadding hide">
|
||||
<h2 class="sectionTitle sectionTitle-cards padded-left padded-right">${HeaderMoreLikeThis}</h2>
|
||||
<div id="similarCollapsible" class="verticalSection detailVerticalSection verticalSection-extrabottompadding hide">
|
||||
<h2 class="sectionTitle sectionTitle-cards padded-right">${HeaderMoreLikeThis}</h2>
|
||||
<div is="emby-scroller" class="padded-top-focusscale padded-bottom-focusscale" data-centerfocus="true">
|
||||
<div is="emby-itemscontainer" class="scrollSlider focuscontainer-x itemsContainer similarContent"></div>
|
||||
</div>
|
|
@ -28,15 +28,11 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti
|
|||
}
|
||||
|
||||
function hideAll(page, className, show) {
|
||||
var i;
|
||||
var length;
|
||||
var elems = page.querySelectorAll('.' + className);
|
||||
|
||||
for (i = 0, length = elems.length; i < length; i++) {
|
||||
for (const elem of page.querySelectorAll('.' + className)) {
|
||||
if (show) {
|
||||
elems[i].classList.remove('hide');
|
||||
elem.classList.remove('hide');
|
||||
} else {
|
||||
elems[i].classList.add('hide');
|
||||
elem.classList.add('hide');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -51,17 +47,19 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti
|
|||
positionTo: button,
|
||||
cancelTimer: false,
|
||||
record: false,
|
||||
deleteItem: true === item.IsFolder,
|
||||
deleteItem: item.CanDelete === true,
|
||||
shuffle: false,
|
||||
instantMix: false,
|
||||
user: user,
|
||||
share: true
|
||||
};
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
function getProgramScheduleHtml(items) {
|
||||
var html = '';
|
||||
|
||||
html += '<div is="emby-itemscontainer" class="itemsContainer vertical-list" data-contextmenu="false">';
|
||||
html += listView.getListViewHtml({
|
||||
items: items,
|
||||
|
@ -75,7 +73,10 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti
|
|||
moreButton: false,
|
||||
recordButton: false
|
||||
});
|
||||
return html += '</div>';
|
||||
|
||||
html += '</div>';
|
||||
|
||||
return html;
|
||||
}
|
||||
|
||||
function renderSeriesTimerSchedule(page, apiClient, seriesTimerId) {
|
||||
|
@ -143,9 +144,12 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti
|
|||
|
||||
var mediaSources = item.MediaSources;
|
||||
instance._currentPlaybackMediaSources = mediaSources;
|
||||
|
||||
page.querySelector('.trackSelections').classList.remove('hide');
|
||||
select.setLabel(globalize.translate('LabelVersion'));
|
||||
|
||||
var currentValue = select.value;
|
||||
|
||||
var selectedId = mediaSources[0].Id;
|
||||
select.innerHTML = mediaSources.map(function (v) {
|
||||
var selected = v.Id === selectedId ? ' selected' : '';
|
||||
|
@ -163,7 +167,6 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti
|
|||
renderAudioSelections(page, mediaSources);
|
||||
renderSubtitleSelections(page, mediaSources);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function renderVideoSelections(page, mediaSources) {
|
||||
|
@ -171,9 +174,11 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti
|
|||
var mediaSource = mediaSources.filter(function (m) {
|
||||
return m.Id === mediaSourceId;
|
||||
})[0];
|
||||
|
||||
var tracks = mediaSource.MediaStreams.filter(function (m) {
|
||||
return 'Video' === m.Type;
|
||||
return m.Type === 'Video';
|
||||
});
|
||||
|
||||
var select = page.querySelector('.selectVideo');
|
||||
select.setLabel(globalize.translate('LabelVideo'));
|
||||
var selectedId = tracks.length ? tracks[0].Index : -1;
|
||||
|
@ -242,12 +247,24 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti
|
|||
select.setLabel(globalize.translate('LabelSubtitles'));
|
||||
var selectedId = null == mediaSource.DefaultSubtitleStreamIndex ? -1 : mediaSource.DefaultSubtitleStreamIndex;
|
||||
|
||||
if (tracks.length) {
|
||||
var videoTracks = mediaSource.MediaStreams.filter(function (m) {
|
||||
return 'Video' === m.Type;
|
||||
});
|
||||
|
||||
// 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) {
|
||||
selected = v.Index === selectedId ? ' selected' : '';
|
||||
return '<option value="' + v.Index + '" ' + selected + '>' + v.DisplayTitle + '</option>';
|
||||
}).join('');
|
||||
|
||||
if (tracks.length > 0) {
|
||||
select.removeAttribute('disabled');
|
||||
} else {
|
||||
select.setAttribute('disabled', 'disabled');
|
||||
}
|
||||
|
||||
page.querySelector('.selectSubtitlesContainer').classList.remove('hide');
|
||||
} else {
|
||||
select.innerHTML = '';
|
||||
|
@ -278,7 +295,15 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti
|
|||
var enableShuffle = item.IsFolder || -1 !== ['MusicAlbum', 'MusicGenre', 'MusicArtist'].indexOf(item.Type);
|
||||
hideAll(page, 'btnShuffle', enableShuffle);
|
||||
canPlay = true;
|
||||
hideAll(page, 'btnResume', item.UserData && item.UserData.PlaybackPositionTicks > 0);
|
||||
|
||||
const isResumable = item.UserData && item.UserData.PlaybackPositionTicks > 0;
|
||||
hideAll(page, 'btnResume', isResumable);
|
||||
|
||||
if (isResumable) {
|
||||
for (const elem of page.querySelectorAll('.btnPlay')) {
|
||||
elem.querySelector('.detailButton-icon').classList.replace('play_arrow', 'replay');
|
||||
}
|
||||
}
|
||||
} else {
|
||||
hideAll(page, 'btnPlay');
|
||||
hideAll(page, 'btnResume');
|
||||
|
@ -324,8 +349,7 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti
|
|||
function getArtistLinksHtml(artists, serverId, context) {
|
||||
var html = [];
|
||||
|
||||
for (var i = 0, length = artists.length; i < length; i++) {
|
||||
var artist = artists[i];
|
||||
for (const artist of artists) {
|
||||
var href = appRouter.getRouteUrl(artist, {
|
||||
context: context,
|
||||
itemType: 'MusicArtist',
|
||||
|
@ -333,10 +357,18 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti
|
|||
});
|
||||
html.push('<a style="color:inherit;" class="button-link" is="emby-linkbutton" href="' + href + '">' + artist.Name + '</a>');
|
||||
}
|
||||
html = html.join(' / ');
|
||||
|
||||
return html = html.join(' / ');
|
||||
return html;
|
||||
}
|
||||
function renderName(item, container, isStatic, context) {
|
||||
|
||||
/**
|
||||
* Renders the item's name block
|
||||
* @param {Object} item - Item used to render the name.
|
||||
* @param {HTMLDivElement} container - Container to render the information into.
|
||||
* @param {Object} context - Application context.
|
||||
*/
|
||||
function renderName(item, container, context) {
|
||||
var parentRoute;
|
||||
var parentNameHtml = [];
|
||||
var parentNameLast = false;
|
||||
|
@ -410,16 +442,12 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti
|
|||
if (parentNameLast) {
|
||||
// Music
|
||||
if (layoutManager.mobile) {
|
||||
html = '<h3 class="parentName" style="margin: .25em 0;">' + parentNameHtml.join('</br>') + '</h3>';
|
||||
html = '<h3 class="parentName musicParentName">' + parentNameHtml.join('</br>') + '</h3>';
|
||||
} else {
|
||||
html = '<h3 class="parentName" style="margin: .25em 0;">' + parentNameHtml.join(' - ') + '</h3>';
|
||||
html = '<h3 class="parentName musicParentName">' + parentNameHtml.join(' - ') + '</h3>';
|
||||
}
|
||||
} else {
|
||||
if (layoutManager.mobile) {
|
||||
html = '<h1 class="parentName" style="margin: 0.2em 0 0">' + parentNameHtml.join('</br>') + '</h1>';
|
||||
} else {
|
||||
html = '<h1 class="parentName" style="margin: 0.2em 0 0">' + tvShowHtml + '</h1>';
|
||||
}
|
||||
html = '<h1 class="parentName">' + tvShowHtml + '</h1>';
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -428,17 +456,19 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti
|
|||
});
|
||||
|
||||
if (html && !parentNameLast) {
|
||||
if (!layoutManager.mobile && tvSeasonHtml) {
|
||||
html += '<h3 class="itemName infoText" style="margin: 0.2em 0 0">' + tvSeasonHtml + ' - ' + name + '</h3>';
|
||||
if (tvSeasonHtml) {
|
||||
html += '<h3 class="itemName infoText subtitle">' + tvSeasonHtml + ' - ' + name + '</h3>';
|
||||
} else {
|
||||
html += '<h3 class="itemName infoText" style="margin: 0.2em 0 0">' + name + '</h3>';
|
||||
html += '<h3 class="itemName infoText subtitle">' + name + '</h3>';
|
||||
}
|
||||
} else if (item.OriginalTitle && item.OriginalTitle != item.Name) {
|
||||
html = '<h1 class="itemName infoText parentNameLast withOriginalTitle">' + name + '</h1>' + html;
|
||||
} else {
|
||||
html = '<h1 class="itemName infoText" style="margin: 0.4em 0 0">' + name + '</h1>' + html;
|
||||
html = '<h1 class="itemName infoText parentNameLast">' + name + '</h1>' + html;
|
||||
}
|
||||
|
||||
if (item.OriginalTitle && item.OriginalTitle != item.Name) {
|
||||
html += '<h4 class="itemName infoText" style="margin: 0 0 0;">' + item.OriginalTitle + '</h4>';
|
||||
html += '<h4 class="itemName infoText originalTitle">' + item.OriginalTitle + '</h4>';
|
||||
}
|
||||
|
||||
container.innerHTML = html;
|
||||
|
@ -470,43 +500,18 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti
|
|||
var imgUrl;
|
||||
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 === 'Person';
|
||||
|
||||
if (!layoutManager.mobile && !userSettings.detailsBanner()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ('Program' === item.Type && item.ImageTags && item.ImageTags.Thumb) {
|
||||
imgUrl = apiClient.getScaledImageUrl(item.Id, {
|
||||
type: 'Thumb',
|
||||
maxWidth: dom.getScreenWidth(),
|
||||
index: 0,
|
||||
tag: item.ImageTags.Thumb
|
||||
});
|
||||
page.classList.remove('noBackdrop');
|
||||
imageLoader.lazyImage(itemBackdropElement, imgUrl);
|
||||
hasbackdrop = true;
|
||||
} else if (usePrimaryImage && item.ImageTags && item.ImageTags.Primary) {
|
||||
imgUrl = apiClient.getScaledImageUrl(item.Id, {
|
||||
type: 'Primary',
|
||||
maxWidth: dom.getScreenWidth(),
|
||||
index: 0,
|
||||
tag: item.ImageTags.Primary
|
||||
});
|
||||
page.classList.remove('noBackdrop');
|
||||
imageLoader.lazyImage(itemBackdropElement, imgUrl);
|
||||
hasbackdrop = true;
|
||||
} else if (item.BackdropImageTags && item.BackdropImageTags.length) {
|
||||
if (item.BackdropImageTags && item.BackdropImageTags.length) {
|
||||
imgUrl = apiClient.getScaledImageUrl(item.Id, {
|
||||
type: 'Backdrop',
|
||||
maxWidth: dom.getScreenWidth(),
|
||||
index: 0,
|
||||
tag: item.BackdropImageTags[0]
|
||||
});
|
||||
page.classList.remove('noBackdrop');
|
||||
imageLoader.lazyImage(itemBackdropElement, imgUrl);
|
||||
hasbackdrop = true;
|
||||
} else if (item.ParentBackdropItemId && item.ParentBackdropImageTags && item.ParentBackdropImageTags.length) {
|
||||
|
@ -516,50 +521,35 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti
|
|||
index: 0,
|
||||
tag: item.ParentBackdropImageTags[0]
|
||||
});
|
||||
page.classList.remove('noBackdrop');
|
||||
imageLoader.lazyImage(itemBackdropElement, imgUrl);
|
||||
hasbackdrop = true;
|
||||
} else if (item.ImageTags && item.ImageTags.Thumb) {
|
||||
imgUrl = apiClient.getScaledImageUrl(item.Id, {
|
||||
type: 'Thumb',
|
||||
maxWidth: dom.getScreenWidth(),
|
||||
index: 0,
|
||||
tag: item.ImageTags.Thumb
|
||||
});
|
||||
page.classList.remove('noBackdrop');
|
||||
imageLoader.lazyImage(itemBackdropElement, imgUrl);
|
||||
hasbackdrop = true;
|
||||
} else {
|
||||
itemBackdropElement.style.backgroundImage = '';
|
||||
}
|
||||
|
||||
if ('Person' === item.Type) {
|
||||
// FIXME: This hides the backdrop on all persons to fix a margin issue. Ideally, a proper fix should be made.
|
||||
page.classList.add('noBackdrop');
|
||||
itemBackdropElement.classList.add('personBackdrop');
|
||||
} else {
|
||||
itemBackdropElement.classList.remove('personBackdrop');
|
||||
}
|
||||
|
||||
return hasbackdrop;
|
||||
}
|
||||
|
||||
function reloadFromItem(instance, page, params, item, user) {
|
||||
var context = params.context;
|
||||
page.querySelector('.detailPagePrimaryContainer').classList.add('detailSticky');
|
||||
const apiClient = connectionManager.getApiClient(item.ServerId);
|
||||
|
||||
renderName(item, page.querySelector('.nameContainer'), false, 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);
|
||||
Emby.Page.setTitle('');
|
||||
setInitialCollapsibleState(page, item, apiClient, context, user);
|
||||
renderDetails(page, item, apiClient, context);
|
||||
renderTrackSelections(page, instance, item);
|
||||
|
||||
// Start rendering the artwork first
|
||||
renderImage(page, item);
|
||||
renderLogo(page, item, apiClient);
|
||||
renderBackdrop(item);
|
||||
renderDetailPageBackdrop(page, item, apiClient);
|
||||
|
||||
// Render the main information for the item
|
||||
page.querySelector('.detailPagePrimaryContainer').classList.add('detailRibbon');
|
||||
renderName(item, page.querySelector('.nameContainer'), params.context);
|
||||
renderDetails(page, item, apiClient, params.context);
|
||||
renderTrackSelections(page, instance, item);
|
||||
|
||||
renderSeriesTimerEditor(page, item, apiClient, user);
|
||||
renderTimerEditor(page, item, apiClient, user);
|
||||
setInitialCollapsibleState(page, item, apiClient, params.context, user);
|
||||
var canPlay = reloadPlayButtons(page, item);
|
||||
|
||||
if ((item.LocalTrailerCount || item.RemoteTrailers && item.RemoteTrailers.length) && -1 !== playbackManager.getSupportedCommands().indexOf('PlayTrailers')) {
|
||||
|
@ -570,12 +560,6 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti
|
|||
|
||||
setTrailerButtonVisibility(page, item);
|
||||
|
||||
if (item.CanDelete && !item.IsFolder) {
|
||||
hideAll(page, 'btnDeleteItem', true);
|
||||
} else {
|
||||
hideAll(page, 'btnDeleteItem');
|
||||
}
|
||||
|
||||
if ('Program' !== item.Type || canPlay) {
|
||||
hideAll(page, 'mainDetailButtons', true);
|
||||
} else {
|
||||
|
@ -667,18 +651,15 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti
|
|||
}
|
||||
|
||||
function renderLogo(page, item, apiClient) {
|
||||
var url = logoImageUrl(item, apiClient, {
|
||||
maxWidth: 400
|
||||
});
|
||||
var detailLogo = page.querySelector('.detailLogo');
|
||||
|
||||
var url = logoImageUrl(item, apiClient, {});
|
||||
|
||||
if (!layoutManager.mobile && !userSettings.enableBackdrops()) {
|
||||
detailLogo.classList.add('hide');
|
||||
} else if (url) {
|
||||
detailLogo.classList.remove('hide');
|
||||
detailLogo.classList.add('lazy');
|
||||
detailLogo.setAttribute('data-src', url);
|
||||
imageLoader.lazyImage(detailLogo);
|
||||
imageLoader.setLazyImage(detailLogo, url);
|
||||
} else {
|
||||
detailLogo.classList.add('hide');
|
||||
}
|
||||
|
@ -704,172 +685,59 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti
|
|||
}
|
||||
}
|
||||
|
||||
function renderLinks(linksElem, item) {
|
||||
var html = [];
|
||||
function renderLinks(page, item) {
|
||||
var externalLinksElem = page.querySelector('.itemExternalLinks');
|
||||
|
||||
var links = [];
|
||||
|
||||
if (!layoutManager.tv && item.HomePageUrl) {
|
||||
links.push('<a style="color:inherit;" is="emby-linkbutton" class="button-link" href="' + item.HomePageUrl + '" target="_blank">' + globalize.translate('ButtonWebsite') + '</a>');
|
||||
links.push(`<a is="emby-linkbutton" class="button-link" href="${item.HomePageUrl}" target="_blank">${globalize.translate('ButtonWebsite')}</a>`);
|
||||
}
|
||||
|
||||
if (item.ExternalUrls) {
|
||||
for (var i = 0, length = item.ExternalUrls.length; i < length; i++) {
|
||||
var url = item.ExternalUrls[i];
|
||||
links.push('<a style="color:inherit;" is="emby-linkbutton" class="button-link" href="' + url.Url + '" target="_blank">' + url.Name + '</a>');
|
||||
for (const url of item.ExternalUrls) {
|
||||
links.push(`<a is="emby-linkbutton" class="button-link" href="${url.Url}" target="_blank">${url.Name}</a>`);
|
||||
}
|
||||
}
|
||||
|
||||
var html = [];
|
||||
if (links.length) {
|
||||
html.push(links.join(', '));
|
||||
}
|
||||
|
||||
linksElem.innerHTML = html.join(', ');
|
||||
externalLinksElem.innerHTML = html.join(', ');
|
||||
|
||||
if (html.length) {
|
||||
linksElem.classList.remove('hide');
|
||||
externalLinksElem.classList.remove('hide');
|
||||
} else {
|
||||
linksElem.classList.add('hide');
|
||||
externalLinksElem.classList.add('hide');
|
||||
}
|
||||
}
|
||||
|
||||
function renderDetailImage(page, elem, item, apiClient, editable, imageLoader, indicators) {
|
||||
if ('SeriesTimer' === item.Type || 'Program' === item.Type) {
|
||||
editable = false;
|
||||
}
|
||||
function renderDetailImage(elem, item, imageLoader) {
|
||||
const itemArray = [];
|
||||
itemArray.push(item);
|
||||
const cardHtml = cardBuilder.getCardsHtml(itemArray, {
|
||||
shape: 'auto',
|
||||
showTitle: false,
|
||||
centerText: true,
|
||||
overlayText: false,
|
||||
transition: false,
|
||||
disableIndicators: true,
|
||||
disableHoverMenu: true,
|
||||
overlayPlayButton: true,
|
||||
width: dom.getWindowSize().innerWidth * 0.5
|
||||
});
|
||||
|
||||
elem.classList.add('detailimg-hidemobile');
|
||||
|
||||
var imageTags = item.ImageTags || {};
|
||||
|
||||
if (item.PrimaryImageTag) {
|
||||
imageTags.Primary = item.PrimaryImageTag;
|
||||
}
|
||||
|
||||
var url;
|
||||
var html = '';
|
||||
var shape = 'portrait';
|
||||
var detectRatio = false;
|
||||
|
||||
/* In the following section, getScreenWidth() is multiplied by 0.5 as the posters
|
||||
are 25vw and we need double the resolution to counter Skia's scaling. */
|
||||
// TODO: Find a reliable way to get the poster width
|
||||
if (imageTags.Primary) {
|
||||
url = apiClient.getScaledImageUrl(item.Id, {
|
||||
type: 'Primary',
|
||||
maxWidth: Math.round(dom.getScreenWidth() * 0.5),
|
||||
tag: item.ImageTags.Primary
|
||||
});
|
||||
detectRatio = true;
|
||||
} else if (item.BackdropImageTags && item.BackdropImageTags.length) {
|
||||
url = apiClient.getScaledImageUrl(item.Id, {
|
||||
type: 'Backdrop',
|
||||
maxWidth: Math.round(dom.getScreenWidth() * 0.5),
|
||||
tag: item.BackdropImageTags[0]
|
||||
});
|
||||
shape = 'thumb';
|
||||
} else if (imageTags.Thumb) {
|
||||
url = apiClient.getScaledImageUrl(item.Id, {
|
||||
type: 'Thumb',
|
||||
maxWidth: Math.round(dom.getScreenWidth() * 0.5),
|
||||
tag: item.ImageTags.Thumb
|
||||
});
|
||||
shape = 'thumb';
|
||||
} else if (imageTags.Disc) {
|
||||
url = apiClient.getScaledImageUrl(item.Id, {
|
||||
type: 'Disc',
|
||||
maxWidth: Math.round(dom.getScreenWidth() * 0.5),
|
||||
tag: item.ImageTags.Disc
|
||||
});
|
||||
shape = 'square';
|
||||
} else if (item.AlbumId && item.AlbumPrimaryImageTag) {
|
||||
url = apiClient.getScaledImageUrl(item.AlbumId, {
|
||||
type: 'Primary',
|
||||
maxWidth: Math.round(dom.getScreenWidth() * 0.5),
|
||||
tag: item.AlbumPrimaryImageTag
|
||||
});
|
||||
shape = 'square';
|
||||
} else if (item.SeriesId && item.SeriesPrimaryImageTag) {
|
||||
url = apiClient.getScaledImageUrl(item.SeriesId, {
|
||||
type: 'Primary',
|
||||
maxWidth: Math.round(dom.getScreenWidth() * 0.5),
|
||||
tag: item.SeriesPrimaryImageTag
|
||||
});
|
||||
} else if (item.ParentPrimaryImageItemId && item.ParentPrimaryImageTag) {
|
||||
url = apiClient.getScaledImageUrl(item.ParentPrimaryImageItemId, {
|
||||
type: 'Primary',
|
||||
maxWidth: Math.round(dom.getScreenWidth() * 0.5),
|
||||
tag: item.ParentPrimaryImageTag
|
||||
});
|
||||
}
|
||||
|
||||
if (editable && url === undefined) {
|
||||
html += "<a class='itemDetailGalleryLink itemDetailImage defaultCardBackground defaultCardBackground" + cardBuilder.getDefaultBackgroundClass(item.Name) + "' is='emby-linkbutton' style='display:block;margin:0;padding:0;' href='#'>";
|
||||
} else if (!editable && url === undefined) {
|
||||
html += "<div class='itemDetailGalleryLink itemDetailImage defaultCardBackground defaultCardBackground" + cardBuilder.getDefaultBackgroundClass(item.Name) + "' is='emby-linkbutton' style='display:block;margin:0;padding:0;' href='#'>";
|
||||
} else if (editable) {
|
||||
html += "<a class='itemDetailGalleryLink' is='emby-linkbutton' style='display:block;margin:0;padding:0;' href='#'>";
|
||||
}
|
||||
|
||||
if (url) {
|
||||
html += "<img class='itemDetailImage lazy' src='data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=' />";
|
||||
}
|
||||
|
||||
if (url === undefined) {
|
||||
html += cardBuilder.getDefaultText(item);
|
||||
}
|
||||
|
||||
if (editable) {
|
||||
html += '</a>';
|
||||
} else if (!editable && url === undefined) {
|
||||
html += '</div>';
|
||||
}
|
||||
|
||||
var progressHtml = item.IsFolder || !item.UserData ? '' : indicators.getProgressBarHtml(item);
|
||||
html += '<div class="detailImageProgressContainer">';
|
||||
|
||||
if (progressHtml) {
|
||||
html += progressHtml;
|
||||
}
|
||||
|
||||
html += '</div>';
|
||||
elem.innerHTML = html;
|
||||
|
||||
if (detectRatio && item.PrimaryImageAspectRatio) {
|
||||
if (item.PrimaryImageAspectRatio >= 1.48) {
|
||||
shape = 'thumb';
|
||||
} else if (item.PrimaryImageAspectRatio >= 0.85 && item.PrimaryImageAspectRatio <= 1.34) {
|
||||
shape = 'square';
|
||||
}
|
||||
}
|
||||
|
||||
if ('thumb' == shape) {
|
||||
elem.classList.add('thumbDetailImageContainer');
|
||||
elem.classList.remove('portraitDetailImageContainer');
|
||||
elem.classList.remove('squareDetailImageContainer');
|
||||
} else if ('square' == shape) {
|
||||
elem.classList.remove('thumbDetailImageContainer');
|
||||
elem.classList.remove('portraitDetailImageContainer');
|
||||
elem.classList.add('squareDetailImageContainer');
|
||||
} else {
|
||||
elem.classList.remove('thumbDetailImageContainer');
|
||||
elem.classList.add('portraitDetailImageContainer');
|
||||
elem.classList.remove('squareDetailImageContainer');
|
||||
}
|
||||
|
||||
if (url) {
|
||||
imageLoader.lazyImage(elem.querySelector('img'), url);
|
||||
}
|
||||
elem.innerHTML = cardHtml;
|
||||
imageLoader.lazyChildren(elem);
|
||||
}
|
||||
|
||||
function renderImage(page, item, apiClient, user) {
|
||||
function renderImage(page, item) {
|
||||
renderDetailImage(
|
||||
page,
|
||||
page.querySelector('.detailImageContainer'),
|
||||
item,
|
||||
apiClient,
|
||||
user.Policy.IsAdministrator && 'Photo' != item.MediaType,
|
||||
imageLoader,
|
||||
indicators
|
||||
imageLoader
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -985,54 +853,41 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti
|
|||
}
|
||||
}
|
||||
|
||||
function renderOverview(elems, item) {
|
||||
for (var i = 0, length = elems.length; i < length; i++) {
|
||||
var elem = elems[i];
|
||||
function renderOverview(page, item) {
|
||||
for (const overviewElemnt of page.querySelectorAll('.overview')) {
|
||||
var overview = item.Overview || '';
|
||||
|
||||
if (overview) {
|
||||
elem.innerHTML = overview;
|
||||
elem.classList.remove('hide');
|
||||
elem.classList.add('detail-clamp-text');
|
||||
overviewElemnt.innerHTML = overview;
|
||||
overviewElemnt.classList.remove('hide');
|
||||
overviewElemnt.classList.add('detail-clamp-text');
|
||||
|
||||
// Grab the sibling element to control the expand state
|
||||
var expandButton = elem.parentElement.querySelector('.overview-expand');
|
||||
var expandButton = overviewElemnt.parentElement.querySelector('.overview-expand');
|
||||
|
||||
// Detect if we have overflow of text. Based on this StackOverflow answer
|
||||
// https://stackoverflow.com/a/35157976
|
||||
if (Math.abs(elem.scrollHeight - elem.offsetHeight) > 2) {
|
||||
if (Math.abs(overviewElemnt.scrollHeight - overviewElemnt.offsetHeight) > 2) {
|
||||
expandButton.classList.remove('hide');
|
||||
} else {
|
||||
expandButton.classList.add('hide');
|
||||
}
|
||||
|
||||
expandButton.addEventListener('click', toggleLineClamp.bind(null, elem));
|
||||
expandButton.addEventListener('click', toggleLineClamp.bind(null, overviewElemnt));
|
||||
|
||||
var anchors = elem.querySelectorAll('a');
|
||||
|
||||
for (var j = 0, length2 = anchors.length; j < length2; j++) {
|
||||
anchors[j].setAttribute('target', '_blank');
|
||||
for (const anchor of overviewElemnt.querySelectorAll('a')) {
|
||||
anchor.setAttribute('target', '_blank');
|
||||
}
|
||||
} else {
|
||||
elem.innerHTML = '';
|
||||
elem.classList.add('hide');
|
||||
overviewElemnt.innerHTML = '';
|
||||
overviewElemnt.classList.add('hide');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function renderGenres(page, item, context) {
|
||||
context = context || inferContext(item);
|
||||
var type;
|
||||
function renderGenres(page, item, context = inferContext(item)) {
|
||||
var genres = item.GenreItems || [];
|
||||
|
||||
switch (context) {
|
||||
case 'music':
|
||||
type = 'MusicGenre';
|
||||
break;
|
||||
|
||||
default:
|
||||
type = 'Genre';
|
||||
}
|
||||
var type = context === 'music' ? 'MusicGenre' : 'Genre';
|
||||
|
||||
var html = genres.map(function (p) {
|
||||
return '<a style="color:inherit;" class="button-link" is="emby-linkbutton" href="' + appRouter.getRouteUrl({
|
||||
|
@ -1058,19 +913,49 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti
|
|||
}
|
||||
}
|
||||
|
||||
function renderDirector(page, item, context) {
|
||||
var directors = (item.People || []).filter(function (p) {
|
||||
return 'Director' === p.Type;
|
||||
function renderWriter(page, item, context) {
|
||||
var writers = (item.People || []).filter(function (person) {
|
||||
return person.Type === 'Writer';
|
||||
});
|
||||
var html = directors.map(function (p) {
|
||||
|
||||
var html = writers.map(function (person) {
|
||||
return '<a style="color:inherit;" class="button-link" is="emby-linkbutton" href="' + appRouter.getRouteUrl({
|
||||
Name: p.Name,
|
||||
Name: person.Name,
|
||||
Type: 'Person',
|
||||
ServerId: item.ServerId,
|
||||
Id: p.Id
|
||||
Id: person.Id
|
||||
}, {
|
||||
context: context
|
||||
}) + '">' + p.Name + '</a>';
|
||||
}) + '">' + person.Name + '</a>';
|
||||
}).join(', ');
|
||||
|
||||
var writersLabel = page.querySelector('.writersLabel');
|
||||
writersLabel.innerHTML = globalize.translate(writers.length > 1 ? 'Writers' : 'Writer');
|
||||
var writersValue = page.querySelector('.writers');
|
||||
writersValue.innerHTML = html;
|
||||
|
||||
var writersGroup = page.querySelector('.writersGroup');
|
||||
if (writers.length) {
|
||||
writersGroup.classList.remove('hide');
|
||||
} else {
|
||||
writersGroup.classList.add('hide');
|
||||
}
|
||||
}
|
||||
|
||||
function renderDirector(page, item, context) {
|
||||
var directors = (item.People || []).filter(function (person) {
|
||||
return person.Type === 'Director';
|
||||
});
|
||||
|
||||
var html = directors.map(function (person) {
|
||||
return '<a style="color:inherit;" class="button-link" is="emby-linkbutton" href="' + appRouter.getRouteUrl({
|
||||
Name: person.Name,
|
||||
Type: 'Person',
|
||||
ServerId: item.ServerId,
|
||||
Id: person.Id
|
||||
}, {
|
||||
context: context
|
||||
}) + '">' + person.Name + '</a>';
|
||||
}).join(', ');
|
||||
|
||||
var directorsLabel = page.querySelector('.directorsLabel');
|
||||
|
@ -1086,13 +971,39 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti
|
|||
}
|
||||
}
|
||||
|
||||
function renderDetails(page, item, apiClient, context, isStatic) {
|
||||
renderSimilarItems(page, item, context);
|
||||
renderMoreFromSeason(page, item, apiClient);
|
||||
renderMoreFromArtist(page, item, apiClient);
|
||||
renderDirector(page, item, context);
|
||||
renderGenres(page, item, context);
|
||||
renderChannelGuide(page, apiClient, item);
|
||||
function renderMiscInfo(page, item) {
|
||||
const primaryItemMiscInfo = page.querySelectorAll('.itemMiscInfo-primary');
|
||||
|
||||
for (const miscInfo of primaryItemMiscInfo) {
|
||||
mediaInfo.fillPrimaryMediaInfo(miscInfo, item, {
|
||||
interactive: true,
|
||||
episodeTitle: false,
|
||||
subtitles: false
|
||||
});
|
||||
|
||||
if (miscInfo.innerHTML && 'SeriesTimer' !== item.Type) {
|
||||
miscInfo.classList.remove('hide');
|
||||
} else {
|
||||
miscInfo.classList.add('hide');
|
||||
}
|
||||
}
|
||||
|
||||
const secondaryItemMiscInfo = page.querySelectorAll('.itemMiscInfo-secondary');
|
||||
|
||||
for (const miscInfo of secondaryItemMiscInfo) {
|
||||
mediaInfo.fillSecondaryMediaInfo(miscInfo, item, {
|
||||
interactive: true
|
||||
});
|
||||
|
||||
if (miscInfo.innerHTML && 'SeriesTimer' !== item.Type) {
|
||||
miscInfo.classList.remove('hide');
|
||||
} else {
|
||||
miscInfo.classList.add('hide');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function renderTagline(page, item) {
|
||||
var taglineElement = page.querySelector('.tagline');
|
||||
|
||||
if (item.Taglines && item.Taglines.length) {
|
||||
|
@ -1101,44 +1012,21 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti
|
|||
} else {
|
||||
taglineElement.classList.add('hide');
|
||||
}
|
||||
}
|
||||
|
||||
var overview = page.querySelector('.overview');
|
||||
var externalLinksElem = page.querySelector('.itemExternalLinks');
|
||||
|
||||
renderOverview([overview], item);
|
||||
|
||||
var i;
|
||||
var itemMiscInfo;
|
||||
itemMiscInfo = page.querySelectorAll('.itemMiscInfo-primary');
|
||||
for (i = 0; i < itemMiscInfo.length; i++) {
|
||||
mediaInfo.fillPrimaryMediaInfo(itemMiscInfo[i], item, {
|
||||
interactive: true,
|
||||
episodeTitle: false,
|
||||
subtitles: false
|
||||
});
|
||||
|
||||
if (itemMiscInfo[i].innerHTML && 'SeriesTimer' !== item.Type) {
|
||||
itemMiscInfo[i].classList.remove('hide');
|
||||
} else {
|
||||
itemMiscInfo[i].classList.add('hide');
|
||||
}
|
||||
}
|
||||
|
||||
itemMiscInfo = page.querySelectorAll('.itemMiscInfo-secondary');
|
||||
for (i = 0; i < itemMiscInfo.length; i++) {
|
||||
mediaInfo.fillSecondaryMediaInfo(itemMiscInfo[i], item, {
|
||||
interactive: true
|
||||
});
|
||||
|
||||
if (itemMiscInfo[i].innerHTML && 'SeriesTimer' !== item.Type) {
|
||||
itemMiscInfo[i].classList.remove('hide');
|
||||
} else {
|
||||
itemMiscInfo[i].classList.add('hide');
|
||||
}
|
||||
}
|
||||
|
||||
function renderDetails(page, item, apiClient, context, isStatic) {
|
||||
renderSimilarItems(page, item, context);
|
||||
renderMoreFromSeason(page, item, apiClient);
|
||||
renderMoreFromArtist(page, item, apiClient);
|
||||
renderDirector(page, item, context);
|
||||
renderWriter(page, item, context);
|
||||
renderGenres(page, item, context);
|
||||
renderChannelGuide(page, apiClient, item);
|
||||
renderTagline(page, item);
|
||||
renderOverview(page, item);
|
||||
renderMiscInfo(page, item);
|
||||
reloadUserDataButtons(page, item);
|
||||
renderLinks(externalLinksElem, item);
|
||||
renderLinks(page, item);
|
||||
renderTags(page, item);
|
||||
renderSeriesAirTime(page, item, isStatic);
|
||||
}
|
||||
|
@ -1426,8 +1314,7 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti
|
|||
action: 'playallfromhere',
|
||||
image: false,
|
||||
artist: 'auto',
|
||||
containerAlbumArtists: item.AlbumArtists,
|
||||
addToListButton: true
|
||||
containerAlbumArtists: item.AlbumArtists
|
||||
});
|
||||
isList = true;
|
||||
} else if ('Series' == item.Type) {
|
||||
|
@ -1469,11 +1356,12 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti
|
|||
items: result.Items,
|
||||
showIndexNumber: false,
|
||||
enableOverview: true,
|
||||
enablePlayedButton: layoutManager.mobile ? false : true,
|
||||
infoButton: layoutManager.mobile ? false : true,
|
||||
imageSize: 'large',
|
||||
enableSideMediaInfo: false,
|
||||
highlight: false,
|
||||
action: layoutManager.tv ? 'resume' : 'none',
|
||||
infoButton: true,
|
||||
action: !layoutManager.desktop ? 'link' : 'none',
|
||||
imagePlayButton: true,
|
||||
includeParentInfoInTitle: false
|
||||
});
|
||||
|
@ -1500,6 +1388,9 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti
|
|||
childrenItemsContainer.classList.remove('vertical-list');
|
||||
}
|
||||
}
|
||||
if (layoutManager.mobile) {
|
||||
childrenItemsContainer.classList.remove('padded-right');
|
||||
}
|
||||
childrenItemsContainer.innerHTML = html;
|
||||
imageLoader.lazyChildren(childrenItemsContainer);
|
||||
if ('BoxSet' == item.Type) {
|
||||
|
@ -1701,12 +1592,10 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti
|
|||
}
|
||||
|
||||
function renderCollectionItems(page, parentItem, types, items) {
|
||||
page.querySelector('.collectionItems').classList.remove('hide');
|
||||
page.querySelector('.collectionItems').innerHTML = '';
|
||||
var i;
|
||||
var length;
|
||||
|
||||
for (i = 0, length = types.length; i < length; i++) {
|
||||
var type = types[i];
|
||||
for (const type of types) {
|
||||
var typeItems = filterItemsByCollectionItemType(items, type);
|
||||
|
||||
if (typeItems.length) {
|
||||
|
@ -1739,8 +1628,8 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti
|
|||
renderChildren(page, parentItem);
|
||||
};
|
||||
|
||||
for (i = 0, length = containers.length; i < length; i++) {
|
||||
containers[i].notifyRefreshNeeded = notifyRefreshNeeded;
|
||||
for (const container of containers) {
|
||||
container.notifyRefreshNeeded = notifyRefreshNeeded;
|
||||
}
|
||||
|
||||
// if nothing in the collection can be played hide play and shuffle buttons
|
||||
|
@ -1876,7 +1765,7 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti
|
|||
|
||||
function renderCast(page, item) {
|
||||
var people = (item.People || []).filter(function (p) {
|
||||
return 'Director' !== p.Type;
|
||||
return p.Type === 'Actor';
|
||||
});
|
||||
|
||||
if (!people.length) {
|
||||
|
@ -1905,12 +1794,10 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti
|
|||
}
|
||||
|
||||
function bindAll(view, selector, eventName, fn) {
|
||||
var i;
|
||||
var length;
|
||||
var elems = view.querySelectorAll(selector);
|
||||
|
||||
for (i = 0, length = elems.length; i < length; i++) {
|
||||
elems[i].addEventListener(eventName, fn);
|
||||
for (const elem of elems) {
|
||||
elem.addEventListener(eventName, fn);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1923,13 +1810,14 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti
|
|||
return function (view, params) {
|
||||
function reload(instance, page, params) {
|
||||
loading.show();
|
||||
|
||||
var apiClient = params.serverId ? connectionManager.getApiClient(params.serverId) : ApiClient;
|
||||
var promises = [getPromise(apiClient, params), apiClient.getCurrentUser()];
|
||||
Promise.all(promises).then(function (responses) {
|
||||
var item = responses[0];
|
||||
var user = responses[1];
|
||||
|
||||
Promise.all([getPromise(apiClient, params), apiClient.getCurrentUser()]).then(([item, user]) => {
|
||||
currentItem = item;
|
||||
reloadFromItem(instance, page, params, item, user);
|
||||
}).catch((error) => {
|
||||
console.error('failed to get item or current user: ', error);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -1980,7 +1868,7 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti
|
|||
});
|
||||
}
|
||||
|
||||
playItem(item, item.UserData && 'resume' === mode ? item.UserData.PlaybackPositionTicks : 0);
|
||||
playItem(item, item.UserData && mode === 'resume' ? item.UserData.PlaybackPositionTicks : 0);
|
||||
}
|
||||
|
||||
function onPlayClick() {
|
||||
|
@ -1995,15 +1883,6 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti
|
|||
playbackManager.shuffle(currentItem);
|
||||
}
|
||||
|
||||
function onDeleteClick() {
|
||||
require(['deleteHelper'], function (deleteHelper) {
|
||||
deleteHelper.deleteItem({
|
||||
item: currentItem,
|
||||
navigate: true
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function onCancelSeriesTimerClick() {
|
||||
require(['recordingHelper'], function (recordingHelper) {
|
||||
recordingHelper.cancelSeriesTimerWithConfirmation(currentItem.Id, currentItem.ServerId).then(function () {
|
||||
|
@ -2092,7 +1971,6 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti
|
|||
bindAll(view, '.btnPlayTrailer', 'click', onPlayTrailerClick);
|
||||
bindAll(view, '.btnCancelSeriesTimer', 'click', onCancelSeriesTimerClick);
|
||||
bindAll(view, '.btnCancelTimer', 'click', onCancelTimerClick);
|
||||
bindAll(view, '.btnDeleteItem', 'click', onDeleteClick);
|
||||
bindAll(view, '.btnDownload', 'click', onDownloadClick);
|
||||
view.querySelector('.trackSelections').addEventListener('submit', onTrackSelectionsSubmit);
|
||||
view.querySelector('.btnSplitVersions').addEventListener('click', function () {
|
||||
|
@ -2125,9 +2003,7 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti
|
|||
view.addEventListener('viewshow', function (e) {
|
||||
var page = this;
|
||||
|
||||
if (layoutManager.mobile) {
|
||||
libraryMenu.setTransparentMenu(true);
|
||||
}
|
||||
libraryMenu.setTransparentMenu(true);
|
||||
|
||||
if (e.detail.isRestored) {
|
||||
if (currentItem) {
|
|
@ -1,22 +1,22 @@
|
|||
define(['components/remotecontrol/remotecontrol', 'libraryMenu', 'emby-button'], function (remotecontrolFactory, libraryMenu) {
|
||||
'use strict';
|
||||
import remotecontrolFactory from 'components/remotecontrol/remotecontrol';
|
||||
import libraryMenu from 'libraryMenu';
|
||||
import 'emby-button';
|
||||
|
||||
return function (view, params) {
|
||||
var remoteControl = new remotecontrolFactory();
|
||||
remoteControl.init(view, view.querySelector('.remoteControlContent'));
|
||||
view.addEventListener('viewshow', function (e) {
|
||||
libraryMenu.setTransparentMenu(true);
|
||||
export default function (view, params) {
|
||||
const remoteControl = new remotecontrolFactory();
|
||||
remoteControl.init(view, view.querySelector('.remoteControlContent'));
|
||||
view.addEventListener('viewshow', function (e) {
|
||||
libraryMenu.setTransparentMenu(true);
|
||||
|
||||
if (remoteControl) {
|
||||
remoteControl.onShow();
|
||||
}
|
||||
});
|
||||
view.addEventListener('viewbeforehide', function (e) {
|
||||
libraryMenu.setTransparentMenu(false);
|
||||
if (remoteControl) {
|
||||
remoteControl.onShow();
|
||||
}
|
||||
});
|
||||
view.addEventListener('viewbeforehide', function (e) {
|
||||
libraryMenu.setTransparentMenu(false);
|
||||
|
||||
if (remoteControl) {
|
||||
remoteControl.destroy();
|
||||
}
|
||||
});
|
||||
};
|
||||
});
|
||||
if (remoteControl) {
|
||||
remoteControl.destroy();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,5 +1,26 @@
|
|||
define(['playbackManager', 'dom', 'inputManager', 'datetime', 'itemHelper', 'mediaInfo', 'focusManager', 'imageLoader', 'scrollHelper', 'events', 'connectionManager', 'browser', 'globalize', 'apphost', 'layoutManager', 'userSettings', 'keyboardnavigation', 'scrollStyles', 'emby-slider', 'paper-icon-button-light', 'css!assets/css/videoosd'], function (playbackManager, dom, inputManager, datetime, itemHelper, mediaInfo, focusManager, imageLoader, scrollHelper, events, connectionManager, browser, globalize, appHost, layoutManager, userSettings, keyboardnavigation) {
|
||||
'use strict';
|
||||
import playbackManager from 'playbackManager';
|
||||
import dom from 'dom';
|
||||
import inputManager from 'inputManager';
|
||||
import datetime from 'datetime';
|
||||
import itemHelper from 'itemHelper';
|
||||
import mediaInfo from 'mediaInfo';
|
||||
import focusManager from 'focusManager';
|
||||
import imageLoader from 'imageLoader';
|
||||
import scrollHelper from 'scrollHelper';
|
||||
import events from 'events';
|
||||
import connectionManager from 'connectionManager';
|
||||
import browser from 'browser';
|
||||
import globalize from 'globalize';
|
||||
import appHost from 'apphost';
|
||||
import layoutManager from 'layoutManager';
|
||||
import * as userSettings from 'userSettings';
|
||||
import keyboardnavigation from 'keyboardnavigation';
|
||||
import 'scrollStyles';
|
||||
import 'emby-slider';
|
||||
import 'paper-icon-button-light';
|
||||
import 'css!assets/css/videoosd';
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
function seriesImageUrl(item, options) {
|
||||
if ('Episode' !== item.Type) {
|
||||
|
@ -45,13 +66,13 @@ define(['playbackManager', 'dom', 'inputManager', 'datetime', 'itemHelper', 'med
|
|||
return null;
|
||||
}
|
||||
|
||||
return function (view, params) {
|
||||
export default function (view, params) {
|
||||
function onVerticalSwipe(e, elem, data) {
|
||||
var player = currentPlayer;
|
||||
const player = currentPlayer;
|
||||
|
||||
if (player) {
|
||||
var deltaY = data.currentDeltaY;
|
||||
var windowSize = dom.getWindowSize();
|
||||
const deltaY = data.currentDeltaY;
|
||||
const windowSize = dom.getWindowSize();
|
||||
|
||||
if (supportsBrightnessChange && data.clientX < windowSize.innerWidth / 2) {
|
||||
return void doBrightnessTouch(deltaY, player, windowSize.innerHeight);
|
||||
|
@ -62,23 +83,23 @@ define(['playbackManager', 'dom', 'inputManager', 'datetime', 'itemHelper', 'med
|
|||
}
|
||||
|
||||
function doBrightnessTouch(deltaY, player, viewHeight) {
|
||||
var delta = -deltaY / viewHeight * 100;
|
||||
var newValue = playbackManager.getBrightness(player) + delta;
|
||||
const delta = -deltaY / viewHeight * 100;
|
||||
let newValue = playbackManager.getBrightness(player) + delta;
|
||||
newValue = Math.min(newValue, 100);
|
||||
newValue = Math.max(newValue, 0);
|
||||
playbackManager.setBrightness(newValue, player);
|
||||
}
|
||||
|
||||
function doVolumeTouch(deltaY, player, viewHeight) {
|
||||
var delta = -deltaY / viewHeight * 100;
|
||||
var newValue = playbackManager.getVolume(player) + delta;
|
||||
const delta = -deltaY / viewHeight * 100;
|
||||
let newValue = playbackManager.getVolume(player) + delta;
|
||||
newValue = Math.min(newValue, 100);
|
||||
newValue = Math.max(newValue, 0);
|
||||
playbackManager.setVolume(newValue, player);
|
||||
}
|
||||
|
||||
function onDoubleClick(e) {
|
||||
var clientX = e.clientX;
|
||||
const clientX = e.clientX;
|
||||
|
||||
if (null != clientX) {
|
||||
if (clientX < dom.getWindowSize().innerWidth / 2) {
|
||||
|
@ -94,7 +115,7 @@ define(['playbackManager', 'dom', 'inputManager', 'datetime', 'itemHelper', 'med
|
|||
|
||||
function getDisplayItem(item) {
|
||||
if ('TvChannel' === item.Type) {
|
||||
var apiClient = connectionManager.getApiClient(item.ServerId);
|
||||
const apiClient = connectionManager.getApiClient(item.ServerId);
|
||||
return apiClient.getItem(apiClient.getCurrentUserId(), item.Id).then(function (refreshedItem) {
|
||||
return {
|
||||
originalItem: refreshedItem,
|
||||
|
@ -120,7 +141,7 @@ define(['playbackManager', 'dom', 'inputManager', 'datetime', 'itemHelper', 'med
|
|||
|
||||
connectionManager.getApiClient(item.ServerId).getCurrentUser().then(function (user) {
|
||||
if (user.Policy.EnableLiveTvManagement) {
|
||||
require(['recordingButton'], function (RecordingButton) {
|
||||
import('recordingButton').then(({default: RecordingButton}) => {
|
||||
if (recordingButtonManager) {
|
||||
return void recordingButtonManager.refreshItem(item);
|
||||
}
|
||||
|
@ -136,22 +157,22 @@ define(['playbackManager', 'dom', 'inputManager', 'datetime', 'itemHelper', 'med
|
|||
}
|
||||
|
||||
function updateDisplayItem(itemInfo) {
|
||||
var item = itemInfo.originalItem;
|
||||
const item = itemInfo.originalItem;
|
||||
currentItem = item;
|
||||
var displayItem = itemInfo.displayItem || item;
|
||||
const displayItem = itemInfo.displayItem || item;
|
||||
updateRecordingButton(displayItem);
|
||||
setPoster(displayItem, item);
|
||||
var parentName = displayItem.SeriesName || displayItem.Album;
|
||||
let parentName = displayItem.SeriesName || displayItem.Album;
|
||||
|
||||
if (displayItem.EpisodeTitle || displayItem.IsSeries) {
|
||||
parentName = displayItem.Name;
|
||||
}
|
||||
|
||||
setTitle(displayItem, parentName);
|
||||
var titleElement;
|
||||
var osdTitle = view.querySelector('.osdTitle');
|
||||
let titleElement;
|
||||
const osdTitle = view.querySelector('.osdTitle');
|
||||
titleElement = osdTitle;
|
||||
var displayName = itemHelper.getDisplayName(displayItem, {
|
||||
let displayName = itemHelper.getDisplayName(displayItem, {
|
||||
includeParentInfo: 'Program' !== displayItem.Type,
|
||||
includeIndexNumber: 'Program' !== displayItem.Type
|
||||
});
|
||||
|
@ -168,7 +189,7 @@ define(['playbackManager', 'dom', 'inputManager', 'datetime', 'itemHelper', 'med
|
|||
titleElement.classList.add('hide');
|
||||
}
|
||||
|
||||
var mediaInfoHtml = mediaInfo.getPrimaryMediaInfoHtml(displayItem, {
|
||||
const mediaInfoHtml = mediaInfo.getPrimaryMediaInfoHtml(displayItem, {
|
||||
runtime: false,
|
||||
subtitles: false,
|
||||
tomatoes: false,
|
||||
|
@ -178,7 +199,7 @@ define(['playbackManager', 'dom', 'inputManager', 'datetime', 'itemHelper', 'med
|
|||
episodeTitleIndexNumber: 'Program' !== displayItem.Type,
|
||||
programIndicator: false
|
||||
});
|
||||
var osdMediaInfo = view.querySelector('.osdMediaInfo');
|
||||
const osdMediaInfo = view.querySelector('.osdMediaInfo');
|
||||
osdMediaInfo.innerHTML = mediaInfoHtml;
|
||||
|
||||
if (mediaInfoHtml) {
|
||||
|
@ -187,8 +208,8 @@ define(['playbackManager', 'dom', 'inputManager', 'datetime', 'itemHelper', 'med
|
|||
osdMediaInfo.classList.add('hide');
|
||||
}
|
||||
|
||||
var secondaryMediaInfo = view.querySelector('.osdSecondaryMediaInfo');
|
||||
var secondaryMediaInfoHtml = mediaInfo.getSecondaryMediaInfoHtml(displayItem, {
|
||||
const secondaryMediaInfo = view.querySelector('.osdSecondaryMediaInfo');
|
||||
const secondaryMediaInfoHtml = mediaInfo.getSecondaryMediaInfoHtml(displayItem, {
|
||||
startDate: false,
|
||||
programTime: false
|
||||
});
|
||||
|
@ -236,7 +257,7 @@ define(['playbackManager', 'dom', 'inputManager', 'datetime', 'itemHelper', 'med
|
|||
}
|
||||
|
||||
function setDisplayTime(elem, date) {
|
||||
var html;
|
||||
let html;
|
||||
|
||||
if (date) {
|
||||
date = datetime.parseISO8601Date(date);
|
||||
|
@ -251,7 +272,7 @@ define(['playbackManager', 'dom', 'inputManager', 'datetime', 'itemHelper', 'med
|
|||
}
|
||||
|
||||
function updateNowPlayingInfo(player, state) {
|
||||
var item = state.NowPlayingItem;
|
||||
const item = state.NowPlayingItem;
|
||||
|
||||
currentItem = item;
|
||||
if (!item) {
|
||||
|
@ -294,7 +315,7 @@ define(['playbackManager', 'dom', 'inputManager', 'datetime', 'itemHelper', 'med
|
|||
function setTitle(item, parentName) {
|
||||
Emby.Page.setTitle(parentName || '');
|
||||
|
||||
var documentTitle = parentName || (item ? item.Name : null);
|
||||
const documentTitle = parentName || (item ? item.Name : null);
|
||||
|
||||
if (documentTitle) {
|
||||
document.title = documentTitle;
|
||||
|
@ -302,10 +323,10 @@ define(['playbackManager', 'dom', 'inputManager', 'datetime', 'itemHelper', 'med
|
|||
}
|
||||
|
||||
function setPoster(item, secondaryItem) {
|
||||
var osdPoster = view.querySelector('.osdPoster');
|
||||
const osdPoster = view.querySelector('.osdPoster');
|
||||
|
||||
if (item) {
|
||||
var imgUrl = seriesImageUrl(item, {
|
||||
let imgUrl = seriesImageUrl(item, {
|
||||
maxWidth: osdPoster.clientWidth * 2,
|
||||
type: 'Primary'
|
||||
}) || seriesImageUrl(item, {
|
||||
|
@ -333,13 +354,21 @@ define(['playbackManager', 'dom', 'inputManager', 'datetime', 'itemHelper', 'med
|
|||
osdPoster.innerHTML = '';
|
||||
}
|
||||
|
||||
let osdLockCount = 0;
|
||||
|
||||
function showOsd() {
|
||||
slideDownToShow(headerElement);
|
||||
showMainOsdControls();
|
||||
startOsdHideTimer();
|
||||
if (!osdLockCount) {
|
||||
startOsdHideTimer();
|
||||
}
|
||||
}
|
||||
|
||||
function hideOsd() {
|
||||
if (osdLockCount) {
|
||||
return;
|
||||
}
|
||||
|
||||
slideUpToHide(headerElement);
|
||||
hideMainOsdControls();
|
||||
}
|
||||
|
@ -352,6 +381,19 @@ 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);
|
||||
|
@ -379,7 +421,7 @@ define(['playbackManager', 'dom', 'inputManager', 'datetime', 'itemHelper', 'med
|
|||
}
|
||||
|
||||
function onHideAnimationComplete(e) {
|
||||
var elem = e.target;
|
||||
const elem = e.target;
|
||||
if (elem != osdBottomElement)
|
||||
return;
|
||||
elem.classList.add('hide');
|
||||
|
@ -390,7 +432,7 @@ define(['playbackManager', 'dom', 'inputManager', 'datetime', 'itemHelper', 'med
|
|||
|
||||
function showMainOsdControls() {
|
||||
if (!currentVisibleMenu) {
|
||||
var elem = osdBottomElement;
|
||||
const elem = osdBottomElement;
|
||||
currentVisibleMenu = 'osd';
|
||||
clearHideAnimationEventListeners(elem);
|
||||
elem.classList.remove('hide');
|
||||
|
@ -407,7 +449,7 @@ define(['playbackManager', 'dom', 'inputManager', 'datetime', 'itemHelper', 'med
|
|||
|
||||
function hideMainOsdControls() {
|
||||
if ('osd' === currentVisibleMenu) {
|
||||
var elem = osdBottomElement;
|
||||
const elem = osdBottomElement;
|
||||
clearHideAnimationEventListeners(elem);
|
||||
elem.classList.add('videoOsdBottom-hidden');
|
||||
dom.addEventListener(elem, transitionEndEventName, onHideAnimationComplete, {
|
||||
|
@ -425,9 +467,9 @@ define(['playbackManager', 'dom', 'inputManager', 'datetime', 'itemHelper', 'med
|
|||
|
||||
function onPointerMove(e) {
|
||||
if ('mouse' === (e.pointerType || (layoutManager.mobile ? 'touch' : 'mouse'))) {
|
||||
var eventX = e.screenX || 0;
|
||||
var eventY = e.screenY || 0;
|
||||
var obj = lastPointerMoveData;
|
||||
const eventX = e.screenX || 0;
|
||||
const eventY = e.screenY || 0;
|
||||
const obj = lastPointerMoveData;
|
||||
|
||||
if (!obj) {
|
||||
lastPointerMoveData = {
|
||||
|
@ -448,7 +490,7 @@ define(['playbackManager', 'dom', 'inputManager', 'datetime', 'itemHelper', 'med
|
|||
}
|
||||
|
||||
function onInputCommand(e) {
|
||||
var player = currentPlayer;
|
||||
const player = currentPlayer;
|
||||
|
||||
switch (e.detail.command) {
|
||||
case 'left':
|
||||
|
@ -507,7 +549,7 @@ define(['playbackManager', 'dom', 'inputManager', 'datetime', 'itemHelper', 'med
|
|||
}
|
||||
|
||||
function onRecordingCommand() {
|
||||
var btnRecord = view.querySelector('.btnRecord');
|
||||
const btnRecord = view.querySelector('.btnRecord');
|
||||
|
||||
if (!btnRecord.classList.contains('hide')) {
|
||||
btnRecord.click();
|
||||
|
@ -534,7 +576,7 @@ define(['playbackManager', 'dom', 'inputManager', 'datetime', 'itemHelper', 'med
|
|||
}
|
||||
|
||||
function onStateChanged(event, state) {
|
||||
var player = this;
|
||||
const player = this;
|
||||
|
||||
if (state.NowPlayingItem) {
|
||||
isEnabled = true;
|
||||
|
@ -552,21 +594,21 @@ define(['playbackManager', 'dom', 'inputManager', 'datetime', 'itemHelper', 'med
|
|||
|
||||
function onVolumeChanged(e) {
|
||||
if (isEnabled) {
|
||||
var player = this;
|
||||
const player = this;
|
||||
updatePlayerVolumeState(player, player.isMuted(), player.getVolume());
|
||||
}
|
||||
}
|
||||
|
||||
function onPlaybackStart(e, state) {
|
||||
console.debug('nowplaying event: ' + e.type);
|
||||
var player = this;
|
||||
const player = this;
|
||||
onStateChanged.call(player, e, state);
|
||||
resetUpNextDialog();
|
||||
}
|
||||
|
||||
function resetUpNextDialog() {
|
||||
comingUpNextDisplayed = false;
|
||||
var dlg = currentUpNextDialog;
|
||||
const dlg = currentUpNextDialog;
|
||||
|
||||
if (dlg) {
|
||||
dlg.destroy();
|
||||
|
@ -586,8 +628,8 @@ define(['playbackManager', 'dom', 'inputManager', 'datetime', 'itemHelper', 'med
|
|||
}
|
||||
|
||||
function onMediaStreamsChanged(e) {
|
||||
var player = this;
|
||||
var state = playbackManager.getPlayerState(player);
|
||||
const player = this;
|
||||
const state = playbackManager.getPlayerState(player);
|
||||
onStateChanged.call(player, {
|
||||
type: 'init'
|
||||
}, state);
|
||||
|
@ -607,7 +649,7 @@ define(['playbackManager', 'dom', 'inputManager', 'datetime', 'itemHelper', 'med
|
|||
currentPlayer = player;
|
||||
if (!player) return;
|
||||
}
|
||||
var state = playbackManager.getPlayerState(player);
|
||||
const state = playbackManager.getPlayerState(player);
|
||||
onStateChanged.call(player, {
|
||||
type: 'init'
|
||||
}, state);
|
||||
|
@ -632,7 +674,7 @@ define(['playbackManager', 'dom', 'inputManager', 'datetime', 'itemHelper', 'med
|
|||
destroyStats();
|
||||
destroySubtitleSync();
|
||||
resetUpNextDialog();
|
||||
var player = currentPlayer;
|
||||
const player = currentPlayer;
|
||||
|
||||
if (player) {
|
||||
events.off(player, 'playbackstart', onPlaybackStart);
|
||||
|
@ -650,15 +692,15 @@ define(['playbackManager', 'dom', 'inputManager', 'datetime', 'itemHelper', 'med
|
|||
function onTimeUpdate(e) {
|
||||
// Test for 'currentItem' is required for Firefox since its player spams 'timeupdate' events even being at breakpoint
|
||||
if (isEnabled && currentItem) {
|
||||
var now = new Date().getTime();
|
||||
const now = new Date().getTime();
|
||||
|
||||
if (!(now - lastUpdateTime < 700)) {
|
||||
lastUpdateTime = now;
|
||||
var player = this;
|
||||
const player = this;
|
||||
currentRuntimeTicks = playbackManager.duration(player);
|
||||
var currentTime = playbackManager.currentTime(player);
|
||||
const currentTime = playbackManager.currentTime(player);
|
||||
updateTimeDisplay(currentTime, currentRuntimeTicks, playbackManager.playbackStartTime(player), playbackManager.getBufferedRanges(player));
|
||||
var item = currentItem;
|
||||
const item = currentItem;
|
||||
refreshProgramInfoIfNeeded(player, item);
|
||||
showComingUpNextIfNeeded(player, item, currentTime, currentRuntimeTicks);
|
||||
}
|
||||
|
@ -667,9 +709,9 @@ define(['playbackManager', 'dom', 'inputManager', 'datetime', 'itemHelper', 'med
|
|||
|
||||
function showComingUpNextIfNeeded(player, currentItem, currentTimeTicks, runtimeTicks) {
|
||||
if (runtimeTicks && currentTimeTicks && !comingUpNextDisplayed && !currentVisibleMenu && 'Episode' === currentItem.Type && userSettings.enableNextVideoInfoOverlay()) {
|
||||
var showAtSecondsLeft = runtimeTicks >= 3e10 ? 40 : runtimeTicks >= 24e9 ? 35 : 30;
|
||||
var showAtTicks = runtimeTicks - 1e3 * showAtSecondsLeft * 1e4;
|
||||
var timeRemainingTicks = runtimeTicks - currentTimeTicks;
|
||||
const showAtSecondsLeft = runtimeTicks >= 3e10 ? 40 : runtimeTicks >= 24e9 ? 35 : 30;
|
||||
const showAtTicks = runtimeTicks - 1e3 * showAtSecondsLeft * 1e4;
|
||||
const timeRemainingTicks = runtimeTicks - currentTimeTicks;
|
||||
|
||||
if (currentTimeTicks >= showAtTicks && runtimeTicks >= 6e9 && timeRemainingTicks >= 2e8) {
|
||||
showComingUpNext(player);
|
||||
|
@ -684,7 +726,7 @@ define(['playbackManager', 'dom', 'inputManager', 'datetime', 'itemHelper', 'med
|
|||
}
|
||||
|
||||
function showComingUpNext(player) {
|
||||
require(['upNextDialog'], function (UpNextDialog) {
|
||||
import('upNextDialog').then(({default: UpNextDialog}) => {
|
||||
if (!(currentVisibleMenu || currentUpNextDialog)) {
|
||||
currentVisibleMenu = 'upnext';
|
||||
comingUpNextDisplayed = true;
|
||||
|
@ -702,15 +744,15 @@ define(['playbackManager', 'dom', 'inputManager', 'datetime', 'itemHelper', 'med
|
|||
|
||||
function refreshProgramInfoIfNeeded(player, item) {
|
||||
if ('TvChannel' === item.Type) {
|
||||
var program = item.CurrentProgram;
|
||||
const program = item.CurrentProgram;
|
||||
|
||||
if (program && program.EndDate) {
|
||||
try {
|
||||
var endDate = datetime.parseISO8601Date(program.EndDate);
|
||||
const endDate = datetime.parseISO8601Date(program.EndDate);
|
||||
|
||||
if (new Date().getTime() >= endDate.getTime()) {
|
||||
console.debug('program info needs to be refreshed');
|
||||
var state = playbackManager.getPlayerState(player);
|
||||
const state = playbackManager.getPlayerState(player);
|
||||
onStateChanged.call(player, {
|
||||
type: 'init'
|
||||
}, state);
|
||||
|
@ -738,9 +780,9 @@ define(['playbackManager', 'dom', 'inputManager', 'datetime', 'itemHelper', 'med
|
|||
}
|
||||
|
||||
function updatePlayerStateInternal(event, player, state) {
|
||||
var playState = state.PlayState || {};
|
||||
const playState = state.PlayState || {};
|
||||
updatePlayPauseState(playState.IsPaused);
|
||||
var supportedCommands = playbackManager.getSupportedCommands(player);
|
||||
const supportedCommands = playbackManager.getSupportedCommands(player);
|
||||
currentPlayerSupportedCommands = supportedCommands;
|
||||
supportsBrightnessChange = -1 !== supportedCommands.indexOf('SetBrightness');
|
||||
updatePlayerVolumeState(player, playState.IsMuted, playState.VolumeLevel);
|
||||
|
@ -751,7 +793,7 @@ define(['playbackManager', 'dom', 'inputManager', 'datetime', 'itemHelper', 'med
|
|||
|
||||
btnFastForward.disabled = !playState.CanSeek;
|
||||
btnRewind.disabled = !playState.CanSeek;
|
||||
var nowPlayingItem = state.NowPlayingItem || {};
|
||||
const nowPlayingItem = state.NowPlayingItem || {};
|
||||
playbackStartTimeTicks = playState.PlaybackStartTimeTicks;
|
||||
updateTimeDisplay(playState.PositionTicks, nowPlayingItem.RunTimeTicks, playState.PlaybackStartTimeTicks, playState.BufferedRanges || []);
|
||||
updateNowPlayingInfo(player, state);
|
||||
|
@ -762,7 +804,7 @@ define(['playbackManager', 'dom', 'inputManager', 'datetime', 'itemHelper', 'med
|
|||
view.querySelector('.btnVideoOsdSettings').classList.add('hide');
|
||||
}
|
||||
|
||||
var isProgressClear = state.MediaSource && null == state.MediaSource.RunTimeTicks;
|
||||
const isProgressClear = state.MediaSource && null == state.MediaSource.RunTimeTicks;
|
||||
nowPlayingPositionSlider.setIsClear(isProgressClear);
|
||||
|
||||
if (nowPlayingItem.RunTimeTicks) {
|
||||
|
@ -799,12 +841,12 @@ define(['playbackManager', 'dom', 'inputManager', 'datetime', 'itemHelper', 'med
|
|||
if (enableProgressByTimeOfDay) {
|
||||
if (nowPlayingPositionSlider && !nowPlayingPositionSlider.dragging) {
|
||||
if (programStartDateMs && programEndDateMs) {
|
||||
var currentTimeMs = (playbackStartTimeTicks + (positionTicks || 0)) / 1e4;
|
||||
var programRuntimeMs = programEndDateMs - programStartDateMs;
|
||||
const currentTimeMs = (playbackStartTimeTicks + (positionTicks || 0)) / 1e4;
|
||||
const programRuntimeMs = programEndDateMs - programStartDateMs;
|
||||
|
||||
if (nowPlayingPositionSlider.value = getDisplayPercentByTimeOfDay(programStartDateMs, programRuntimeMs, currentTimeMs), bufferedRanges.length) {
|
||||
var rangeStart = getDisplayPercentByTimeOfDay(programStartDateMs, programRuntimeMs, (playbackStartTimeTicks + (bufferedRanges[0].start || 0)) / 1e4);
|
||||
var rangeEnd = getDisplayPercentByTimeOfDay(programStartDateMs, programRuntimeMs, (playbackStartTimeTicks + (bufferedRanges[0].end || 0)) / 1e4);
|
||||
const rangeStart = getDisplayPercentByTimeOfDay(programStartDateMs, programRuntimeMs, (playbackStartTimeTicks + (bufferedRanges[0].start || 0)) / 1e4);
|
||||
const rangeEnd = getDisplayPercentByTimeOfDay(programStartDateMs, programRuntimeMs, (playbackStartTimeTicks + (bufferedRanges[0].end || 0)) / 1e4);
|
||||
nowPlayingPositionSlider.setBufferedRanges([{
|
||||
start: rangeStart,
|
||||
end: rangeEnd
|
||||
|
@ -823,7 +865,7 @@ define(['playbackManager', 'dom', 'inputManager', 'datetime', 'itemHelper', 'med
|
|||
} else {
|
||||
if (nowPlayingPositionSlider && !nowPlayingPositionSlider.dragging) {
|
||||
if (runtimeTicks) {
|
||||
var pct = positionTicks / runtimeTicks;
|
||||
let pct = positionTicks / runtimeTicks;
|
||||
pct *= 100;
|
||||
nowPlayingPositionSlider.value = pct;
|
||||
} else {
|
||||
|
@ -847,9 +889,9 @@ define(['playbackManager', 'dom', 'inputManager', 'datetime', 'itemHelper', 'med
|
|||
}
|
||||
|
||||
function updatePlayerVolumeState(player, isMuted, volumeLevel) {
|
||||
var supportedCommands = currentPlayerSupportedCommands;
|
||||
var showMuteButton = true;
|
||||
var showVolumeSlider = true;
|
||||
const supportedCommands = currentPlayerSupportedCommands;
|
||||
let showMuteButton = true;
|
||||
let showVolumeSlider = true;
|
||||
|
||||
if (-1 === supportedCommands.indexOf('Mute')) {
|
||||
showMuteButton = false;
|
||||
|
@ -897,8 +939,8 @@ define(['playbackManager', 'dom', 'inputManager', 'datetime', 'itemHelper', 'med
|
|||
}
|
||||
|
||||
function updatePlaylist(player) {
|
||||
var btnPreviousTrack = view.querySelector('.btnPreviousTrack');
|
||||
var btnNextTrack = view.querySelector('.btnNextTrack');
|
||||
const btnPreviousTrack = view.querySelector('.btnPreviousTrack');
|
||||
const btnNextTrack = view.querySelector('.btnNextTrack');
|
||||
btnPreviousTrack.classList.remove('hide');
|
||||
btnNextTrack.classList.remove('hide');
|
||||
btnNextTrack.disabled = false;
|
||||
|
@ -911,7 +953,7 @@ define(['playbackManager', 'dom', 'inputManager', 'datetime', 'itemHelper', 'med
|
|||
return;
|
||||
}
|
||||
|
||||
var html = datetime.getDisplayRunningTime(ticks);
|
||||
let html = datetime.getDisplayRunningTime(ticks);
|
||||
|
||||
if (divider) {
|
||||
html = ' / ' + html;
|
||||
|
@ -921,15 +963,15 @@ define(['playbackManager', 'dom', 'inputManager', 'datetime', 'itemHelper', 'med
|
|||
}
|
||||
|
||||
function onSettingsButtonClick(e) {
|
||||
var btn = this;
|
||||
const btn = this;
|
||||
|
||||
require(['playerSettingsMenu'], function (playerSettingsMenu) {
|
||||
var player = currentPlayer;
|
||||
import('playerSettingsMenu').then(({default: playerSettingsMenu}) => {
|
||||
const player = currentPlayer;
|
||||
|
||||
if (player) {
|
||||
|
||||
// show subtitle offset feature only if player and media support it
|
||||
var showSubOffset = playbackManager.supportSubtitleOffset(player) &&
|
||||
const showSubOffset = playbackManager.supportSubtitleOffset(player) &&
|
||||
playbackManager.canHandleOffsetOnCurrentSubtitle(player);
|
||||
|
||||
playerSettingsMenu.show({
|
||||
|
@ -948,7 +990,7 @@ define(['playbackManager', 'dom', 'inputManager', 'datetime', 'itemHelper', 'med
|
|||
if ('stats' === selectedOption) {
|
||||
toggleStats();
|
||||
} else if ('suboffset' === selectedOption) {
|
||||
var player = currentPlayer;
|
||||
const player = currentPlayer;
|
||||
if (player) {
|
||||
playbackManager.enableShowingSubtitleOffset(player);
|
||||
toggleSubtitleSync();
|
||||
|
@ -957,8 +999,8 @@ define(['playbackManager', 'dom', 'inputManager', 'datetime', 'itemHelper', 'med
|
|||
}
|
||||
|
||||
function toggleStats() {
|
||||
require(['playerStats'], function (PlayerStats) {
|
||||
var player = currentPlayer;
|
||||
import('playerStats').then(({default: PlayerStats}) => {
|
||||
const player = currentPlayer;
|
||||
|
||||
if (player) {
|
||||
if (statsOverlay) {
|
||||
|
@ -980,11 +1022,11 @@ define(['playbackManager', 'dom', 'inputManager', 'datetime', 'itemHelper', 'med
|
|||
}
|
||||
|
||||
function showAudioTrackSelection() {
|
||||
var player = currentPlayer;
|
||||
var audioTracks = playbackManager.audioTracks(player);
|
||||
var currentIndex = playbackManager.getAudioStreamIndex(player);
|
||||
var menuItems = audioTracks.map(function (stream) {
|
||||
var opt = {
|
||||
const player = currentPlayer;
|
||||
const audioTracks = playbackManager.audioTracks(player);
|
||||
const currentIndex = playbackManager.getAudioStreamIndex(player);
|
||||
const menuItems = audioTracks.map(function (stream) {
|
||||
const opt = {
|
||||
name: stream.DisplayTitle,
|
||||
id: stream.Index
|
||||
};
|
||||
|
@ -995,15 +1037,15 @@ define(['playbackManager', 'dom', 'inputManager', 'datetime', 'itemHelper', 'med
|
|||
|
||||
return opt;
|
||||
});
|
||||
var positionTo = this;
|
||||
const positionTo = this;
|
||||
|
||||
require(['actionsheet'], function (actionsheet) {
|
||||
import('actionsheet').then(({default: actionsheet}) => {
|
||||
actionsheet.show({
|
||||
items: menuItems,
|
||||
title: globalize.translate('Audio'),
|
||||
positionTo: positionTo
|
||||
}).then(function (id) {
|
||||
var index = parseInt(id);
|
||||
const index = parseInt(id);
|
||||
|
||||
if (index !== currentIndex) {
|
||||
playbackManager.setAudioStreamIndex(index, player);
|
||||
|
@ -1013,9 +1055,9 @@ define(['playbackManager', 'dom', 'inputManager', 'datetime', 'itemHelper', 'med
|
|||
}
|
||||
|
||||
function showSubtitleTrackSelection() {
|
||||
var player = currentPlayer;
|
||||
var streams = playbackManager.subtitleTracks(player);
|
||||
var currentIndex = playbackManager.getSubtitleStreamIndex(player);
|
||||
const player = currentPlayer;
|
||||
const streams = playbackManager.subtitleTracks(player);
|
||||
let currentIndex = playbackManager.getSubtitleStreamIndex(player);
|
||||
|
||||
if (null == currentIndex) {
|
||||
currentIndex = -1;
|
||||
|
@ -1025,8 +1067,8 @@ define(['playbackManager', 'dom', 'inputManager', 'datetime', 'itemHelper', 'med
|
|||
Index: -1,
|
||||
DisplayTitle: globalize.translate('Off')
|
||||
});
|
||||
var menuItems = streams.map(function (stream) {
|
||||
var opt = {
|
||||
const menuItems = streams.map(function (stream) {
|
||||
const opt = {
|
||||
name: stream.DisplayTitle,
|
||||
id: stream.Index
|
||||
};
|
||||
|
@ -1037,15 +1079,15 @@ define(['playbackManager', 'dom', 'inputManager', 'datetime', 'itemHelper', 'med
|
|||
|
||||
return opt;
|
||||
});
|
||||
var positionTo = this;
|
||||
const positionTo = this;
|
||||
|
||||
require(['actionsheet'], function (actionsheet) {
|
||||
import('actionsheet').then(({default: actionsheet}) => {
|
||||
actionsheet.show({
|
||||
title: globalize.translate('Subtitles'),
|
||||
items: menuItems,
|
||||
positionTo: positionTo
|
||||
}).then(function (id) {
|
||||
var index = parseInt(id);
|
||||
const index = parseInt(id);
|
||||
|
||||
if (index !== currentIndex) {
|
||||
playbackManager.setSubtitleStreamIndex(index, player);
|
||||
|
@ -1057,8 +1099,8 @@ define(['playbackManager', 'dom', 'inputManager', 'datetime', 'itemHelper', 'med
|
|||
}
|
||||
|
||||
function toggleSubtitleSync(action) {
|
||||
require(['subtitleSync'], function (SubtitleSync) {
|
||||
var player = currentPlayer;
|
||||
import('subtitleSync').then(({default: SubtitleSync}) => {
|
||||
const player = currentPlayer;
|
||||
if (subtitleSyncOverlay) {
|
||||
subtitleSyncOverlay.toggle(action);
|
||||
} else if (player) {
|
||||
|
@ -1078,12 +1120,12 @@ define(['playbackManager', 'dom', 'inputManager', 'datetime', 'itemHelper', 'med
|
|||
* Clicked element.
|
||||
* To skip 'click' handling on Firefox/Edge.
|
||||
*/
|
||||
var clickedElement;
|
||||
let clickedElement;
|
||||
|
||||
function onWindowKeyDown(e) {
|
||||
function onKeyDown(e) {
|
||||
clickedElement = e.srcElement;
|
||||
|
||||
var key = keyboardnavigation.getKeyName(e);
|
||||
const key = keyboardnavigation.getKeyName(e);
|
||||
|
||||
if (!currentVisibleMenu && 32 === e.keyCode) {
|
||||
playbackManager.playPause(currentPlayer);
|
||||
|
@ -1187,19 +1229,37 @@ define(['playbackManager', 'dom', 'inputManager', 'datetime', 'itemHelper', 'med
|
|||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
var percent = parseInt(key, 10) * 10;
|
||||
case '9': {
|
||||
const percent = parseInt(key, 10) * 10;
|
||||
playbackManager.seekPercent(percent, currentPlayer);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function onKeyDownCapture() {
|
||||
// Restart hide timer if OSD is currently visible
|
||||
if (currentVisibleMenu) {
|
||||
showOsd();
|
||||
}
|
||||
}
|
||||
|
||||
function onWindowMouseDown(e) {
|
||||
clickedElement = e.srcElement;
|
||||
lockOsd();
|
||||
}
|
||||
|
||||
function onWindowMouseUp() {
|
||||
unlockOsd();
|
||||
}
|
||||
|
||||
function onWindowTouchStart(e) {
|
||||
clickedElement = e.srcElement;
|
||||
lockOsd();
|
||||
}
|
||||
|
||||
function onWindowTouchEnd() {
|
||||
unlockOsd();
|
||||
}
|
||||
|
||||
function getImgUrl(item, chapter, index, maxWidth, apiClient) {
|
||||
|
@ -1216,11 +1276,11 @@ define(['playbackManager', 'dom', 'inputManager', 'datetime', 'itemHelper', 'med
|
|||
}
|
||||
|
||||
function getChapterBubbleHtml(apiClient, item, chapters, positionTicks) {
|
||||
var chapter;
|
||||
var index = -1;
|
||||
let chapter;
|
||||
let index = -1;
|
||||
|
||||
for (var i = 0, length = chapters.length; i < length; i++) {
|
||||
var currentChapter = chapters[i];
|
||||
for (let i = 0, length = chapters.length; i < length; i++) {
|
||||
const currentChapter = chapters[i];
|
||||
|
||||
if (positionTicks >= currentChapter.StartPositionTicks) {
|
||||
chapter = currentChapter;
|
||||
|
@ -1232,10 +1292,10 @@ define(['playbackManager', 'dom', 'inputManager', 'datetime', 'itemHelper', 'med
|
|||
return null;
|
||||
}
|
||||
|
||||
var src = getImgUrl(item, chapter, index, 400, apiClient);
|
||||
const src = getImgUrl(item, chapter, index, 400, apiClient);
|
||||
|
||||
if (src) {
|
||||
var html = '<div class="chapterThumbContainer">';
|
||||
let html = '<div class="chapterThumbContainer">';
|
||||
html += '<img class="chapterThumb" src="' + src + '" />';
|
||||
html += '<div class="chapterThumbTextContainer">';
|
||||
html += '<div class="chapterThumbText chapterThumbText-dim">';
|
||||
|
@ -1251,15 +1311,15 @@ define(['playbackManager', 'dom', 'inputManager', 'datetime', 'itemHelper', 'med
|
|||
return null;
|
||||
}
|
||||
|
||||
var playPauseClickTimeout;
|
||||
let playPauseClickTimeout;
|
||||
function onViewHideStopPlayback() {
|
||||
if (playbackManager.isPlayingVideo()) {
|
||||
require(['shell'], function (shell) {
|
||||
import('shell').then(({default: shell}) => {
|
||||
shell.disableFullscreen();
|
||||
});
|
||||
|
||||
clearTimeout(playPauseClickTimeout);
|
||||
var player = currentPlayer;
|
||||
const player = currentPlayer;
|
||||
view.removeEventListener('viewbeforehide', onViewHideStopPlayback);
|
||||
releaseCurrentPlayer();
|
||||
playbackManager.stop(player);
|
||||
|
@ -1274,47 +1334,49 @@ define(['playbackManager', 'dom', 'inputManager', 'datetime', 'itemHelper', 'med
|
|||
}
|
||||
}
|
||||
|
||||
require(['shell'], function (shell) {
|
||||
import('shell').then(({default: shell}) => {
|
||||
shell.enableFullscreen();
|
||||
});
|
||||
|
||||
var currentPlayer;
|
||||
var comingUpNextDisplayed;
|
||||
var currentUpNextDialog;
|
||||
var isEnabled;
|
||||
var currentItem;
|
||||
var recordingButtonManager;
|
||||
var enableProgressByTimeOfDay;
|
||||
var supportsBrightnessChange;
|
||||
var currentVisibleMenu;
|
||||
var statsOverlay;
|
||||
var osdHideTimeout;
|
||||
var lastPointerMoveData;
|
||||
var self = this;
|
||||
var currentPlayerSupportedCommands = [];
|
||||
var currentRuntimeTicks = 0;
|
||||
var lastUpdateTime = 0;
|
||||
var programStartDateMs = 0;
|
||||
var programEndDateMs = 0;
|
||||
var playbackStartTimeTicks = 0;
|
||||
var subtitleSyncOverlay;
|
||||
var nowPlayingVolumeSlider = view.querySelector('.osdVolumeSlider');
|
||||
var nowPlayingVolumeSliderContainer = view.querySelector('.osdVolumeSliderContainer');
|
||||
var nowPlayingPositionSlider = view.querySelector('.osdPositionSlider');
|
||||
var nowPlayingPositionText = view.querySelector('.osdPositionText');
|
||||
var nowPlayingDurationText = view.querySelector('.osdDurationText');
|
||||
var startTimeText = view.querySelector('.startTimeText');
|
||||
var endTimeText = view.querySelector('.endTimeText');
|
||||
var endsAtText = view.querySelector('.endsAtText');
|
||||
var btnRewind = view.querySelector('.btnRewind');
|
||||
var btnFastForward = view.querySelector('.btnFastForward');
|
||||
var transitionEndEventName = dom.whichTransitionEvent();
|
||||
var headerElement = document.querySelector('.skinHeader');
|
||||
var osdBottomElement = document.querySelector('.videoOsdBottom-maincontrols');
|
||||
let currentPlayer;
|
||||
let comingUpNextDisplayed;
|
||||
let currentUpNextDialog;
|
||||
let isEnabled;
|
||||
let currentItem;
|
||||
let recordingButtonManager;
|
||||
let enableProgressByTimeOfDay;
|
||||
let supportsBrightnessChange;
|
||||
let currentVisibleMenu;
|
||||
let statsOverlay;
|
||||
let osdHideTimeout;
|
||||
let lastPointerMoveData;
|
||||
const self = this;
|
||||
let currentPlayerSupportedCommands = [];
|
||||
let currentRuntimeTicks = 0;
|
||||
let lastUpdateTime = 0;
|
||||
let programStartDateMs = 0;
|
||||
let programEndDateMs = 0;
|
||||
let playbackStartTimeTicks = 0;
|
||||
let subtitleSyncOverlay;
|
||||
const nowPlayingVolumeSlider = view.querySelector('.osdVolumeSlider');
|
||||
const nowPlayingVolumeSliderContainer = view.querySelector('.osdVolumeSliderContainer');
|
||||
const nowPlayingPositionSlider = view.querySelector('.osdPositionSlider');
|
||||
const nowPlayingPositionText = view.querySelector('.osdPositionText');
|
||||
const nowPlayingDurationText = view.querySelector('.osdDurationText');
|
||||
const startTimeText = view.querySelector('.startTimeText');
|
||||
const endTimeText = view.querySelector('.endTimeText');
|
||||
const endsAtText = view.querySelector('.endsAtText');
|
||||
const btnRewind = view.querySelector('.btnRewind');
|
||||
const btnFastForward = view.querySelector('.btnFastForward');
|
||||
const transitionEndEventName = dom.whichTransitionEvent();
|
||||
const headerElement = document.querySelector('.skinHeader');
|
||||
const osdBottomElement = document.querySelector('.videoOsdBottom-maincontrols');
|
||||
|
||||
nowPlayingPositionSlider.enableKeyboardDragging();
|
||||
nowPlayingVolumeSlider.enableKeyboardDragging();
|
||||
|
||||
if (layoutManager.tv) {
|
||||
nowPlayingPositionSlider.classList.add('focusable');
|
||||
nowPlayingPositionSlider.enableKeyboardDragging();
|
||||
}
|
||||
|
||||
view.addEventListener('viewbeforeshow', function (e) {
|
||||
|
@ -1325,23 +1387,35 @@ define(['playbackManager', 'dom', 'inputManager', 'datetime', 'itemHelper', 'med
|
|||
try {
|
||||
events.on(playbackManager, 'playerchange', onPlayerChange);
|
||||
bindToPlayer(playbackManager.getCurrentPlayer());
|
||||
/* eslint-disable-next-line compat/compat */
|
||||
dom.addEventListener(document, window.PointerEvent ? 'pointermove' : 'mousemove', onPointerMove, {
|
||||
passive: true
|
||||
});
|
||||
showOsd();
|
||||
inputManager.on(window, onInputCommand);
|
||||
dom.addEventListener(window, 'keydown', onWindowKeyDown, {
|
||||
document.addEventListener('keydown', onKeyDown);
|
||||
dom.addEventListener(document, 'keydown', onKeyDownCapture, {
|
||||
capture: true
|
||||
});
|
||||
/* eslint-disable-next-line compat/compat */
|
||||
dom.addEventListener(window, window.PointerEvent ? 'pointerdown' : 'mousedown', onWindowMouseDown, {
|
||||
passive: true
|
||||
});
|
||||
/* eslint-disable-next-line compat/compat */
|
||||
dom.addEventListener(window, window.PointerEvent ? 'pointerup' : 'mouseup', onWindowMouseUp, {
|
||||
passive: true
|
||||
});
|
||||
dom.addEventListener(window, 'touchstart', onWindowTouchStart, {
|
||||
passive: true
|
||||
});
|
||||
['touchend', 'touchcancel'].forEach((event) => {
|
||||
dom.addEventListener(window, event, onWindowTouchEnd, {
|
||||
passive: true
|
||||
});
|
||||
});
|
||||
} catch (e) {
|
||||
require(['appRouter'], function(appRouter) {
|
||||
appRouter.showDirect('/');
|
||||
import('appRouter').then(({default: appRouter}) => {
|
||||
appRouter.goHome();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
@ -1350,18 +1424,30 @@ define(['playbackManager', 'dom', 'inputManager', 'datetime', 'itemHelper', 'med
|
|||
statsOverlay.enabled(false);
|
||||
}
|
||||
|
||||
dom.removeEventListener(window, 'keydown', onWindowKeyDown, {
|
||||
document.removeEventListener('keydown', onKeyDown);
|
||||
dom.removeEventListener(document, 'keydown', onKeyDownCapture, {
|
||||
capture: true
|
||||
});
|
||||
/* eslint-disable-next-line compat/compat */
|
||||
dom.removeEventListener(window, window.PointerEvent ? 'pointerdown' : 'mousedown', onWindowMouseDown, {
|
||||
passive: true
|
||||
});
|
||||
/* eslint-disable-next-line compat/compat */
|
||||
dom.removeEventListener(window, window.PointerEvent ? 'pointerup' : 'mouseup', onWindowMouseUp, {
|
||||
passive: true
|
||||
});
|
||||
dom.removeEventListener(window, 'touchstart', onWindowTouchStart, {
|
||||
passive: true
|
||||
});
|
||||
['touchend', 'touchcancel'].forEach((event) => {
|
||||
dom.removeEventListener(window, event, onWindowTouchEnd, {
|
||||
passive: true
|
||||
});
|
||||
});
|
||||
stopOsdHideTimer();
|
||||
headerElement.classList.remove('osdHeader');
|
||||
headerElement.classList.remove('osdHeader-hidden');
|
||||
/* eslint-disable-next-line compat/compat */
|
||||
dom.removeEventListener(document, window.PointerEvent ? 'pointermove' : 'mousemove', onPointerMove, {
|
||||
passive: true
|
||||
});
|
||||
|
@ -1396,14 +1482,15 @@ define(['playbackManager', 'dom', 'inputManager', 'datetime', 'itemHelper', 'med
|
|||
destroyStats();
|
||||
destroySubtitleSync();
|
||||
});
|
||||
var lastPointerDown = 0;
|
||||
let lastPointerDown = 0;
|
||||
/* eslint-disable-next-line compat/compat */
|
||||
dom.addEventListener(view, window.PointerEvent ? 'pointerdown' : 'click', function (e) {
|
||||
if (dom.parentWithClass(e.target, ['videoOsdBottom', 'upNextContainer'])) {
|
||||
return void showOsd();
|
||||
}
|
||||
|
||||
var pointerType = e.pointerType || (layoutManager.mobile ? 'touch' : 'mouse');
|
||||
var now = new Date().getTime();
|
||||
const pointerType = e.pointerType || (layoutManager.mobile ? 'touch' : 'mouse');
|
||||
const now = new Date().getTime();
|
||||
|
||||
switch (pointerType) {
|
||||
case 'touch':
|
||||
|
@ -1441,31 +1528,28 @@ define(['playbackManager', 'dom', 'inputManager', 'datetime', 'itemHelper', 'med
|
|||
if (browser.touch) {
|
||||
dom.addEventListener(view, 'dblclick', onDoubleClick, {});
|
||||
} else {
|
||||
var options = { passive: true };
|
||||
const options = { passive: true };
|
||||
dom.addEventListener(view, 'dblclick', function () {
|
||||
playbackManager.toggleFullscreen(currentPlayer);
|
||||
}, options);
|
||||
}
|
||||
|
||||
function setVolume() {
|
||||
playbackManager.setVolume(this.value, currentPlayer);
|
||||
}
|
||||
|
||||
view.querySelector('.buttonMute').addEventListener('click', function () {
|
||||
playbackManager.toggleMute(currentPlayer);
|
||||
});
|
||||
nowPlayingVolumeSlider.addEventListener('change', setVolume);
|
||||
nowPlayingVolumeSlider.addEventListener('mousemove', setVolume);
|
||||
nowPlayingVolumeSlider.addEventListener('touchmove', setVolume);
|
||||
|
||||
nowPlayingVolumeSlider.addEventListener('input', (e) => {
|
||||
playbackManager.setVolume(e.target.value, currentPlayer);
|
||||
});
|
||||
|
||||
nowPlayingPositionSlider.addEventListener('change', function () {
|
||||
var player = currentPlayer;
|
||||
const player = currentPlayer;
|
||||
|
||||
if (player) {
|
||||
var newPercent = parseFloat(this.value);
|
||||
const newPercent = parseFloat(this.value);
|
||||
|
||||
if (enableProgressByTimeOfDay) {
|
||||
var seekAirTimeTicks = newPercent / 100 * (programEndDateMs - programStartDateMs) * 1e4;
|
||||
let seekAirTimeTicks = newPercent / 100 * (programEndDateMs - programStartDateMs) * 1e4;
|
||||
seekAirTimeTicks += 1e4 * programStartDateMs;
|
||||
seekAirTimeTicks -= playbackStartTimeTicks;
|
||||
playbackManager.seek(seekAirTimeTicks, player);
|
||||
|
@ -1479,7 +1563,7 @@ define(['playbackManager', 'dom', 'inputManager', 'datetime', 'itemHelper', 'med
|
|||
showOsd();
|
||||
if (enableProgressByTimeOfDay) {
|
||||
if (programStartDateMs && programEndDateMs) {
|
||||
var ms = programEndDateMs - programStartDateMs;
|
||||
let ms = programEndDateMs - programStartDateMs;
|
||||
ms /= 100;
|
||||
ms *= value;
|
||||
ms += programStartDateMs;
|
||||
|
@ -1493,13 +1577,13 @@ define(['playbackManager', 'dom', 'inputManager', 'datetime', 'itemHelper', 'med
|
|||
return '--:--';
|
||||
}
|
||||
|
||||
var ticks = currentRuntimeTicks;
|
||||
let ticks = currentRuntimeTicks;
|
||||
ticks /= 100;
|
||||
ticks *= value;
|
||||
var item = currentItem;
|
||||
const item = currentItem;
|
||||
|
||||
if (item && item.Chapters && item.Chapters.length && item.Chapters[0].ImageTag) {
|
||||
var html = getChapterBubbleHtml(connectionManager.getApiClient(item.ServerId), item, item.Chapters, ticks);
|
||||
let html = getChapterBubbleHtml(connectionManager.getApiClient(item.ServerId), item, item.Chapters, ticks);
|
||||
|
||||
if (html) {
|
||||
return html;
|
||||
|
@ -1532,8 +1616,13 @@ define(['playbackManager', 'dom', 'inputManager', 'datetime', 'itemHelper', 'med
|
|||
|
||||
if (browser.touch) {
|
||||
(function () {
|
||||
<<<<<<< HEAD
|
||||
require(['touchHelper'], function (TouchHelper) {
|
||||
self.touchHelper = new TouchHelper.default(view, {
|
||||
=======
|
||||
import('touchHelper').then(({default: TouchHelper}) => {
|
||||
self.touchHelper = new TouchHelper(view, {
|
||||
>>>>>>> upstream/master
|
||||
swipeYThreshold: 30,
|
||||
triggerOnMove: true,
|
||||
preventDefaultOnMove: true,
|
||||
|
@ -1544,5 +1633,6 @@ define(['playbackManager', 'dom', 'inputManager', 'datetime', 'itemHelper', 'med
|
|||
});
|
||||
})();
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
|
|
@ -1,20 +1,23 @@
|
|||
define(['displaySettings', 'userSettings', 'autoFocuser'], function (DisplaySettings, userSettings, autoFocuser) {
|
||||
'use strict';
|
||||
import DisplaySettings from 'displaySettings';
|
||||
import * as userSettings from 'userSettings';
|
||||
import autoFocuser from 'autoFocuser';
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
// Shortcuts
|
||||
const UserSettings = userSettings.UserSettings;
|
||||
|
||||
return function (view, params) {
|
||||
export default function (view, params) {
|
||||
function onBeforeUnload(e) {
|
||||
if (hasChanges) {
|
||||
e.returnValue = 'You currently have unsaved changes. Are you sure you wish to leave?';
|
||||
}
|
||||
}
|
||||
|
||||
var settingsInstance;
|
||||
var hasChanges;
|
||||
var userId = params.userId || ApiClient.getCurrentUserId();
|
||||
var currentSettings = userId === ApiClient.getCurrentUserId() ? userSettings : new UserSettings();
|
||||
let settingsInstance;
|
||||
let hasChanges;
|
||||
const userId = params.userId || ApiClient.getCurrentUserId();
|
||||
const currentSettings = userId === ApiClient.getCurrentUserId() ? userSettings : new UserSettings();
|
||||
view.addEventListener('viewshow', function () {
|
||||
window.addEventListener('beforeunload', onBeforeUnload);
|
||||
|
||||
|
@ -26,28 +29,23 @@ define(['displaySettings', 'userSettings', 'autoFocuser'], function (DisplaySett
|
|||
userId: userId,
|
||||
element: view.querySelector('.settingsContainer'),
|
||||
userSettings: currentSettings,
|
||||
enableSaveButton: false,
|
||||
enableSaveConfirmation: false,
|
||||
enableSaveButton: true,
|
||||
enableSaveConfirmation: true,
|
||||
autoFocus: autoFocuser.isEnabled()
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
view.addEventListener('change', function () {
|
||||
hasChanges = true;
|
||||
});
|
||||
view.addEventListener('viewbeforehide', function () {
|
||||
window.removeEventListener('beforeunload', onBeforeUnload);
|
||||
hasChanges = false;
|
||||
|
||||
if (settingsInstance) {
|
||||
settingsInstance.submit();
|
||||
}
|
||||
});
|
||||
view.addEventListener('viewdestroy', function () {
|
||||
if (settingsInstance) {
|
||||
settingsInstance.destroy();
|
||||
settingsInstance = null;
|
||||
}
|
||||
});
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
|
|
@ -1,20 +1,27 @@
|
|||
define(['homescreenSettings', 'dom', 'globalize', 'loading', 'userSettings', 'autoFocuser', 'listViewStyle'], function (HomescreenSettings, dom, globalize, loading, userSettings, autoFocuser) {
|
||||
'use strict';
|
||||
import HomescreenSettings from 'homescreenSettings';
|
||||
import dom from 'dom';
|
||||
import globalize from 'globalize';
|
||||
import loading from 'loading';
|
||||
import * as userSettings from 'userSettings';
|
||||
import autoFocuser from 'autoFocuser';
|
||||
import 'listViewStyle';
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
// Shortcuts
|
||||
const UserSettings = userSettings.UserSettings;
|
||||
|
||||
return function (view, params) {
|
||||
export default function (view, params) {
|
||||
function onBeforeUnload(e) {
|
||||
if (hasChanges) {
|
||||
e.returnValue = 'You currently have unsaved changes. Are you sure you wish to leave?';
|
||||
}
|
||||
}
|
||||
|
||||
var homescreenSettingsInstance;
|
||||
var hasChanges;
|
||||
var userId = params.userId || ApiClient.getCurrentUserId();
|
||||
var currentSettings = userId === ApiClient.getCurrentUserId() ? userSettings : new UserSettings();
|
||||
let homescreenSettingsInstance;
|
||||
let hasChanges;
|
||||
const userId = params.userId || ApiClient.getCurrentUserId();
|
||||
const currentSettings = userId === ApiClient.getCurrentUserId() ? userSettings : new UserSettings();
|
||||
view.addEventListener('viewshow', function () {
|
||||
window.addEventListener('beforeunload', onBeforeUnload);
|
||||
|
||||
|
@ -26,27 +33,23 @@ define(['homescreenSettings', 'dom', 'globalize', 'loading', 'userSettings', 'au
|
|||
userId: userId,
|
||||
element: view.querySelector('.homeScreenSettingsContainer'),
|
||||
userSettings: currentSettings,
|
||||
enableSaveButton: false,
|
||||
enableSaveConfirmation: false,
|
||||
enableSaveButton: true,
|
||||
enableSaveConfirmation: true,
|
||||
autoFocus: autoFocuser.isEnabled()
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
view.addEventListener('change', function () {
|
||||
hasChanges = true;
|
||||
});
|
||||
view.addEventListener('viewbeforehide', function () {
|
||||
hasChanges = false;
|
||||
|
||||
if (homescreenSettingsInstance) {
|
||||
homescreenSettingsInstance.submit();
|
||||
}
|
||||
});
|
||||
view.addEventListener('viewdestroy', function () {
|
||||
if (homescreenSettingsInstance) {
|
||||
homescreenSettingsInstance.destroy();
|
||||
homescreenSettingsInstance = null;
|
||||
}
|
||||
});
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
|
|
@ -1,20 +1,27 @@
|
|||
define(['playbackSettings', 'dom', 'globalize', 'loading', 'userSettings', 'autoFocuser', 'listViewStyle'], function (PlaybackSettings, dom, globalize, loading, userSettings, autoFocuser) {
|
||||
'use strict';
|
||||
import PlaybackSettings from 'playbackSettings';
|
||||
import dom from 'dom';
|
||||
import globalize from 'globalize';
|
||||
import loading from 'loading';
|
||||
import * as userSettings from 'userSettings';
|
||||
import autoFocuser from 'autoFocuser';
|
||||
import 'listViewStyle';
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
// Shortcuts
|
||||
const UserSettings = userSettings.UserSettings;
|
||||
|
||||
return function (view, params) {
|
||||
export default function (view, params) {
|
||||
function onBeforeUnload(e) {
|
||||
if (hasChanges) {
|
||||
e.returnValue = 'You currently have unsaved changes. Are you sure you wish to leave?';
|
||||
}
|
||||
}
|
||||
|
||||
var settingsInstance;
|
||||
var hasChanges;
|
||||
var userId = params.userId || ApiClient.getCurrentUserId();
|
||||
var currentSettings = userId === ApiClient.getCurrentUserId() ? userSettings : new UserSettings();
|
||||
let settingsInstance;
|
||||
let hasChanges;
|
||||
const userId = params.userId || ApiClient.getCurrentUserId();
|
||||
const currentSettings = userId === ApiClient.getCurrentUserId() ? userSettings : new UserSettings();
|
||||
view.addEventListener('viewshow', function () {
|
||||
window.addEventListener('beforeunload', onBeforeUnload);
|
||||
|
||||
|
@ -26,27 +33,23 @@ define(['playbackSettings', 'dom', 'globalize', 'loading', 'userSettings', 'auto
|
|||
userId: userId,
|
||||
element: view.querySelector('.settingsContainer'),
|
||||
userSettings: currentSettings,
|
||||
enableSaveButton: false,
|
||||
enableSaveConfirmation: false,
|
||||
enableSaveButton: true,
|
||||
enableSaveConfirmation: true,
|
||||
autoFocus: autoFocuser.isEnabled()
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
view.addEventListener('change', function () {
|
||||
hasChanges = true;
|
||||
});
|
||||
view.addEventListener('viewbeforehide', function () {
|
||||
hasChanges = false;
|
||||
|
||||
if (settingsInstance) {
|
||||
settingsInstance.submit();
|
||||
}
|
||||
});
|
||||
view.addEventListener('viewdestroy', function () {
|
||||
if (settingsInstance) {
|
||||
settingsInstance.destroy();
|
||||
settingsInstance = null;
|
||||
}
|
||||
});
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
|
|
@ -1,6 +1,14 @@
|
|||
<<<<<<< HEAD
|
||||
import subtitleSettings from 'subtitleSettings';
|
||||
import {UserSettings, currentSettings as userSettings} from 'userSettings';
|
||||
import autoFocuser from 'autoFocuser';
|
||||
=======
|
||||
import SubtitleSettings from 'subtitleSettings';
|
||||
import * as userSettings from 'userSettings';
|
||||
import autoFocuser from 'autoFocuser';
|
||||
|
||||
/* eslint-disable indent */
|
||||
>>>>>>> upstream/master
|
||||
|
||||
export class SubtitleController {
|
||||
constructor(view, params) {
|
||||
|
@ -10,6 +18,7 @@ export class SubtitleController {
|
|||
this.subtitleSettingsInstance = null;
|
||||
this.view = view;
|
||||
|
||||
<<<<<<< HEAD
|
||||
view.addEventListener('viewshow', this.viewShow.bind(this));
|
||||
view.addEventListener('change', this.change.bind(this));
|
||||
view.addEventListener('viewbeforehide', this.viewBeforeHide.bind(this));
|
||||
|
@ -56,8 +65,53 @@ export class SubtitleController {
|
|||
beforeUnload(e) {
|
||||
if (this.hasChanges) {
|
||||
e.returnValue = 'You currently have unsaved changes. Are you sure you wish to leave?';
|
||||
=======
|
||||
export default function (view, params) {
|
||||
function onBeforeUnload(e) {
|
||||
if (hasChanges) {
|
||||
e.returnValue = 'You currently have unsaved changes. Are you sure you wish to leave?';
|
||||
}
|
||||
>>>>>>> upstream/master
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
<<<<<<< HEAD
|
||||
export default SubtitleController;
|
||||
=======
|
||||
let subtitleSettingsInstance;
|
||||
let hasChanges;
|
||||
const userId = params.userId || ApiClient.getCurrentUserId();
|
||||
const currentSettings = userId === ApiClient.getCurrentUserId() ? userSettings : new UserSettings();
|
||||
view.addEventListener('viewshow', function () {
|
||||
window.addEventListener('beforeunload', onBeforeUnload);
|
||||
|
||||
if (subtitleSettingsInstance) {
|
||||
subtitleSettingsInstance.loadData();
|
||||
} else {
|
||||
subtitleSettingsInstance = new SubtitleSettings({
|
||||
serverId: ApiClient.serverId(),
|
||||
userId: userId,
|
||||
element: view.querySelector('.settingsContainer'),
|
||||
userSettings: currentSettings,
|
||||
enableSaveButton: true,
|
||||
enableSaveConfirmation: true,
|
||||
autoFocus: autoFocuser.isEnabled()
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
view.addEventListener('change', function () {
|
||||
hasChanges = true;
|
||||
});
|
||||
|
||||
view.addEventListener('viewdestroy', function () {
|
||||
if (subtitleSettingsInstance) {
|
||||
subtitleSettingsInstance.destroy();
|
||||
subtitleSettingsInstance = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/* eslint-enable indent */
|
||||
>>>>>>> upstream/master
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
<<<<<<< HEAD
|
||||
import browser from 'browser';
|
||||
import dom from 'dom';
|
||||
import layoutManager from 'layoutManager';
|
||||
|
@ -6,6 +7,10 @@ import appRouter from 'appRouter';
|
|||
import appHost from 'apphost';
|
||||
import 'css!./emby-button';
|
||||
import 'registerElement';
|
||||
=======
|
||||
define(['browser', 'dom', 'layoutManager', 'shell', 'appRouter', 'apphost', 'css!./emby-button', 'webcomponents'], function (browser, dom, layoutManager, shell, appRouter, appHost) {
|
||||
'use strict';
|
||||
>>>>>>> upstream/master
|
||||
|
||||
const EmbyButtonPrototype = Object.create(HTMLButtonElement.prototype);
|
||||
const EmbyLinkButtonPrototype = Object.create(HTMLAnchorElement.prototype);
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
<<<<<<< HEAD
|
||||
import layoutManager from 'layoutManager';
|
||||
import 'css!./emby-button';
|
||||
import 'registerElement';
|
||||
=======
|
||||
define(['layoutManager', 'css!./emby-button', 'webcomponents'], function (layoutManager) {
|
||||
'use strict';
|
||||
>>>>>>> upstream/master
|
||||
|
||||
const EmbyButtonPrototype = Object.create(HTMLButtonElement.prototype);
|
||||
|
||||
|
|
|
@ -1,7 +1,12 @@
|
|||
<<<<<<< HEAD
|
||||
import browser from 'browser';
|
||||
import dom from 'dom';
|
||||
import 'css!./emby-checkbox';
|
||||
import 'registerElement';
|
||||
=======
|
||||
define(['browser', 'dom', 'css!./emby-checkbox', 'webcomponents'], function (browser, dom) {
|
||||
'use strict';
|
||||
>>>>>>> upstream/master
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
|
|
|
@ -1,7 +1,12 @@
|
|||
<<<<<<< HEAD
|
||||
import browser from 'browser';
|
||||
import 'css!./emby-collapse';
|
||||
import 'registerElement';
|
||||
import 'emby-button';
|
||||
=======
|
||||
define(['browser', 'css!./emby-collapse', 'webcomponents', 'emby-button'], function (browser) {
|
||||
'use strict';
|
||||
>>>>>>> upstream/master
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
|
|
|
@ -1,8 +1,13 @@
|
|||
<<<<<<< HEAD
|
||||
import layoutManager from 'layoutManager';
|
||||
import browser from 'browser';
|
||||
import dom from 'dom';
|
||||
import 'css!./emby-input';
|
||||
import 'registerElement';
|
||||
=======
|
||||
define(['layoutManager', 'browser', 'dom', 'css!./emby-input', 'webcomponents'], function (layoutManager, browser, dom) {
|
||||
'use strict';
|
||||
>>>>>>> upstream/master
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
<<<<<<< HEAD
|
||||
import EmbyProgressRing from 'emby-progressring';
|
||||
import dom from 'dom';
|
||||
import serverNotifications from 'serverNotifications';
|
||||
|
@ -5,6 +6,10 @@ import events from 'events';
|
|||
import 'registerElement';
|
||||
|
||||
/* eslint-disable indent */
|
||||
=======
|
||||
define(['emby-progressring', 'dom', 'serverNotifications', 'events', 'webcomponents'], function (EmbyProgressRing, dom, serverNotifications, events) {
|
||||
'use strict';
|
||||
>>>>>>> upstream/master
|
||||
|
||||
function addNotificationEvent(instance, name, handler) {
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
<<<<<<< HEAD
|
||||
import itemShortcuts from 'itemShortcuts';
|
||||
import inputManager from 'inputManager';
|
||||
import connectionManager from 'connectionManager';
|
||||
|
@ -15,6 +16,12 @@ import 'registerElement';
|
|||
/* eslint-disable indent */
|
||||
|
||||
const ItemsContainerPrototype = Object.create(HTMLDivElement.prototype);
|
||||
=======
|
||||
define(['itemShortcuts', 'inputManager', 'connectionManager', 'playbackManager', 'imageLoader', 'layoutManager', 'browser', 'dom', 'loading', 'focusManager', 'serverNotifications', 'events', 'webcomponents'], function (itemShortcuts, inputManager, connectionManager, playbackManager, imageLoader, layoutManager, browser, dom, loading, focusManager, serverNotifications, events) {
|
||||
'use strict';
|
||||
|
||||
var ItemsContainerPrototype = Object.create(HTMLDivElement.prototype);
|
||||
>>>>>>> upstream/master
|
||||
|
||||
function onClick(e) {
|
||||
const itemsContainer = this;
|
||||
|
@ -42,7 +49,7 @@ import 'registerElement';
|
|||
|
||||
// check for serverId, it won't be present on selectserver
|
||||
if (card && card.getAttribute('data-serverid')) {
|
||||
inputManager.trigger('menu', {
|
||||
inputManager.handleCommand('menu', {
|
||||
sourceElement: card
|
||||
});
|
||||
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
<<<<<<< HEAD
|
||||
import require from 'require';
|
||||
import 'css!./emby-progressring';
|
||||
import 'webcomponents';
|
||||
=======
|
||||
define(['require', 'css!./emby-progressring', 'webcomponents'], function (require) {
|
||||
'use strict';
|
||||
>>>>>>> upstream/master
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
<<<<<<< HEAD
|
||||
import layoutManager from 'layoutManager';
|
||||
import 'css!./emby-radio';
|
||||
import 'registerElement';
|
||||
=======
|
||||
define(['layoutManager', 'css!./emby-radio', 'webcomponents'], function (layoutManager) {
|
||||
'use strict';
|
||||
>>>>>>> upstream/master
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
justify-content: center;
|
||||
min-width: 104px;
|
||||
min-height: 24px;
|
||||
padding-top: 1.25em;
|
||||
padding-top: 0.85em;
|
||||
z-index: 1;
|
||||
color: #fff;
|
||||
display: flex;
|
||||
|
|
|
@ -1,8 +1,13 @@
|
|||
<<<<<<< HEAD
|
||||
import layoutManager from 'layoutManager';
|
||||
import dom from 'dom';
|
||||
import 'css!./emby-scrollbuttons';
|
||||
import 'registerElement';
|
||||
import 'paper-icon-button-light';
|
||||
=======
|
||||
define(['layoutManager', 'dom', 'css!./emby-scrollbuttons', 'webcomponents', 'paper-icon-button-light'], function (layoutManager, dom) {
|
||||
'use strict';
|
||||
>>>>>>> upstream/master
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
<<<<<<< HEAD
|
||||
import scroller from 'scroller';
|
||||
import dom from 'dom';
|
||||
import layoutManager from 'layoutManager';
|
||||
|
@ -6,6 +7,10 @@ import focusManager from 'focusManager';
|
|||
import browser from 'browser';
|
||||
import 'registerElement';
|
||||
import 'css!./emby-scroller';
|
||||
=======
|
||||
define(['scroller', 'dom', 'layoutManager', 'inputManager', 'focusManager', 'browser', 'webcomponents', 'css!./emby-scroller'], function (scroller, dom, layoutManager, inputManager, focusManager, browser) {
|
||||
'use strict';
|
||||
>>>>>>> upstream/master
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
|
|
|
@ -1,8 +1,13 @@
|
|||
<<<<<<< HEAD
|
||||
import layoutManager from 'layoutManager';
|
||||
import browser from 'browser';
|
||||
import actionsheet from 'actionsheet';
|
||||
import 'css!./emby-select';
|
||||
import 'registerElement';
|
||||
=======
|
||||
define(['layoutManager', 'browser', 'actionsheet', 'css!./emby-select', 'webcomponents'], function (layoutManager, browser, actionsheet) {
|
||||
'use strict';
|
||||
>>>>>>> upstream/master
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
<<<<<<< HEAD
|
||||
import browser from 'browser';
|
||||
import dom from 'dom';
|
||||
import layoutManager from 'layoutManager';
|
||||
|
@ -5,6 +6,10 @@ import keyboardnavigation from 'keyboardnavigation';
|
|||
import 'css!./emby-slider';
|
||||
import 'webcomponents';
|
||||
import 'emby-input';
|
||||
=======
|
||||
define(['browser', 'dom', 'layoutManager', 'keyboardnavigation', 'css!./emby-slider', 'webcomponents', 'emby-input'], function (browser, dom, layoutManager, keyboardnavigation) {
|
||||
'use strict';
|
||||
>>>>>>> upstream/master
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
|
|
|
@ -31,11 +31,6 @@
|
|||
|
||||
.emby-tabs-slider {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.layout-mobile .emby-tabs-slider {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.tabContent:not(.is-active) {
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
<<<<<<< HEAD
|
||||
import dom from 'dom';
|
||||
import scroller from 'scroller';
|
||||
import browser from 'browser';
|
||||
|
@ -6,6 +7,10 @@ import focusManager from 'focusManager';
|
|||
import 'registerElement';
|
||||
import 'css!./emby-tabs';
|
||||
import 'scrollStyles';
|
||||
=======
|
||||
define(['dom', 'scroller', 'browser', 'layoutManager', 'focusManager', 'webcomponents', 'css!./emby-tabs', 'scrollStyles'], function (dom, scroller, browser, layoutManager, focusManager) {
|
||||
'use strict';
|
||||
>>>>>>> upstream/master
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
<<<<<<< HEAD
|
||||
import layoutManager from 'layoutManager';
|
||||
import browser from 'browser';
|
||||
import 'css!./emby-textarea';
|
||||
|
@ -5,6 +6,10 @@ import 'registerElement';
|
|||
import 'emby-input';
|
||||
|
||||
/* eslint-disable indent */
|
||||
=======
|
||||
define(['layoutManager', 'browser', 'css!./emby-textarea', 'webcomponents', 'emby-input'], function (layoutManager, browser) {
|
||||
'use strict';
|
||||
>>>>>>> upstream/master
|
||||
|
||||
function autoGrow(textarea, maxLines) {
|
||||
const self = this;
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
<<<<<<< HEAD
|
||||
import 'css!./emby-toggle';
|
||||
import 'registerElement';
|
||||
=======
|
||||
define(['css!./emby-toggle', 'webcomponents'], function () {
|
||||
'use strict';
|
||||
>>>>>>> upstream/master
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
|
|
|
@ -52,7 +52,7 @@
|
|||
<!-- iPad Pro 1 -->
|
||||
<link href="assets/splash/ipadpro1_splash.png" media="screen and (device-width: 834px) and (device-height: 1112px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)" rel="apple-touch-startup-image" />
|
||||
<link href="assets/splash/ipadpro1_splash_l.png" media="screen and (device-width: 834px) and (device-height: 1112px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)" rel="apple-touch-startup-image" />
|
||||
|
||||
|
||||
<!-- iPad Pro 3 -->
|
||||
<link href="assets/splash/ipadpro3_splash.png" media="screen and (device-width: 834px) and (device-height: 1194px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)" rel="apple-touch-startup-image" />
|
||||
<link href="assets/splash/ipadpro3_splash_l.png" media="screen and (device-width: 834px) and (device-height: 1194px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)" rel="apple-touch-startup-image" />
|
||||
|
@ -69,12 +69,19 @@
|
|||
<title>Jellyfin</title>
|
||||
|
||||
<style>
|
||||
.transparentDocument, .backgroundContainer-transparent:not(.withBackdrop) {
|
||||
.transparentDocument,
|
||||
.backgroundContainer-transparent:not(.withBackdrop) {
|
||||
background: none !important;
|
||||
background-color: transparent !important;
|
||||
}
|
||||
|
||||
.mouseIdle, .mouseIdle button, .mouseIdle select, .mouseIdle input, .mouseIdle textarea, .mouseIdle a, .mouseIdle label {
|
||||
.mouseIdle,
|
||||
.mouseIdle button,
|
||||
.mouseIdle select,
|
||||
.mouseIdle input,
|
||||
.mouseIdle textarea,
|
||||
.mouseIdle a,
|
||||
.mouseIdle label {
|
||||
cursor: none !important;
|
||||
}
|
||||
|
||||
|
@ -82,7 +89,9 @@
|
|||
background-color: #101010;
|
||||
}
|
||||
|
||||
.hide, .mouseIdle .hide-mouse-idle, .mouseIdle-tv .hide-mouse-idle-tv {
|
||||
.hide,
|
||||
.mouseIdle .hide-mouse-idle,
|
||||
.mouseIdle-tv .hide-mouse-idle-tv {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
|
@ -94,6 +103,42 @@
|
|||
z-index: 1;
|
||||
width: 0.8em;
|
||||
}
|
||||
|
||||
@-webkit-keyframes fadein {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fadein {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.splashLogo {
|
||||
-webkit-animation: fadein 0.5s;
|
||||
animation: fadein 0.5s;
|
||||
width: 30%;
|
||||
height: 30%;
|
||||
background-image: url(assets/img/banner-light.png);
|
||||
background-position: center center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: contain;
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
-webkit-transform: translate(-50%, -50%);
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
@ -103,7 +148,9 @@
|
|||
<div class="mainDrawer-scrollContainer scrollContainer focuscontainer-y"></div>
|
||||
</div>
|
||||
<div class="skinHeader focuscontainer-x"></div>
|
||||
<div class="mainAnimatedPages skinBody"></div>
|
||||
<div class="mainAnimatedPages skinBody">
|
||||
<div class="splashLogo"></div>
|
||||
</div>
|
||||
<div class="mainDrawerHandle"></div>
|
||||
|
||||
<!-- inject:js -->
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
<div id="loginPage" data-role="page" class="page standalonePage" data-backbutton="false">
|
||||
<div id="loginPage" data-role="page" class="page standalonePage flex flex-direction-column align-items-center justify-content-center" data-backbutton="false">
|
||||
<div class="padded-left padded-right padded-bottom-page">
|
||||
<form class="manualLoginForm hide" style="margin: 0 auto;">
|
||||
<h1 style="margin-top:1em;text-align: left;">${HeaderPleaseSignIn}</h1>
|
||||
<form class="manualLoginForm hide">
|
||||
<div class="padded-left padded-right flex align-items-center justify-content-center">
|
||||
<h1 class="sectionTitle">${HeaderPleaseSignIn}</h1>
|
||||
</div>
|
||||
<div style="height:0; overflow: hidden;">
|
||||
<input type="text" name="fakeusernameremembered" tabindex="-1" />
|
||||
<input type="password" name="fakepasswordremembered" tabindex="-1" />
|
||||
|
@ -29,8 +31,6 @@
|
|||
<span>${ButtonCancel}</span>
|
||||
</button>
|
||||
</div>
|
||||
<br/>
|
||||
<br/>
|
||||
</form>
|
||||
|
||||
<div class="visualLoginForm" style="text-align: center;">
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<div class="nowPlayingInfoContainer">
|
||||
<div class="nowPlayingPageImageContainer"></div>
|
||||
<div class="nowPlayingInfoControls">
|
||||
|
||||
|
||||
<div class="flex">
|
||||
|
||||
<div class="nowPlayingInfoContainerMedia">
|
||||
|
@ -15,9 +15,9 @@
|
|||
<div class="nowPlayingArtist nowPlayingSerie"></div>
|
||||
</div>
|
||||
<div class="nowPlayingPageUserDataButtonsTitle"></div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div class="sliderContainer flex">
|
||||
<div class="positionTime"></div>
|
||||
<div class="nowPlayingPositionSliderContainer">
|
||||
|
@ -25,15 +25,20 @@
|
|||
</div>
|
||||
<div class="runtime"></div>
|
||||
</div>
|
||||
|
||||
<div class="nowPlayingButtonsContainer focuscontainer-x">
|
||||
|
||||
|
||||
<div class="nowPlayingButtonsContainer focuscontainer-x justify-content-space-between">
|
||||
|
||||
<div class="nowPlayingInfoButtons">
|
||||
|
||||
|
||||
<button is="paper-icon-button-light" class="btnCommand btnRepeat repeatToggleButton autoSize" title="${ButtonRepeat}"
|
||||
data-command="SetRepeatMode">
|
||||
<span class="material-icons repeat"></span>
|
||||
</button>
|
||||
|
||||
<button is="paper-icon-button-light" class="btnRewind btnNowPlayingRewind btnPlayStateCommand autoSize" title="${Rewind}">
|
||||
<span class="material-icons replay_10"></span>
|
||||
</button>
|
||||
|
||||
|
||||
<button is="paper-icon-button-light" class="btnPreviousTrack btnPlayStateCommand autoSize" title="${ButtonPreviousTrack}">
|
||||
<span class="material-icons skip_previous"></span>
|
||||
</button>
|
||||
|
@ -49,15 +54,19 @@
|
|||
<button is="paper-icon-button-light" class="btnPlayStateCommand btnNextTrack autoSize" title="${ButtonNextTrack}">
|
||||
<span class="material-icons skip_next"></span>
|
||||
</button>
|
||||
|
||||
|
||||
<button is="paper-icon-button-light" class="btnPlayStateCommand btnFastForward btnNowPlayingFastForward autoSize" title="${FastForward}">
|
||||
<span class="material-icons forward_30"></span>
|
||||
</button>
|
||||
|
||||
|
||||
<button is="paper-icon-button-light" class="btnShuffleQueue autoSize" title="${ButtonShuffle}">
|
||||
<span class="material-icons shuffle"></span>
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="nowPlayingSecondaryButtons">
|
||||
|
||||
|
||||
<button is="paper-icon-button-light" class="btnAudioTracks videoButton btnPlayStateCommand autoSize" title="${ButtonAudioTracks}" data-command="GoToSearch">
|
||||
<span class="material-icons audiotrack"></span>
|
||||
</button>
|
||||
|
@ -65,14 +74,19 @@
|
|||
<button is="paper-icon-button-light" class="btnSubtitles videoButton btnPlayStateCommand autoSize" title="${ButtonSubtitles}" data-command="GoToSearch">
|
||||
<span class="material-icons closed_caption"></span>
|
||||
</button>
|
||||
|
||||
|
||||
<div class="nowPlayingPageUserDataButtons"></div>
|
||||
|
||||
<button is="paper-icon-button-light" class="btnToggleFullscreen videoButton btnPlayStateCommand autoSize" title="${ButtonFullscreen}" data-command="ToggleFullscreen">
|
||||
<span class="material-icons fullscreen"></span>
|
||||
</button>
|
||||
|
||||
<button is="paper-icon-button-light" class="btnCommand repeatToggleButton autoSize" title="${ButtonRepeat}" data-command="SetRepeatMode">
|
||||
<button is="paper-icon-button-light" class="btnShuffleQueue autoSize" title="${ButtonShuffle}">
|
||||
<span class="material-icons shuffle"></span>
|
||||
</button>
|
||||
|
||||
<button is="paper-icon-button-light" class="btnCommand btnRepeat repeatToggleButton autoSize" title="${ButtonRepeat}"
|
||||
data-command="SetRepeatMode">
|
||||
<span class="material-icons repeat"></span>
|
||||
</button>
|
||||
|
||||
|
@ -162,21 +176,18 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="playlistSection">
|
||||
<div class="playlistSectionButton flex align-items-center justify-content-center">
|
||||
<button id="togglePlaylist" is="paper-icon-button-light" class="btnTogglePlaylist" title="${ButtonTogglePlaylist}">
|
||||
<div class="playlistSectionButton flex align-items-center justify-content-center focuscontainer-x">
|
||||
<button id="togglePlaylist" is="paper-icon-button-light" class="btnTogglePlaylist hide" title="${ButtonTogglePlaylist}">
|
||||
<span class="material-icons queue_music"></span>
|
||||
</button>
|
||||
<button is="paper-icon-button-light" class="btnSavePlaylist" title="${ButtonSave}">
|
||||
<button is="paper-icon-button-light" class="btnSavePlaylist hide" title="${ButtonSave}">
|
||||
<span class="material-icons save"></span>
|
||||
</button>
|
||||
<button id="toggleContextMenu" is="paper-icon-button-light" class="btnToggleContextMenu" title="${ButtonToggleContextMenu}">
|
||||
<span class="material-icons more_vert"></span>
|
||||
</button>
|
||||
</div>
|
||||
<div id="playlist" class="playlist itemsContainer vertical-list nowPlayingPlaylist hide" is="emby-itemscontainer" data-dragreorder="true"></div>
|
||||
<div id="contextMenu" class="contextMenu itemsContainer vertical-list nowPlayingContextMenu hide" is="emby-itemscontainer">
|
||||
<div class="listItem listItem-border contextMenuList contextMenuArtist">
|
||||
</div>
|
||||
<div class="listItem listItem-border contextMenuList contextMenuAlbum">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -548,7 +548,7 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', '
|
|||
|
||||
events.trigger(instance, 'playbackstop', [state]);
|
||||
|
||||
var state = instance.lastPlayerData.PlayState || {};
|
||||
state = instance.lastPlayerData.PlayState || {};
|
||||
var volume = state.VolumeLevel || 0.5;
|
||||
var mute = state.IsMuted || false;
|
||||
|
||||
|
@ -572,6 +572,7 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', '
|
|||
bindEventForRelay(instance, 'unpause');
|
||||
bindEventForRelay(instance, 'volumechange');
|
||||
bindEventForRelay(instance, 'repeatmodechange');
|
||||
bindEventForRelay(instance, 'shufflequeuemodechange');
|
||||
|
||||
events.on(instance._castPlayer, 'playstatechange', function (e, data) {
|
||||
|
||||
|
@ -651,6 +652,7 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', '
|
|||
'SetSubtitleStreamIndex',
|
||||
'DisplayContent',
|
||||
'SetRepeatMode',
|
||||
'SetShuffleQueue',
|
||||
'EndSession',
|
||||
'PlayMediaSource',
|
||||
'PlayTrailers'
|
||||
|
@ -864,6 +866,12 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', '
|
|||
return state.RepeatMode;
|
||||
};
|
||||
|
||||
ChromecastPlayer.prototype.getQueueShuffleMode = function () {
|
||||
var state = this.lastPlayerData || {};
|
||||
state = state.PlayState || {};
|
||||
return state.ShuffleMode;
|
||||
};
|
||||
|
||||
ChromecastPlayer.prototype.playTrailers = function (item) {
|
||||
|
||||
this._castPlayer.sendMessage({
|
||||
|
@ -884,6 +892,15 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', '
|
|||
});
|
||||
};
|
||||
|
||||
ChromecastPlayer.prototype.setQueueShuffleMode = function (value) {
|
||||
this._castPlayer.sendMessage({
|
||||
options: {
|
||||
ShuffleMode: value
|
||||
},
|
||||
command: 'SetShuffleQueue'
|
||||
});
|
||||
};
|
||||
|
||||
ChromecastPlayer.prototype.toggleMute = function () {
|
||||
|
||||
this._castPlayer.sendMessage({
|
||||
|
|
|
@ -649,7 +649,7 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa
|
|||
function setTrackEventsSubtitleOffset(trackEvents, offsetValue) {
|
||||
|
||||
if (Array.isArray(trackEvents)) {
|
||||
offsetValue = updateCurrentTrackOffset(offsetValue);
|
||||
offsetValue = updateCurrentTrackOffset(offsetValue) * 1e7; // ticks
|
||||
trackEvents.forEach(function(trackEvent) {
|
||||
trackEvent.StartPositionTicks -= offsetValue;
|
||||
trackEvent.EndPositionTicks -= offsetValue;
|
||||
|
|
|
@ -263,7 +263,7 @@ define(['playbackManager', 'events', 'serverNotifications', 'connectionManager']
|
|||
appName: s.Client,
|
||||
playableMediaTypes: s.PlayableMediaTypes,
|
||||
isLocalPlayer: false,
|
||||
supportedCommands: s.SupportedCommands,
|
||||
supportedCommands: s.Capabilities.SupportedCommands,
|
||||
user: s.UserId ? {
|
||||
|
||||
Id: s.UserId,
|
||||
|
@ -506,6 +506,17 @@ define(['playbackManager', 'events', 'serverNotifications', 'connectionManager']
|
|||
});
|
||||
};
|
||||
|
||||
SessionPlayer.prototype.setQueueShuffleMode = function (mode) {
|
||||
|
||||
sendCommandByName(this, 'SetShuffleQueue', {
|
||||
ShuffleMode: mode
|
||||
});
|
||||
};
|
||||
|
||||
SessionPlayer.prototype.getQueueShuffleMode = function () {
|
||||
|
||||
};
|
||||
|
||||
SessionPlayer.prototype.displayContent = function (options) {
|
||||
|
||||
sendCommandByName(this, 'DisplayContent', options);
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
src += `?v=${self.dashboardVersion}`;
|
||||
}
|
||||
script.src = src;
|
||||
script.setAttribute('async', '');
|
||||
|
||||
if (onload) {
|
||||
script.onload = onload;
|
||||
|
|
|
@ -60,7 +60,7 @@ define(['browser'], function (browser) {
|
|||
|
||||
function canPlayHlsWithMSE() {
|
||||
// text tracks don’t work with this in firefox
|
||||
return window.MediaSource != null;
|
||||
return window.MediaSource != null; /* eslint-disable-line compat/compat */
|
||||
}
|
||||
|
||||
function supportsAc3(videoTestElement) {
|
||||
|
|
|
@ -211,7 +211,7 @@
|
|||
'MozAnimation': 'animationend',
|
||||
'WebkitAnimation': 'webkitAnimationEnd'
|
||||
};
|
||||
for (let t in animations) {
|
||||
for (const t in animations) {
|
||||
if (el.style[t] !== undefined) {
|
||||
_animationEvent = animations[t];
|
||||
return animations[t];
|
||||
|
@ -251,7 +251,7 @@
|
|||
'MozTransition': 'transitionend',
|
||||
'WebkitTransition': 'webkitTransitionEnd'
|
||||
};
|
||||
for (let t in transitions) {
|
||||
for (const t in transitions) {
|
||||
if (el.style[t] !== undefined) {
|
||||
_transitionEvent = transitions[t];
|
||||
return transitions[t];
|
||||
|
|
|
@ -201,6 +201,9 @@ import appHost from 'apphost';
|
|||
'rewind': () => {
|
||||
playbackManager.rewind();
|
||||
},
|
||||
'seek': () => {
|
||||
playbackManager.seekMs(options);
|
||||
},
|
||||
'togglefullscreen': () => {
|
||||
playbackManager.toggleFullscreen();
|
||||
},
|
||||
|
@ -235,9 +238,6 @@ import appHost from 'apphost';
|
|||
}
|
||||
}
|
||||
|
||||
// Alias for backward compatibility
|
||||
export const trigger = handleCommand;
|
||||
|
||||
dom.addEventListener(document, 'click', notify, {
|
||||
passive: true
|
||||
});
|
||||
|
@ -245,8 +245,7 @@ import appHost from 'apphost';
|
|||
/* eslint-enable indent */
|
||||
|
||||
export default {
|
||||
trigger: handleCommand,
|
||||
handle: handleCommand,
|
||||
handleCommand: handleCommand,
|
||||
notify: notify,
|
||||
notifyMouseMove: notifyMouseMove,
|
||||
idleTime: idleTime,
|
||||
|
|
|
@ -71,12 +71,12 @@ define(['connectionManager', 'listView', 'cardBuilder', 'imageLoader', 'libraryB
|
|||
|
||||
html += '<div class="' + sectionClass + '" data-type="' + section.type + '">';
|
||||
html += '<div class="sectionTitleContainer sectionTitleContainer-cards">';
|
||||
html += '<h2 class="sectionTitle sectionTitle-cards padded-left">';
|
||||
html += '<h2 class="sectionTitle sectionTitle-cards">';
|
||||
html += section.name;
|
||||
html += '</h2>';
|
||||
html += '<a is="emby-linkbutton" href="#" class="clearLink hide" style="margin-left:1em;vertical-align:middle;"><button is="emby-button" type="button" class="raised more raised-mini noIcon">' + globalize.translate('ButtonMore') + '</button></a>';
|
||||
html += '</div>';
|
||||
html += '<div is="emby-itemscontainer" class="itemsContainer padded-left padded-right">';
|
||||
html += '<div is="emby-itemscontainer" class="itemsContainer padded-right">';
|
||||
html += '</div>';
|
||||
return html += '</div>';
|
||||
}).join('');
|
||||
|
|
|
@ -78,7 +78,7 @@ export function isNavigationKey(key) {
|
|||
}
|
||||
|
||||
export function enable() {
|
||||
document.addEventListener('keydown', function (e) {
|
||||
window.addEventListener('keydown', function (e) {
|
||||
const key = getKeyName(e);
|
||||
|
||||
// Ignore navigation keys for non-TV
|
||||
|
@ -90,53 +90,53 @@ export function enable() {
|
|||
|
||||
switch (key) {
|
||||
case 'ArrowLeft':
|
||||
inputManager.handle('left');
|
||||
inputManager.handleCommand('left');
|
||||
break;
|
||||
case 'ArrowUp':
|
||||
inputManager.handle('up');
|
||||
inputManager.handleCommand('up');
|
||||
break;
|
||||
case 'ArrowRight':
|
||||
inputManager.handle('right');
|
||||
inputManager.handleCommand('right');
|
||||
break;
|
||||
case 'ArrowDown':
|
||||
inputManager.handle('down');
|
||||
inputManager.handleCommand('down');
|
||||
break;
|
||||
|
||||
case 'Back':
|
||||
inputManager.handle('back');
|
||||
inputManager.handleCommand('back');
|
||||
break;
|
||||
|
||||
case 'Escape':
|
||||
if (layoutManager.tv) {
|
||||
inputManager.handle('back');
|
||||
inputManager.handleCommand('back');
|
||||
} else {
|
||||
capture = false;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'MediaPlay':
|
||||
inputManager.handle('play');
|
||||
inputManager.handleCommand('play');
|
||||
break;
|
||||
case 'Pause':
|
||||
inputManager.handle('pause');
|
||||
inputManager.handleCommand('pause');
|
||||
break;
|
||||
case 'MediaPlayPause':
|
||||
inputManager.handle('playpause');
|
||||
inputManager.handleCommand('playpause');
|
||||
break;
|
||||
case 'MediaRewind':
|
||||
inputManager.handle('rewind');
|
||||
inputManager.handleCommand('rewind');
|
||||
break;
|
||||
case 'MediaFastForward':
|
||||
inputManager.handle('fastforward');
|
||||
inputManager.handleCommand('fastforward');
|
||||
break;
|
||||
case 'MediaStop':
|
||||
inputManager.handle('stop');
|
||||
inputManager.handleCommand('stop');
|
||||
break;
|
||||
case 'MediaTrackPrevious':
|
||||
inputManager.handle('previoustrack');
|
||||
inputManager.handleCommand('previoustrack');
|
||||
break;
|
||||
case 'MediaTrackNext':
|
||||
inputManager.handle('nexttrack');
|
||||
inputManager.handleCommand('nexttrack');
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
|
@ -13,7 +13,7 @@ define(['dom', 'layoutManager', 'inputManager', 'connectionManager', 'events', '
|
|||
html += '<div class="headerRight">';
|
||||
html += '<span class="headerSelectedPlayer"></span>';
|
||||
html += `<button is="paper-icon-button-light" class="headerSyncButton syncButton headerButton headerButtonRight hide" title="${globalize.translate('ButtonSyncPlay')}"><span class="material-icons sync_disabled"></span></button>`;
|
||||
html += '<button is="paper-icon-button-light" class="headerAudioPlayerButton audioPlayerButton headerButton headerButtonRight hide"><span class="material-icons music_note"></span></button>';
|
||||
html += `<button is="paper-icon-button-light" class="headerAudioPlayerButton audioPlayerButton headerButton headerButtonRight hide" title="${globalize.translate('ButtonPlayer')}"><span class="material-icons music_note"></span></button>`;
|
||||
html += `<button is="paper-icon-button-light" class="headerCastButton castButton headerButton headerButtonRight hide" title="${globalize.translate('ButtonCast')}"><span class="material-icons cast"></span></button>`;
|
||||
html += `<button type="button" is="paper-icon-button-light" class="headerButton headerButtonRight headerSearchButton hide" title="${globalize.translate('ButtonSearch')}"><span class="material-icons search"></span></button>`;
|
||||
html += '<button is="paper-icon-button-light" class="headerButton headerButtonRight headerUserButton hide"><span class="material-icons person"></span></button>';
|
||||
|
@ -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 {
|
||||
|
@ -116,7 +117,7 @@ define(['dom', 'layoutManager', 'inputManager', 'connectionManager', 'events', '
|
|||
}
|
||||
|
||||
function showSearch() {
|
||||
inputManager.trigger('search');
|
||||
inputManager.handleCommand('search');
|
||||
}
|
||||
|
||||
function onHeaderUserButtonClick(e) {
|
||||
|
@ -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;
|
||||
});
|
||||
|
|
|
@ -136,6 +136,7 @@ define(['inputManager', 'focusManager', 'browser', 'layoutManager', 'events', 'd
|
|||
|
||||
stopMouseInterval();
|
||||
|
||||
/* eslint-disable-next-line compat/compat */
|
||||
dom.removeEventListener(document, (window.PointerEvent ? 'pointermove' : 'mousemove'), onPointerMove, {
|
||||
passive: true
|
||||
});
|
||||
|
@ -148,6 +149,7 @@ define(['inputManager', 'focusManager', 'browser', 'layoutManager', 'events', 'd
|
|||
});
|
||||
}
|
||||
|
||||
/* eslint-disable-next-line compat/compat */
|
||||
dom.removeEventListener(document, (window.PointerEvent ? 'pointerenter' : 'mouseenter'), onPointerEnter, {
|
||||
capture: true,
|
||||
passive: true
|
||||
|
|
|
@ -15,7 +15,7 @@ define([
|
|||
'detailtablecss'], function () {
|
||||
|
||||
function defineRoute(newRoute) {
|
||||
var path = newRoute.path;
|
||||
var path = newRoute.alias ? newRoute.alias : newRoute.path;
|
||||
console.debug('defining route: ' + path);
|
||||
newRoute.dictionary = 'core';
|
||||
Emby.Page.addRoute(path, newRoute);
|
||||
|
@ -240,8 +240,9 @@ define([
|
|||
transition: 'fade'
|
||||
});
|
||||
defineRoute({
|
||||
path: '/itemdetails.html',
|
||||
controller: 'itemDetails',
|
||||
alias: '/details',
|
||||
path: '/controllers/itemDetails/index.html',
|
||||
controller: 'itemDetails/index',
|
||||
autoFocus: false,
|
||||
transition: 'fade'
|
||||
});
|
||||
|
|
|
@ -36,28 +36,28 @@ define(['connectionManager', 'playbackManager', 'syncPlayManager', 'events', 'in
|
|||
console.debug('Received command: ' + cmd.Name);
|
||||
switch (cmd.Name) {
|
||||
case 'Select':
|
||||
inputManager.trigger('select');
|
||||
inputManager.handleCommand('select');
|
||||
return;
|
||||
case 'Back':
|
||||
inputManager.trigger('back');
|
||||
inputManager.handleCommand('back');
|
||||
return;
|
||||
case 'MoveUp':
|
||||
inputManager.trigger('up');
|
||||
inputManager.handleCommand('up');
|
||||
return;
|
||||
case 'MoveDown':
|
||||
inputManager.trigger('down');
|
||||
inputManager.handleCommand('down');
|
||||
return;
|
||||
case 'MoveLeft':
|
||||
inputManager.trigger('left');
|
||||
inputManager.handleCommand('left');
|
||||
return;
|
||||
case 'MoveRight':
|
||||
inputManager.trigger('right');
|
||||
inputManager.handleCommand('right');
|
||||
return;
|
||||
case 'PageUp':
|
||||
inputManager.trigger('pageup');
|
||||
inputManager.handleCommand('pageup');
|
||||
return;
|
||||
case 'PageDown':
|
||||
inputManager.trigger('pagedown');
|
||||
inputManager.handleCommand('pagedown');
|
||||
return;
|
||||
case 'PlayTrailers':
|
||||
playTrailers(apiClient, cmd.Arguments.ItemId);
|
||||
|
@ -65,26 +65,29 @@ define(['connectionManager', 'playbackManager', 'syncPlayManager', 'events', 'in
|
|||
case 'SetRepeatMode':
|
||||
playbackManager.setRepeatMode(cmd.Arguments.RepeatMode);
|
||||
break;
|
||||
case 'SetShuffleQueue':
|
||||
playbackManager.setQueueShuffleMode(cmd.Arguments.ShuffleMode);
|
||||
break;
|
||||
case 'VolumeUp':
|
||||
inputManager.trigger('volumeup');
|
||||
inputManager.handleCommand('volumeup');
|
||||
return;
|
||||
case 'VolumeDown':
|
||||
inputManager.trigger('volumedown');
|
||||
inputManager.handleCommand('volumedown');
|
||||
return;
|
||||
case 'ChannelUp':
|
||||
inputManager.trigger('channelup');
|
||||
inputManager.handleCommand('channelup');
|
||||
return;
|
||||
case 'ChannelDown':
|
||||
inputManager.trigger('channeldown');
|
||||
inputManager.handleCommand('channeldown');
|
||||
return;
|
||||
case 'Mute':
|
||||
inputManager.trigger('mute');
|
||||
inputManager.handleCommand('mute');
|
||||
return;
|
||||
case 'Unmute':
|
||||
inputManager.trigger('unmute');
|
||||
inputManager.handleCommand('unmute');
|
||||
return;
|
||||
case 'ToggleMute':
|
||||
inputManager.trigger('togglemute');
|
||||
inputManager.handleCommand('togglemute');
|
||||
return;
|
||||
case 'SetVolume':
|
||||
notifyApp();
|
||||
|
@ -99,19 +102,19 @@ define(['connectionManager', 'playbackManager', 'syncPlayManager', 'events', 'in
|
|||
playbackManager.setSubtitleStreamIndex(parseInt(cmd.Arguments.Index));
|
||||
break;
|
||||
case 'ToggleFullscreen':
|
||||
inputManager.trigger('togglefullscreen');
|
||||
inputManager.handleCommand('togglefullscreen');
|
||||
return;
|
||||
case 'GoHome':
|
||||
inputManager.trigger('home');
|
||||
inputManager.handleCommand('home');
|
||||
return;
|
||||
case 'GoToSettings':
|
||||
inputManager.trigger('settings');
|
||||
inputManager.handleCommand('settings');
|
||||
return;
|
||||
case 'DisplayContent':
|
||||
displayContent(cmd, apiClient);
|
||||
break;
|
||||
case 'GoToSearch':
|
||||
inputManager.trigger('search');
|
||||
inputManager.handleCommand('search');
|
||||
return;
|
||||
case 'DisplayMessage':
|
||||
displayMessage(cmd);
|
||||
|
@ -162,19 +165,19 @@ define(['connectionManager', 'playbackManager', 'syncPlayManager', 'events', 'in
|
|||
}
|
||||
} else if (msg.MessageType === 'Playstate') {
|
||||
if (msg.Data.Command === 'Stop') {
|
||||
inputManager.trigger('stop');
|
||||
inputManager.handleCommand('stop');
|
||||
} else if (msg.Data.Command === 'Pause') {
|
||||
inputManager.trigger('pause');
|
||||
inputManager.handleCommand('pause');
|
||||
} else if (msg.Data.Command === 'Unpause') {
|
||||
inputManager.trigger('play');
|
||||
inputManager.handleCommand('play');
|
||||
} else if (msg.Data.Command === 'PlayPause') {
|
||||
inputManager.trigger('playpause');
|
||||
inputManager.handleCommand('playpause');
|
||||
} else if (msg.Data.Command === 'Seek') {
|
||||
playbackManager.seek(msg.Data.SeekPositionTicks);
|
||||
} else if (msg.Data.Command === 'NextTrack') {
|
||||
inputManager.trigger('next');
|
||||
inputManager.handleCommand('next');
|
||||
} else if (msg.Data.Command === 'PreviousTrack') {
|
||||
inputManager.trigger('previous');
|
||||
inputManager.handleCommand('previous');
|
||||
} else {
|
||||
notifyApp();
|
||||
}
|
||||
|
|
|
@ -196,7 +196,7 @@ var Dashboard = {
|
|||
capabilities: function (appHost) {
|
||||
var capabilities = {
|
||||
PlayableMediaTypes: ['Audio', 'Video'],
|
||||
SupportedCommands: ['MoveUp', 'MoveDown', 'MoveLeft', 'MoveRight', 'PageUp', 'PageDown', 'PreviousLetter', 'NextLetter', 'ToggleOsd', 'ToggleContextMenu', 'Select', 'Back', 'SendKey', 'SendString', 'GoHome', 'GoToSettings', 'VolumeUp', 'VolumeDown', 'Mute', 'Unmute', 'ToggleMute', 'SetVolume', 'SetAudioStreamIndex', 'SetSubtitleStreamIndex', 'DisplayContent', 'GoToSearch', 'DisplayMessage', 'SetRepeatMode', 'ChannelUp', 'ChannelDown', 'PlayMediaSource', 'PlayTrailers'],
|
||||
SupportedCommands: ['MoveUp', 'MoveDown', 'MoveLeft', 'MoveRight', 'PageUp', 'PageDown', 'PreviousLetter', 'NextLetter', 'ToggleOsd', 'ToggleContextMenu', 'Select', 'Back', 'SendKey', 'SendString', 'GoHome', 'GoToSettings', 'VolumeUp', 'VolumeDown', 'Mute', 'Unmute', 'ToggleMute', 'SetVolume', 'SetAudioStreamIndex', 'SetSubtitleStreamIndex', 'DisplayContent', 'GoToSearch', 'DisplayMessage', 'SetRepeatMode', 'SetShuffleQueue', 'ChannelUp', 'ChannelDown', 'PlayMediaSource', 'PlayTrailers'],
|
||||
SupportsPersistentIdentifier: 'cordova' === self.appMode || 'android' === self.appMode,
|
||||
SupportsMediaControl: true
|
||||
};
|
||||
|
@ -387,8 +387,6 @@ var AppInfo = {};
|
|||
define('lazyLoader', [componentsPath + '/lazyLoader/lazyLoaderIntersectionObserver'], returnFirstDependency);
|
||||
define('shell', [scriptsPath + '/shell'], returnFirstDependency);
|
||||
|
||||
define('registerElement', ['document-register-element'], returnFirstDependency);
|
||||
|
||||
define('alert', [componentsPath + '/alert'], returnFirstDependency);
|
||||
|
||||
defineResizeObserver();
|
||||
|
@ -672,7 +670,6 @@ var AppInfo = {};
|
|||
},
|
||||
bundles: {
|
||||
bundle: [
|
||||
'document-register-element',
|
||||
'fetch',
|
||||
'flvjs',
|
||||
'jstree',
|
||||
|
@ -1039,7 +1036,7 @@ var AppInfo = {};
|
|||
}
|
||||
|
||||
if ('SeriesTimer' == itemType) {
|
||||
return 'itemdetails.html?seriesTimerId=' + id + '&serverId=' + serverId;
|
||||
return 'details?seriesTimerId=' + id + '&serverId=' + serverId;
|
||||
}
|
||||
|
||||
if ('livetv' == item.CollectionType) {
|
||||
|
@ -1109,13 +1106,13 @@ var AppInfo = {};
|
|||
var itemTypes = ['Playlist', 'TvChannel', 'Program', 'BoxSet', 'MusicAlbum', 'MusicGenre', 'Person', 'Recording', 'MusicArtist'];
|
||||
|
||||
if (itemTypes.indexOf(itemType) >= 0) {
|
||||
return 'itemdetails.html?id=' + id + '&serverId=' + serverId;
|
||||
return 'details?id=' + id + '&serverId=' + serverId;
|
||||
}
|
||||
|
||||
var contextSuffix = context ? '&context=' + context : '';
|
||||
|
||||
if ('Series' == itemType || 'Season' == itemType || 'Episode' == itemType) {
|
||||
return 'itemdetails.html?id=' + id + contextSuffix + '&serverId=' + serverId;
|
||||
return 'details?id=' + id + contextSuffix + '&serverId=' + serverId;
|
||||
}
|
||||
|
||||
if (item.IsFolder) {
|
||||
|
@ -1126,7 +1123,7 @@ var AppInfo = {};
|
|||
return '#';
|
||||
}
|
||||
|
||||
return 'itemdetails.html?id=' + id + '&serverId=' + serverId;
|
||||
return 'details?id=' + id + '&serverId=' + serverId;
|
||||
};
|
||||
|
||||
appRouter.showItem = showItem;
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
<div id="selectServerPage" data-role="page" class="page noSecondaryNavPage standalonePage pageContainer fullWidth vertical flex flex-direction-column">
|
||||
<div class="verticalSection flex-shrink-zero flex flex-direction-column" style="margin: 2em 0 1em;">
|
||||
<div class="padded-left padded-right flex align-items-center justify-content-center" style="margin-bottom:2em;">
|
||||
<div id="selectServerPage" data-role="page" class="page noSecondaryNavPage standalonePage pageContainer fullWidthContent vertical flex flex-direction-column align-items-center justify-content-center">
|
||||
<div class="verticalSection flex-shrink-zero w-100 flex flex-direction-column">
|
||||
<div class="padded-left padded-right flex align-items-center justify-content-center">
|
||||
<h1 class="sectionTitle sectionTitle-cards">${HeaderSelectServer}</h1>
|
||||
</div>
|
||||
<div class="padded-top padded-bottom-focusscale flex-grow flex" data-horizontal="true" data-centerfocus="card">
|
||||
<div is="emby-itemscontainer" class="scrollSlider focuscontainer-x padded-left padded-right servers flex-grow" style="display: block; text-align: center;" data-hovermenu="false" data-multiselect="false"></div>
|
||||
<div is="emby-itemscontainer" class="scrollSlider focuscontainer-x servers flex-grow" style="display: block; text-align: center;" data-hovermenu="false" data-multiselect="false"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="padded-top padded-left padded-right flex flex-shrink-zero justify-content-center verticalSection flex-wrap-wrap" style="margin-left:auto;margin-right:auto;">
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue