diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000000..ac62bd07a12 --- /dev/null +++ b/.gitignore @@ -0,0 +1,575 @@ + +# Created by https://www.gitignore.io/api/node,rider,macos,linux,windows,visualstudio,visualstudiocode +# Edit at https://www.gitignore.io/?templates=node,rider,macos,linux,windows,visualstudio,visualstudiocode + +### Linux ### +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +### macOS ### +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### Node ### +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# TypeScript v1 declaration files +typings/ + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env +.env.test + +# parcel-bundler cache (https://parceljs.org/) +.cache + +# next.js build output +.next + +# nuxt.js build output +.nuxt + +# vuepress build output +.vuepress/dist + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +### Rider ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/modules.xml +# .idea/*.iml +# .idea/modules + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +### VisualStudioCode ### +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json + +### VisualStudioCode Patch ### +# Ignore all local history of files +.history + +### Windows ### +# Windows thumbnail cache files +Thumbs.db +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +### VisualStudio ### +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ +# ASP.NET Core default setup: bower directory is configured as wwwroot/lib/ and bower restore is true +**/wwwroot/lib/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- Backup*.rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# End of https://www.gitignore.io/api/node,rider,macos,linux,windows,visualstudio,visualstudiocode diff --git a/src/bower_components/emby-webcomponents/nowplayingbar/nowplayingbar.js b/src/bower_components/emby-webcomponents/nowplayingbar/nowplayingbar.js index 8ac00f13d7a..331b178b39d 100644 --- a/src/bower_components/emby-webcomponents/nowplayingbar/nowplayingbar.js +++ b/src/bower_components/emby-webcomponents/nowplayingbar/nowplayingbar.js @@ -186,13 +186,15 @@ define(['require', 'datetime', 'itemHelper', 'events', 'browser', 'imageLoader', volumeSliderContainer.classList.remove('hide'); } - volumeSlider.addEventListener('change', function () { - + function setVolume() { if (currentPlayer) { currentPlayer.setVolume(this.value); } + } + volumeSlider.addEventListener('change', setVolume.bind(this)); + volumeSlider.addEventListener('mousemove', setVolume.bind(this)); + volumeSlider.addEventListener('touchmove', setVolume.bind(this)); - }); positionSlider = elem.querySelector('.nowPlayingBarPositionSlider'); positionSlider.addEventListener('change', function () { @@ -392,6 +394,7 @@ define(['require', 'datetime', 'itemHelper', 'events', 'browser', 'imageLoader', var showMuteButton = true; var showVolumeSlider = true; + var progressElement = volumeSliderContainer.querySelector('.mdl-slider-background-lower'); if (supportedCommands.indexOf('ToggleMute') === -1) { showMuteButton = false; @@ -403,6 +406,10 @@ define(['require', 'datetime', 'itemHelper', 'events', 'browser', 'imageLoader', muteButton.querySelector('i').innerHTML = ''; } + if (progressElement) { + progressElement.style.width = (volumeLevel || 0) + '%'; + } + if (supportedCommands.indexOf('SetVolume') === -1) { showVolumeSlider = false; } @@ -779,4 +786,4 @@ define(['require', 'datetime', 'itemHelper', 'events', 'browser', 'imageLoader', } } }); -}); \ No newline at end of file +}); diff --git a/src/components/remotecontrol.js b/src/components/remotecontrol.js index 46096299605..58e69961e71 100644 --- a/src/components/remotecontrol.js +++ b/src/components/remotecontrol.js @@ -1,268 +1,479 @@ -define(["browser", "datetime", "backdrop", "libraryBrowser", "listView", "imageLoader", "playbackManager", "nowPlayingHelper", "events", "connectionManager", "apphost", "globalize", "cardStyle", "emby-itemscontainer", "css!css/nowplaying.css", "emby-ratingbutton"], function(browser, datetime, backdrop, libraryBrowser, listView, imageLoader, playbackManager, nowPlayingHelper, events, connectionManager, appHost, globalize) { +define(["browser", "datetime", "backdrop", "libraryBrowser", "listView", "imageLoader", "playbackManager", "nowPlayingHelper", "events", "connectionManager", "apphost", "globalize", "cardStyle", "emby-itemscontainer", "css!css/nowplaying.css", "emby-ratingbutton"], function (browser, datetime, backdrop, libraryBrowser, listView, imageLoader, playbackManager, nowPlayingHelper, events, connectionManager, appHost, globalize) { "use strict"; function showAudioMenu(context, player, button, item) { - var currentIndex = playbackManager.getAudioStreamIndex(player), - streams = playbackManager.audioTracks(player), - menuItems = streams.map(function(s) { - var menuItem = { - name: s.DisplayTitle, - id: s.Index - }; - return s.Index == currentIndex && (menuItem.selected = !0), menuItem - }); - require(["actionsheet"], function(actionsheet) { + var currentIndex = playbackManager.getAudioStreamIndex(player); + var streams = playbackManager.audioTracks(player); + var menuItems = streams.map(function (s) { + var menuItem = { + name: s.DisplayTitle, + id: s.Index + }; + + if (s.Index == currentIndex) { + menuItem.selected = true; + } + + return menuItem; + }); + + require(["actionsheet"], function (actionsheet) { actionsheet.show({ items: menuItems, positionTo: button, - callback: function(id) { - playbackManager.setAudioStreamIndex(parseInt(id), player) + callback: function (id) { + playbackManager.setAudioStreamIndex(parseInt(id), player); } - }) - }) + }); + }); } function showSubtitleMenu(context, player, button, item) { - var currentIndex = playbackManager.getSubtitleStreamIndex(player), - streams = playbackManager.subtitleTracks(player), - menuItems = streams.map(function(s) { - var menuItem = { - name: s.DisplayTitle, - id: s.Index - }; - return s.Index == currentIndex && (menuItem.selected = !0), menuItem - }); + var currentIndex = playbackManager.getSubtitleStreamIndex(player); + var streams = playbackManager.subtitleTracks(player); + var menuItems = streams.map(function (s) { + var menuItem = { + name: s.DisplayTitle, + id: s.Index + }; + + if (s.Index == currentIndex) { + menuItem.selected = true; + } + + return menuItem; + }); menuItems.unshift({ id: -1, name: globalize.translate("ButtonOff"), selected: null == currentIndex - }), require(["actionsheet"], function(actionsheet) { + }); + + require(["actionsheet"], function (actionsheet) { actionsheet.show({ items: menuItems, positionTo: button, - callback: function(id) { - playbackManager.setSubtitleStreamIndex(parseInt(id), player) + callback: function (id) { + playbackManager.setSubtitleStreamIndex(parseInt(id), player); } - }) - }) + }); + }); } function getNowPlayingNameHtml(nowPlayingItem, includeNonNameInfo) { - return nowPlayingHelper.getNowPlayingNames(nowPlayingItem, includeNonNameInfo).map(function(i) { - return i.text - }).join("
") + return nowPlayingHelper.getNowPlayingNames(nowPlayingItem, includeNonNameInfo).map(function (i) { + return i.text; + }).join("
"); } function seriesImageUrl(item, options) { - if ("Episode" !== item.Type) return null; - if (options = options || {}, options.type = options.type || "Primary", "Primary" === options.type && item.SeriesPrimaryImageTag) return options.tag = item.SeriesPrimaryImageTag, connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.SeriesId, options); + if ("Episode" !== item.Type) { + return null; + } + + options = options || {}; + options.type = options.type || "Primary"; + if ("Primary" === options.type && item.SeriesPrimaryImageTag) { + options.tag = item.SeriesPrimaryImageTag; + return connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.SeriesId, options); + } + if ("Thumb" === options.type) { - if (item.SeriesThumbImageTag) return options.tag = item.SeriesThumbImageTag, connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.SeriesId, options); - if (item.ParentThumbImageTag) return options.tag = item.ParentThumbImageTag, connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.ParentThumbItemId, options) + if (item.SeriesThumbImageTag) { + options.tag = item.SeriesThumbImageTag; + return connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.SeriesId, options); + } + + if (item.ParentThumbImageTag) { + options.tag = item.ParentThumbImageTag; + return connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.ParentThumbItemId, options); + } } - return null + + return null; } function imageUrl(item, options) { - return options = options || {}, options.type = options.type || "Primary", item.ImageTags && item.ImageTags[options.type] ? (options.tag = item.ImageTags[options.type], connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.PrimaryImageItemId || item.Id, options)) : item.AlbumId && item.AlbumPrimaryImageTag ? (options.tag = item.AlbumPrimaryImageTag, connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.AlbumId, options)) : null + options = options || {}; + options.type = options.type || "Primary"; + + if (item.ImageTags && item.ImageTags[options.type]) { + options.tag = item.ImageTags[options.type]; + return connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.PrimaryImageItemId || item.Id, options); + } + + if (item.AlbumId && item.AlbumPrimaryImageTag) { + options.tag = item.AlbumPrimaryImageTag; + return connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.AlbumId, options); + } + + return null; } function updateNowPlayingInfo(context, state) { - var item = state.NowPlayingItem, - displayName = item ? getNowPlayingNameHtml(item).replace("
", " - ") : ""; - context.querySelector(".nowPlayingPageTitle").innerHTML = displayName, displayName.length > 0 ? context.querySelector(".nowPlayingPageTitle").classList.remove("hide") : context.querySelector(".nowPlayingPageTitle").classList.add("hide"); + var item = state.NowPlayingItem; + var displayName = item ? getNowPlayingNameHtml(item).replace("
", " - ") : ""; + context.querySelector(".nowPlayingPageTitle").innerHTML = displayName; + + if (displayName.length > 0) { + context.querySelector(".nowPlayingPageTitle").classList.remove("hide"); + } else { + context.querySelector(".nowPlayingPageTitle").classList.add("hide"); + } + var url = item ? seriesImageUrl(item, { maxHeight: 300 }) || imageUrl(item, { maxHeight: 300 }) : null; - if (console.log("updateNowPlayingInfo"), setImageUrl(context, url), item) { + + console.log("updateNowPlayingInfo"); + setImageUrl(context, 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 || {}, - likes = null == userData.Likes ? "" : userData.Likes; - context.querySelector(".nowPlayingPageUserDataButtons").innerHTML = '' - }) - } else backdrop.clear(), context.querySelector(".nowPlayingPageUserDataButtons").innerHTML = "" + apiClient.getItem(apiClient.getCurrentUserId(), item.Id).then(function (fullItem) { + var userData = fullItem.UserData || {}; + var likes = null == userData.Likes ? "" : userData.Likes; + context.querySelector(".nowPlayingPageUserDataButtons").innerHTML = ''; + }); + } else { + backdrop.clear(); + context.querySelector(".nowPlayingPageUserDataButtons").innerHTML = ""; + } } function setImageUrl(context, url) { currentImgUrl = url; var imgContainer = context.querySelector(".nowPlayingPageImageContainer"); - url ? (imgContainer.innerHTML = '', imgContainer.classList.remove("hide")) : (imgContainer.classList.add("hide"), imgContainer.innerHTML = "") + + if (url) { + imgContainer.innerHTML = ''; + imgContainer.classList.remove("hide"); + } else { + imgContainer.classList.add("hide"); + imgContainer.innerHTML = ""; + } } function buttonEnabled(btn, enabled) { - btn.disabled = !enabled + btn.disabled = !enabled; } function buttonVisible(btn, enabled) { - enabled ? btn.classList.remove("hide") : btn.classList.add("hide") + if (enabled) { + btn.classList.remove("hide"); + } else { + btn.classList.add("hide"); + } } function updateSupportedCommands(context, commands) { - for (var all = context.querySelectorAll(".btnCommand"), i = 0, length = all.length; i < length; i++) buttonEnabled(all[i], -1 != commands.indexOf(all[i].getAttribute("data-command"))) + var all = context.querySelectorAll(".btnCommand"); + + for (var i = 0, length = all.length; i < length; i++) { + buttonEnabled(all[i], -1 != commands.indexOf(all[i].getAttribute("data-command"))); + } } + var currentImgUrl; - return function() { + return function () { function toggleRepeat(player) { - if (player) switch (playbackManager.getRepeatMode(player)) { - case "RepeatNone": + if (player) { + switch (playbackManager.getRepeatMode(player)) { + case "RepeatNone": playbackManager.setRepeatMode("RepeatAll", player); break; - case "RepeatAll": + + case "RepeatAll": playbackManager.setRepeatMode("RepeatOne", player); break; - case "RepeatOne": - playbackManager.setRepeatMode("RepeatNone", player) + + case "RepeatOne": + playbackManager.setRepeatMode("RepeatNone", player); + } } } function updatePlayerState(player, context, state) { lastPlayerState = state; - var item = state.NowPlayingItem, - playerInfo = playbackManager.getPlayerInfo(), - supportedCommands = playerInfo.supportedCommands; + var item = state.NowPlayingItem; + var playerInfo = playbackManager.getPlayerInfo(); + var supportedCommands = playerInfo.supportedCommands; currentPlayerSupportedCommands = supportedCommands; var playState = state.PlayState || {}; - buttonVisible(context.querySelector(".btnToggleFullscreen"), item && "Video" == item.MediaType && -1 != supportedCommands.indexOf("ToggleFullscreen")), updateAudioTracksDisplay(player, context), updateSubtitleTracksDisplay(player, context), -1 != supportedCommands.indexOf("DisplayMessage") ? context.querySelector(".sendMessageSection").classList.remove("hide") : context.querySelector(".sendMessageSection").classList.add("hide"), -1 != supportedCommands.indexOf("SendString") ? context.querySelector(".sendTextSection").classList.remove("hide") : context.querySelector(".sendTextSection").classList.add("hide"), 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); + buttonVisible(context.querySelector(".btnToggleFullscreen"), item && "Video" == item.MediaType && -1 != supportedCommands.indexOf("ToggleFullscreen")); + updateAudioTracksDisplay(player, context); + updateSubtitleTracksDisplay(player, context); + + if (-1 != supportedCommands.indexOf("DisplayMessage")) { + context.querySelector(".sendMessageSection").classList.remove("hide"); + } else { + context.querySelector(".sendMessageSection").classList.add("hide"); + } + + if (-1 != supportedCommands.indexOf("SendString")) { + context.querySelector(".sendTextSection").classList.remove("hide"); + } else { + context.querySelector(".sendTextSection").classList.add("hide"); + } + + 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); var positionSlider = context.querySelector(".nowPlayingPositionSlider"); + if (positionSlider && !positionSlider.dragging) { positionSlider.disabled = !playState.CanSeek; var isProgressClear = state.MediaSource && null == state.MediaSource.RunTimeTicks; - positionSlider.setIsClear(isProgressClear) + positionSlider.setIsClear(isProgressClear); + } + + updatePlayPauseState(playState.IsPaused, null != item); + updateTimeDisplay(playState.PositionTicks, item ? item.RunTimeTicks : null); + updatePlayerVolumeState(context, playState.IsMuted, playState.VolumeLevel); + + if (item && "Video" == item.MediaType) { + context.classList.remove("hideVideoButtons"); + } else { + context.classList.add("hideVideoButtons"); } - updatePlayPauseState(playState.IsPaused, null != item), updateTimeDisplay(playState.PositionTicks, item ? item.RunTimeTicks : null), updatePlayerVolumeState(context, playState.IsMuted, playState.VolumeLevel), item && "Video" == item.MediaType ? context.classList.remove("hideVideoButtons") : context.classList.add("hideVideoButtons"), updateRepeatModeDisplay(playState.RepeatMode), updateNowPlayingInfo(context, state) + + updateRepeatModeDisplay(playState.RepeatMode); + updateNowPlayingInfo(context, state); } function updateAudioTracksDisplay(player, context) { var supportedCommands = currentPlayerSupportedCommands; - buttonVisible(context.querySelector(".btnAudioTracks"), playbackManager.audioTracks(player).length > 1 && -1 != supportedCommands.indexOf("SetAudioStreamIndex")) + buttonVisible(context.querySelector(".btnAudioTracks"), playbackManager.audioTracks(player).length > 1 && -1 != supportedCommands.indexOf("SetAudioStreamIndex")); } function updateSubtitleTracksDisplay(player, context) { var supportedCommands = currentPlayerSupportedCommands; - buttonVisible(context.querySelector(".btnSubtitles"), playbackManager.subtitleTracks(player).length && -1 != supportedCommands.indexOf("SetSubtitleStreamIndex")) + buttonVisible(context.querySelector(".btnSubtitles"), playbackManager.subtitleTracks(player).length && -1 != supportedCommands.indexOf("SetSubtitleStreamIndex")); } function updateRepeatModeDisplay(repeatMode) { - var context = dlg, - toggleRepeatButton = context.querySelector(".repeatToggleButton"); - "RepeatAll" == repeatMode ? (toggleRepeatButton.innerHTML = "repeat", toggleRepeatButton.classList.add("repeatButton-active")) : "RepeatOne" == repeatMode ? (toggleRepeatButton.innerHTML = "repeat_one", toggleRepeatButton.classList.add("repeatButton-active")) : (toggleRepeatButton.innerHTML = "repeat", toggleRepeatButton.classList.remove("repeatButton-active")) + var context = dlg; + var toggleRepeatButton = context.querySelector(".repeatToggleButton"); + + if ("RepeatAll" == repeatMode) { + toggleRepeatButton.innerHTML = "repeat"; + toggleRepeatButton.classList.add("repeatButton-active"); + } else if ("RepeatOne" == repeatMode) { + toggleRepeatButton.innerHTML = "repeat_one"; + toggleRepeatButton.classList.add("repeatButton-active"); + } else { + toggleRepeatButton.innerHTML = "repeat"; + toggleRepeatButton.classList.remove("repeatButton-active"); + } } function updatePlayerVolumeState(context, isMuted, volumeLevel) { - var view = context, - supportedCommands = currentPlayerSupportedCommands, - showMuteButton = !0, - showVolumeSlider = !0; - 1 === supportedCommands.indexOf("Mute") && (showMuteButton = !1), -1 === supportedCommands.indexOf("SetVolume") && (showVolumeSlider = !1), currentPlayer.isLocalPlayer && appHost.supports("physicalvolumecontrol") && (showMuteButton = !1, showVolumeSlider = !1), isMuted ? (view.querySelector(".buttonMute").setAttribute("title", globalize.translate("Unmute")), view.querySelector(".buttonMute i").innerHTML = "") : (view.querySelector(".buttonMute").setAttribute("title", globalize.translate("Mute")), view.querySelector(".buttonMute i").innerHTML = ""), showMuteButton ? view.querySelector(".buttonMute").classList.remove("hide") : view.querySelector(".buttonMute").classList.add("hide"); - var nowPlayingVolumeSlider = context.querySelector(".nowPlayingVolumeSlider"), - nowPlayingVolumeSliderContainer = context.querySelector(".nowPlayingVolumeSliderContainer"); - nowPlayingVolumeSlider && (showVolumeSlider ? nowPlayingVolumeSliderContainer.classList.remove("hide") : nowPlayingVolumeSliderContainer.classList.add("hide"), nowPlayingVolumeSlider.dragging || (nowPlayingVolumeSlider.value = volumeLevel || 0)) + var view = context; + var supportedCommands = currentPlayerSupportedCommands; + var showMuteButton = true; + var showVolumeSlider = true; + var volumeSlider = view.querySelector('.nowPlayingVolumeSliderContainer'); + var progressElement = volumeSlider.querySelector('.mdl-slider-background-lower'); + + if (-1 === supportedCommands.indexOf("Mute")) { + showMuteButton = false; + } + + if (-1 === supportedCommands.indexOf("SetVolume")) { + showVolumeSlider = false; + } + + if (currentPlayer.isLocalPlayer && appHost.supports("physicalvolumecontrol")) { + showMuteButton = false; + showVolumeSlider = false; + } + + if (isMuted) { + view.querySelector(".buttonMute").setAttribute("title", globalize.translate("Unmute")); + view.querySelector(".buttonMute i").innerHTML = ""; + } else { + view.querySelector(".buttonMute").setAttribute("title", globalize.translate("Mute")); + view.querySelector(".buttonMute i").innerHTML = ""; + } + + if (progressElement) { + progressElement.style.width = (volumeLevel || 0) + '%'; + } + + if (showMuteButton) { + view.querySelector(".buttonMute").classList.remove("hide"); + } else { + view.querySelector(".buttonMute").classList.add("hide"); + } + + 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.dragging) { + nowPlayingVolumeSlider.value = volumeLevel || 0; + } + } } function updatePlayPauseState(isPaused, isActive) { - var context = dlg, - btnPlayPause = context.querySelector(".btnPlayPause"); - btnPlayPause.querySelector("i").innerHTML = isPaused ? "play_arrow" : "pause", buttonVisible(btnPlayPause, isActive) + var context = dlg; + var btnPlayPause = context.querySelector(".btnPlayPause"); + btnPlayPause.querySelector("i").innerHTML = isPaused ? "play_arrow" : "pause"; + buttonVisible(btnPlayPause, isActive); } function updateTimeDisplay(positionTicks, runtimeTicks) { - var context = dlg, - positionSlider = context.querySelector(".nowPlayingPositionSlider"); - if (positionSlider && !positionSlider.dragging) + var context = dlg; + var positionSlider = context.querySelector(".nowPlayingPositionSlider"); + + if (positionSlider && !positionSlider.dragging) { if (runtimeTicks) { var pct = positionTicks / runtimeTicks; - pct *= 100, positionSlider.value = pct - } else positionSlider.value = 0; - context.querySelector(".positionTime").innerHTML = null == positionTicks ? "--:--" : datetime.getDisplayRunningTime(positionTicks), context.querySelector(".runtime").innerHTML = null != runtimeTicks ? datetime.getDisplayRunningTime(runtimeTicks) : "--:--" + pct *= 100; + positionSlider.value = pct; + } else { + positionSlider.value = 0; + } + } + + context.querySelector(".positionTime").innerHTML = null == positionTicks ? "--:--" : datetime.getDisplayRunningTime(positionTicks); + context.querySelector(".runtime").innerHTML = null != runtimeTicks ? datetime.getDisplayRunningTime(runtimeTicks) : "--:--"; } function getPlaylistItems(player) { - return playbackManager.getPlaylist(player) + return playbackManager.getPlaylist(player); } function loadPlaylist(context, player) { - getPlaylistItems(player).then(function(items) { + getPlaylistItems(player).then(function (items) { var html = ""; html += listView.getListViewHtml({ items: items, - smallIcon: !0, + smallIcon: true, action: "setplaylistindex", - enableUserDataButtons: !1, + enableUserDataButtons: false, rightButtons: [{ icon: "", title: globalize.translate("ButtonRemove"), id: "remove" }], - dragHandle: !0 - }), items.length ? context.querySelector(".playlistSection").classList.remove("hide") : context.querySelector(".playlistSection").classList.add("hide"); + dragHandle: true + }); + + if (items.length) { + context.querySelector(".playlistSection").classList.remove("hide"); + } else { + context.querySelector(".playlistSection").classList.add("hide"); + } + var itemsContainer = context.querySelector(".playlist"); itemsContainer.innerHTML = html; var playlistItemId = playbackManager.getCurrentPlaylistItemId(player); + if (playlistItemId) { var img = itemsContainer.querySelector('.listItem[data-playlistItemId="' + playlistItemId + '"] .listItemImage'); - img && (img.classList.remove("lazy"), img.classList.add("playlistIndexIndicatorImage")) + + if (img) { + img.classList.remove("lazy"); + img.classList.add("playlistIndexIndicatorImage"); + } } - imageLoader.lazyChildren(itemsContainer) - }) + + imageLoader.lazyChildren(itemsContainer); + }); } function onPlaybackStart(e, state) { console.log("remotecontrol event: " + e.type); var player = this; - onStateChanged.call(player, e, state) + onStateChanged.call(player, e, state); } function onRepeatModeChange(e) { var player = this; - updateRepeatModeDisplay(playbackManager.getRepeatMode(player)) + updateRepeatModeDisplay(playbackManager.getRepeatMode(player)); } function onPlaylistUpdate(e) { - loadPlaylist(dlg, this) + loadPlaylist(dlg, this); } function onPlaylistItemRemoved(e, info) { - for (var context = dlg, playlistItemIds = info.playlistItemIds, i = 0, length = playlistItemIds.length; i < length; i++) { + var context = dlg; + var playlistItemIds = info.playlistItemIds; + + for (var i = 0, length = playlistItemIds.length; i < length; i++) { var listItem = context.querySelector('.listItem[data-playlistItemId="' + playlistItemIds[i] + '"]'); - listItem && listItem.parentNode.removeChild(listItem) + + if (listItem) { + listItem.parentNode.removeChild(listItem); + } } } function onPlaybackStopped(e, state) { console.log("remotecontrol event: " + e.type); var player = this; - state.NextMediaType || (updatePlayerState(player, dlg, {}), loadPlaylist(dlg)) + + if (!state.NextMediaType) { + updatePlayerState(player, dlg, {}); + loadPlaylist(dlg); + } } function onPlayPauseStateChanged(e) { - updatePlayPauseState(this.paused(), !0) + updatePlayPauseState(this.paused(), true); } function onStateChanged(event, state) { var player = this; - updatePlayerState(player, dlg, state), loadPlaylist(dlg, player) + updatePlayerState(player, dlg, state); + loadPlaylist(dlg, player); } function onTimeUpdate(e) { - var now = (new Date).getTime(); + var now = new Date().getTime(); + if (!(now - lastUpdateTime < 700)) { lastUpdateTime = now; var player = this; - currentRuntimeTicks = playbackManager.duration(player), updateTimeDisplay(playbackManager.currentTime(player), currentRuntimeTicks) + currentRuntimeTicks = playbackManager.duration(player); + updateTimeDisplay(playbackManager.currentTime(player), currentRuntimeTicks); } } function onVolumeChanged(e) { var player = this; - updatePlayerVolumeState(dlg, player.isMuted(), player.getVolume()) + updatePlayerVolumeState(dlg, player.isMuted(), player.getVolume()); } function releaseCurrentPlayer() { var player = currentPlayer; - player && (events.off(player, "playbackstart", onPlaybackStart), events.off(player, "statechange", onStateChanged), events.off(player, "repeatmodechange", onRepeatModeChange), events.off(player, "playlistitemremove", onPlaylistUpdate), events.off(player, "playlistitemmove", onPlaylistUpdate), events.off(player, "playbackstop", onPlaybackStopped), events.off(player, "volumechange", onVolumeChanged), events.off(player, "pause", onPlayPauseStateChanged), events.off(player, "unpause", onPlayPauseStateChanged), events.off(player, "timeupdate", onTimeUpdate), currentPlayer = null) + + if (player) { + events.off(player, "playbackstart", onPlaybackStart); + events.off(player, "statechange", onStateChanged); + events.off(player, "repeatmodechange", onRepeatModeChange); + events.off(player, "playlistitemremove", onPlaylistUpdate); + events.off(player, "playlistitemmove", onPlaylistUpdate); + events.off(player, "playbackstop", onPlaybackStopped); + events.off(player, "volumechange", onVolumeChanged); + events.off(player, "pause", onPlayPauseStateChanged); + events.off(player, "unpause", onPlayPauseStateChanged); + events.off(player, "timeupdate", onTimeUpdate); + currentPlayer = null; + } } function bindToPlayer(context, player) { @@ -270,141 +481,238 @@ define(["browser", "datetime", "backdrop", "libraryBrowser", "listView", "imageL var state = playbackManager.getPlayerState(player); onStateChanged.call(player, { type: "init" - }, state), events.on(player, "playbackstart", onPlaybackStart), events.on(player, "statechange", onStateChanged), events.on(player, "repeatmodechange", onRepeatModeChange), events.on(player, "playlistitemremove", onPlaylistItemRemoved), events.on(player, "playlistitemmove", onPlaylistUpdate), events.on(player, "playbackstop", onPlaybackStopped), events.on(player, "volumechange", onVolumeChanged), events.on(player, "pause", onPlayPauseStateChanged), events.on(player, "unpause", onPlayPauseStateChanged), events.on(player, "timeupdate", onTimeUpdate); - var playerInfo = playbackManager.getPlayerInfo(), - supportedCommands = playerInfo.supportedCommands; - currentPlayerSupportedCommands = supportedCommands, updateSupportedCommands(context, supportedCommands) + }, state); + events.on(player, "playbackstart", onPlaybackStart); + events.on(player, "statechange", onStateChanged); + events.on(player, "repeatmodechange", onRepeatModeChange); + events.on(player, "playlistitemremove", onPlaylistItemRemoved); + events.on(player, "playlistitemmove", onPlaylistUpdate); + events.on(player, "playbackstop", onPlaybackStopped); + events.on(player, "volumechange", onVolumeChanged); + events.on(player, "pause", onPlayPauseStateChanged); + events.on(player, "unpause", onPlayPauseStateChanged); + events.on(player, "timeupdate", onTimeUpdate); + var playerInfo = playbackManager.getPlayerInfo(); + var supportedCommands = playerInfo.supportedCommands; + currentPlayerSupportedCommands = supportedCommands; + updateSupportedCommands(context, supportedCommands); } } function onBtnCommandClick() { - currentPlayer && (this.classList.contains("repeatToggleButton") ? toggleRepeat(currentPlayer) : playbackManager.sendCommand({ - Name: this.getAttribute("data-command") - }, currentPlayer)) + if (currentPlayer) { + if (this.classList.contains("repeatToggleButton")) { + toggleRepeat(currentPlayer); + } else { + playbackManager.sendCommand({ + Name: this.getAttribute("data-command") + }, currentPlayer); + } + } } function getSaveablePlaylistItems() { - return getPlaylistItems(currentPlayer).then(function(items) { - return items.filter(function(i) { + return getPlaylistItems(currentPlayer).then(function (items) { return i.Id && i.ServerId - }) - }) + }); } function savePlaylist() { - require(["playlistEditor"], function(playlistEditor) { - getSaveablePlaylistItems().then(function(items) { + require(["playlistEditor"], function (playlistEditor) { + getSaveablePlaylistItems().then(function (items) { var serverId = items.length ? items[0].ServerId : ApiClient.serverId(); - (new playlistEditor).show({ - items: items.map(function(i) { - return i.Id + new playlistEditor().show({ + items: items.map(function (i) { + return i.Id; }), serverId: serverId, - enableAddToPlayQueue: !1, + enableAddToPlayQueue: false, defaultValue: "new" - }) - }) - }) + }); + }); + }); } function bindEvents(context) { - for (var btnCommand = context.querySelectorAll(".btnCommand"), i = 0, length = btnCommand.length; i < length; i++) btnCommand[i].addEventListener("click", onBtnCommandClick); - context.querySelector(".btnToggleFullscreen").addEventListener("click", function(e) { - currentPlayer && playbackManager.sendCommand({ - Name: e.target.getAttribute("data-command") - }, currentPlayer) - }), context.querySelector(".btnAudioTracks").addEventListener("click", function(e) { - currentPlayer && lastPlayerState && lastPlayerState.NowPlayingItem && showAudioMenu(context, currentPlayer, e.target, lastPlayerState.NowPlayingItem) - }), context.querySelector(".btnSubtitles").addEventListener("click", function(e) { - currentPlayer && lastPlayerState && lastPlayerState.NowPlayingItem && showSubtitleMenu(context, currentPlayer, e.target, lastPlayerState.NowPlayingItem) - }), context.querySelector(".btnStop").addEventListener("click", function() { - currentPlayer && playbackManager.stop(currentPlayer) - }), context.querySelector(".btnPlayPause").addEventListener("click", function() { - currentPlayer && playbackManager.playPause(currentPlayer) - }), context.querySelector(".btnNextTrack").addEventListener("click", function() { - currentPlayer && playbackManager.nextTrack(currentPlayer) - }), context.querySelector(".btnRewind").addEventListener("click", function() { - currentPlayer && playbackManager.rewind(currentPlayer) - }), context.querySelector(".btnFastForward").addEventListener("click", function() { - currentPlayer && playbackManager.fastForward(currentPlayer) - }), context.querySelector(".btnPreviousTrack").addEventListener("click", function() { - currentPlayer && playbackManager.previousTrack(currentPlayer) - }), context.querySelector(".nowPlayingPositionSlider").addEventListener("change", function() { + var btnCommand = context.querySelectorAll(".btnCommand"); + + for (var i = 0, length = btnCommand.length; i < length; i++) { + btnCommand[i].addEventListener("click", onBtnCommandClick); + } + + context.querySelector(".btnToggleFullscreen").addEventListener("click", function (e) { + if (currentPlayer) { + playbackManager.sendCommand({ + Name: e.target.getAttribute("data-command") + }, currentPlayer); + } + }); + context.querySelector(".btnAudioTracks").addEventListener("click", function (e) { + if (currentPlayer && lastPlayerState && lastPlayerState.NowPlayingItem) { + showAudioMenu(context, currentPlayer, e.target, lastPlayerState.NowPlayingItem); + } + }); + context.querySelector(".btnSubtitles").addEventListener("click", function (e) { + if (currentPlayer && lastPlayerState && lastPlayerState.NowPlayingItem) { + showSubtitleMenu(context, currentPlayer, e.target, lastPlayerState.NowPlayingItem); + } + }); + context.querySelector(".btnStop").addEventListener("click", function () { + if (currentPlayer) { + playbackManager.stop(currentPlayer); + } + }); + context.querySelector(".btnPlayPause").addEventListener("click", function () { + if (currentPlayer) { + playbackManager.playPause(currentPlayer); + } + }); + context.querySelector(".btnNextTrack").addEventListener("click", function () { + if (currentPlayer) { + playbackManager.nextTrack(currentPlayer); + } + }); + context.querySelector(".btnRewind").addEventListener("click", function () { + if (currentPlayer) { + playbackManager.rewind(currentPlayer); + } + }); + context.querySelector(".btnFastForward").addEventListener("click", function () { + if (currentPlayer) { + playbackManager.fastForward(currentPlayer); + } + }); + context.querySelector(".btnPreviousTrack").addEventListener("click", function () { + if (currentPlayer) { + playbackManager.previousTrack(currentPlayer); + } + }); + context.querySelector(".nowPlayingPositionSlider").addEventListener("change", function () { var value = this.value; + if (currentPlayer) { var newPercent = parseFloat(value); - playbackManager.seekPercent(newPercent, currentPlayer) + playbackManager.seekPercent(newPercent, currentPlayer); } - }), context.querySelector(".nowPlayingPositionSlider").getBubbleText = function(value) { + }); + + context.querySelector(".nowPlayingPositionSlider").getBubbleText = function (value) { var state = lastPlayerState; - if (!state || !state.NowPlayingItem || !currentRuntimeTicks) return "--:--"; + + if (!state || !state.NowPlayingItem || !currentRuntimeTicks) { + return "--:--"; + } + var ticks = currentRuntimeTicks; - return ticks /= 100, ticks *= value, datetime.getDisplayRunningTime(ticks) - }, context.querySelector(".nowPlayingVolumeSlider").addEventListener("change", function() { - playbackManager.setVolume(this.value, currentPlayer) - }), context.querySelector(".buttonMute").addEventListener("click", function() { - playbackManager.toggleMute(currentPlayer) + ticks /= 100; + ticks *= value; + return datetime.getDisplayRunningTime(ticks); + }; + + context.querySelector(".nowPlayingVolumeSlider").addEventListener("change", function () { + playbackManager.setVolume(this.value, currentPlayer); + }); + context.querySelector(".nowPlayingVolumeSlider").addEventListener("mousemove", function () { + playbackManager.setVolume(this.value, currentPlayer); + }); + context.querySelector(".nowPlayingVolumeSlider").addEventListener("touchmove", function () { + playbackManager.setVolume(this.value, currentPlayer); + }); + context.querySelector(".buttonMute").addEventListener("click", function () { + playbackManager.toggleMute(currentPlayer); }); var playlistContainer = context.querySelector(".playlist"); - playlistContainer.addEventListener("action-remove", function(e) { - playbackManager.removeFromPlaylist([e.detail.playlistItemId], currentPlayer) - }), playlistContainer.addEventListener("itemdrop", function(e) { - var newIndex = e.detail.newIndex, - playlistItemId = e.detail.playlistItemId; - playbackManager.movePlaylistItem(playlistItemId, newIndex, currentPlayer) - }), context.querySelector(".btnSavePlaylist").addEventListener("click", savePlaylist) + playlistContainer.addEventListener("action-remove", function (e) { + playbackManager.removeFromPlaylist([e.detail.playlistItemId], currentPlayer); + }); + playlistContainer.addEventListener("itemdrop", function (e) { + var newIndex = e.detail.newIndex; + var playlistItemId = e.detail.playlistItemId; + playbackManager.movePlaylistItem(playlistItemId, newIndex, currentPlayer); + }); + context.querySelector(".btnSavePlaylist").addEventListener("click", savePlaylist); } function onPlayerChange() { - bindToPlayer(dlg, playbackManager.getCurrentPlayer()) + bindToPlayer(dlg, playbackManager.getCurrentPlayer()); } function onMessageSubmit(e) { var form = e.target; - return playbackManager.sendCommand({ + playbackManager.sendCommand({ Name: "DisplayMessage", Arguments: { Header: form.querySelector("#txtMessageTitle").value, Text: form.querySelector("#txtMessageText", form).value } - }, currentPlayer), form.querySelector("input").value = "", require(["toast"], function(toast) { - toast("Message sent.") - }), e.preventDefault(), e.stopPropagation(), !1 + }, currentPlayer); + form.querySelector("input").value = ""; + + require(["toast"], function (toast) { + toast("Message sent."); + }); + + e.preventDefault(); + e.stopPropagation(); + return false; } function onSendStringSubmit(e) { var form = e.target; - return playbackManager.sendCommand({ + playbackManager.sendCommand({ Name: "SendString", Arguments: { String: form.querySelector("#txtTypeText", form).value } - }, currentPlayer), form.querySelector("input").value = "", require(["toast"], function(toast) { - toast("Text sent.") - }), e.preventDefault(), e.stopPropagation(), !1 + }, currentPlayer); + form.querySelector("input").value = ""; + + require(["toast"], function (toast) { + toast("Text sent."); + }); + + e.preventDefault(); + e.stopPropagation(); + return false; } function init(ownerView, context) { - bindEvents(context), context.querySelector(".sendMessageForm").addEventListener("submit", onMessageSubmit), context.querySelector(".typeTextForm").addEventListener("submit", onSendStringSubmit), events.on(playbackManager, "playerchange", onPlayerChange) + bindEvents(context); + context.querySelector(".sendMessageForm").addEventListener("submit", onMessageSubmit); + context.querySelector(".typeTextForm").addEventListener("submit", onSendStringSubmit); + events.on(playbackManager, "playerchange", onPlayerChange); } function onDialogClosed(e) { - releaseCurrentPlayer(), events.off(playbackManager, "playerchange", onPlayerChange), lastPlayerState = null + releaseCurrentPlayer(); + events.off(playbackManager, "playerchange", onPlayerChange); + lastPlayerState = null; } function onShow(context, tab) { - currentImgUrl = null, bindToPlayer(context, playbackManager.getCurrentPlayer()) - } - var dlg, currentPlayer, lastPlayerState, currentPlayerSupportedCommands = [], - lastUpdateTime = 0, - currentRuntimeTicks = 0, - self = this; - self.init = function(ownerView, context) { - dlg = context, init(ownerView, dlg) - }, self.onShow = function() { - onShow(dlg, window.location.hash) - }, self.destroy = function() { - onDialogClosed() - } - } -}); \ No newline at end of file + currentImgUrl = null; + bindToPlayer(context, playbackManager.getCurrentPlayer()); + } + + var dlg; + var currentPlayer; + var lastPlayerState; + var currentPlayerSupportedCommands = []; + var lastUpdateTime = 0; + var currentRuntimeTicks = 0; + var self = this; + + self.init = function (ownerView, context) { + dlg = context; + init(ownerView, dlg); + }; + + self.onShow = function () { + onShow(dlg, window.location.hash); + }; + + self.destroy = function () { + onDialogClosed(); + }; + }; +}); diff --git a/src/scripts/videoosd.js b/src/scripts/videoosd.js index d4c97bc1288..c9befe03c5f 100644 --- a/src/scripts/videoosd.js +++ b/src/scripts/videoosd.js @@ -1,152 +1,335 @@ -define(["playbackManager", "dom", "inputmanager", "datetime", "itemHelper", "mediaInfo", "focusManager", "imageLoader", "scrollHelper", "events", "connectionManager", "browser", "globalize", "apphost", "layoutManager", "userSettings", "scrollStyles", "emby-slider", "paper-icon-button-light", "css!css/videoosd"], function(playbackManager, dom, inputManager, datetime, itemHelper, mediaInfo, focusManager, imageLoader, scrollHelper, events, connectionManager, browser, globalize, appHost, layoutManager, userSettings) { +define(["playbackManager", "dom", "inputmanager", "datetime", "itemHelper", "mediaInfo", "focusManager", "imageLoader", "scrollHelper", "events", "connectionManager", "browser", "globalize", "apphost", "layoutManager", "userSettings", "scrollStyles", "emby-slider", "paper-icon-button-light", "css!css/videoosd"], function (playbackManager, dom, inputManager, datetime, itemHelper, mediaInfo, focusManager, imageLoader, scrollHelper, events, connectionManager, browser, globalize, appHost, layoutManager, userSettings) { "use strict"; function seriesImageUrl(item, options) { - if ("Episode" !== item.Type) return null; - if (options = options || {}, options.type = options.type || "Primary", "Primary" === options.type && item.SeriesPrimaryImageTag) return options.tag = item.SeriesPrimaryImageTag, connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.SeriesId, options); + if ("Episode" !== item.Type) { + return null; + } + + options = options || {}; + options.type = options.type || "Primary"; + if ("Primary" === options.type && item.SeriesPrimaryImageTag) { + options.tag = item.SeriesPrimaryImageTag; + return connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.SeriesId, options); + } + if ("Thumb" === options.type) { - if (item.SeriesThumbImageTag) return options.tag = item.SeriesThumbImageTag, connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.SeriesId, options); - if (item.ParentThumbImageTag) return options.tag = item.ParentThumbImageTag, connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.ParentThumbItemId, options) + if (item.SeriesThumbImageTag) { + options.tag = item.SeriesThumbImageTag; + return connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.SeriesId, options); + } + + if (item.ParentThumbImageTag) { + options.tag = item.ParentThumbImageTag; + return connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.ParentThumbItemId, options); + } } - return null + + return null; } function imageUrl(item, options) { - return options = options || {}, options.type = options.type || "Primary", item.ImageTags && item.ImageTags[options.type] ? (options.tag = item.ImageTags[options.type], connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.PrimaryImageItemId || item.Id, options)) : "Primary" === options.type && item.AlbumId && item.AlbumPrimaryImageTag ? (options.tag = item.AlbumPrimaryImageTag, connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.AlbumId, options)) : null + options = options || {}; + options.type = options.type || "Primary"; + + if (item.ImageTags && item.ImageTags[options.type]) { + options.tag = item.ImageTags[options.type]; + return connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.PrimaryImageItemId || item.Id, options); + } + + if ("Primary" === options.type && item.AlbumId && item.AlbumPrimaryImageTag) { + options.tag = item.AlbumPrimaryImageTag; + return connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.AlbumId, options); + } + + return null; } function logoImageUrl(item, apiClient, options) { - return options = options || {}, options.type = "Logo", item.ImageTags && item.ImageTags.Logo ? (options.tag = item.ImageTags.Logo, apiClient.getScaledImageUrl(item.Id, options)) : item.ParentLogoImageTag ? (options.tag = item.ParentLogoImageTag, apiClient.getScaledImageUrl(item.ParentLogoItemId, options)) : null + options = options || {}; + options.type = "Logo"; + + if (item.ImageTags && item.ImageTags.Logo) { + options.tag = item.ImageTags.Logo; + return apiClient.getScaledImageUrl(item.Id, options); + } + + if (item.ParentLogoImageTag) { + options.tag = item.ParentLogoImageTag; + return apiClient.getScaledImageUrl(item.ParentLogoItemId, options); + } + + return null; } - return function(view, params) { + return function (view, params) { function onVerticalSwipe(e, elem, data) { var player = currentPlayer; + if (player) { - var deltaY = data.currentDeltaY, - windowSize = dom.getWindowSize(); - if (supportsBrightnessChange && data.clientX < windowSize.innerWidth / 2) return void doBrightnessTouch(deltaY, player, windowSize.innerHeight); - doVolumeTouch(deltaY, player, windowSize.innerHeight) + var deltaY = data.currentDeltaY; + var windowSize = dom.getWindowSize(); + + if (supportsBrightnessChange && data.clientX < windowSize.innerWidth / 2) { + return void doBrightnessTouch(deltaY, player, windowSize.innerHeight); + } + + doVolumeTouch(deltaY, player, windowSize.innerHeight); } } function doBrightnessTouch(deltaY, player, viewHeight) { - var delta = -deltaY / viewHeight * 100, - newValue = playbackManager.getBrightness(player) + delta; - newValue = Math.min(newValue, 100), newValue = Math.max(newValue, 0), playbackManager.setBrightness(newValue, player) + var delta = -deltaY / viewHeight * 100; + var 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, - newValue = playbackManager.getVolume(player) + delta; - newValue = Math.min(newValue, 100), newValue = Math.max(newValue, 0), playbackManager.setVolume(newValue, player) + var delta = -deltaY / viewHeight * 100; + var 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; + if (null != clientX) { - clientX < dom.getWindowSize().innerWidth / 2 ? playbackManager.rewind(currentPlayer) : playbackManager.fastForward(currentPlayer), e.preventDefault(), e.stopPropagation() + if (clientX < dom.getWindowSize().innerWidth / 2) { + playbackManager.rewind(currentPlayer); + } else { + playbackManager.fastForward(currentPlayer); + } + + e.preventDefault(); + e.stopPropagation(); } } function getDisplayItem(item) { if ("TvChannel" === item.Type) { var apiClient = connectionManager.getApiClient(item.ServerId); - return apiClient.getItem(apiClient.getCurrentUserId(), item.Id).then(function(refreshedItem) { + return apiClient.getItem(apiClient.getCurrentUserId(), item.Id).then(function (refreshedItem) { return { originalItem: refreshedItem, displayItem: refreshedItem.CurrentProgram - } - }) + }; + }); } + return Promise.resolve({ originalItem: item - }) + }); } function updateRecordingButton(item) { - if (!item || "Program" !== item.Type) return recordingButtonManager && (recordingButtonManager.destroy(), recordingButtonManager = null), void view.querySelector(".btnRecord").classList.add("hide"); - connectionManager.getApiClient(item.ServerId).getCurrentUser().then(function(user) { - user.Policy.EnableLiveTvManagement && require(["recordingButton"], function(RecordingButton) { - if (recordingButtonManager) return void recordingButtonManager.refreshItem(item); - recordingButtonManager = new RecordingButton({ - item: item, - button: view.querySelector(".btnRecord") - }), view.querySelector(".btnRecord").classList.remove("hide") - }) - }) + if (!item || "Program" !== item.Type) { + if (recordingButtonManager) { + recordingButtonManager.destroy(); + recordingButtonManager = null; + } + + return void view.querySelector(".btnRecord").classList.add("hide"); + } + + connectionManager.getApiClient(item.ServerId).getCurrentUser().then(function (user) { + if (user.Policy.EnableLiveTvManagement) { + require(["recordingButton"], function (RecordingButton) { + if (recordingButtonManager) { + return void recordingButtonManager.refreshItem(item); + } + + recordingButtonManager = new RecordingButton({ + item: item, + button: view.querySelector(".btnRecord") + }); + view.querySelector(".btnRecord").classList.remove("hide"); + }); + } + }); } function updateDisplayItem(itemInfo) { var item = itemInfo.originalItem; currentItem = item; var displayItem = itemInfo.displayItem || item; - updateRecordingButton(displayItem), setPoster(displayItem, item); + updateRecordingButton(displayItem); + setPoster(displayItem, item); var parentName = displayItem.SeriesName || displayItem.Album; - (displayItem.EpisodeTitle || displayItem.IsSeries) && (parentName = displayItem.Name), setTitle(displayItem, parentName); - var titleElement, osdTitle = view.querySelector(".osdTitle"); + + if (displayItem.EpisodeTitle || displayItem.IsSeries) { + parentName = displayItem.Name; + } + + setTitle(displayItem, parentName); + var titleElement; + var osdTitle = view.querySelector(".osdTitle"); titleElement = osdTitle; var displayName = itemHelper.getDisplayName(displayItem, { includeParentInfo: "Program" !== displayItem.Type, includeIndexNumber: "Program" !== displayItem.Type }); - !displayName && displayItem.Type, titleElement.innerHTML = displayName, displayName ? titleElement.classList.remove("hide") : titleElement.classList.add("hide"); + + if (!displayName) { + displayItem.Type; + } + + titleElement.innerHTML = displayName; + + if (displayName) { + titleElement.classList.remove("hide"); + } else { + titleElement.classList.add("hide"); + } + var mediaInfoHtml = mediaInfo.getPrimaryMediaInfoHtml(displayItem, { - runtime: !1, - subtitles: !1, - tomatoes: !1, - endsAt: !1, - episodeTitle: !1, - originalAirDate: "Program" !== displayItem.Type, - episodeTitleIndexNumber: "Program" !== displayItem.Type, - programIndicator: !1 - }), - osdMediaInfo = view.querySelector(".osdMediaInfo"); - osdMediaInfo.innerHTML = mediaInfoHtml, mediaInfoHtml ? osdMediaInfo.classList.remove("hide") : osdMediaInfo.classList.add("hide"); - var secondaryMediaInfo = view.querySelector(".osdSecondaryMediaInfo"), - secondaryMediaInfoHtml = mediaInfo.getSecondaryMediaInfoHtml(displayItem, { - startDate: !1, - programTime: !1 - }); - secondaryMediaInfo.innerHTML = secondaryMediaInfoHtml, secondaryMediaInfoHtml ? secondaryMediaInfo.classList.remove("hide") : secondaryMediaInfo.classList.add("hide"), displayName ? view.querySelector(".osdMainTextContainer").classList.remove("hide") : view.querySelector(".osdMainTextContainer").classList.add("hide"), enableProgressByTimeOfDay ? (setDisplayTime(startTimeText, displayItem.StartDate), setDisplayTime(endTimeText, displayItem.EndDate), startTimeText.classList.remove("hide"), endTimeText.classList.remove("hide"), programStartDateMs = displayItem.StartDate ? datetime.parseISO8601Date(displayItem.StartDate).getTime() : 0, programEndDateMs = displayItem.EndDate ? datetime.parseISO8601Date(displayItem.EndDate).getTime() : 0) : (startTimeText.classList.add("hide"), endTimeText.classList.add("hide"), startTimeText.innerHTML = "", endTimeText.innerHTML = "", programStartDateMs = 0, programEndDateMs = 0) + runtime: false, + subtitles: false, + tomatoes: false, + endsAt: false, + episodeTitle: false, + originalAirDate: "Program" !== displayItem.Type, + episodeTitleIndexNumber: "Program" !== displayItem.Type, + programIndicator: false + }); + var osdMediaInfo = view.querySelector(".osdMediaInfo"); + osdMediaInfo.innerHTML = mediaInfoHtml; + + if (mediaInfoHtml) { + osdMediaInfo.classList.remove("hide"); + } else { + osdMediaInfo.classList.add("hide"); + } + + var secondaryMediaInfo = view.querySelector(".osdSecondaryMediaInfo"); + var secondaryMediaInfoHtml = mediaInfo.getSecondaryMediaInfoHtml(displayItem, { + startDate: false, + programTime: false + }); + secondaryMediaInfo.innerHTML = secondaryMediaInfoHtml; + + if (secondaryMediaInfoHtml) { + secondaryMediaInfo.classList.remove("hide"); + } else { + secondaryMediaInfo.classList.add("hide"); + } + + if (displayName) { + view.querySelector(".osdMainTextContainer").classList.remove("hide"); + } else { + view.querySelector(".osdMainTextContainer").classList.add("hide"); + } + + if (enableProgressByTimeOfDay) { + setDisplayTime(startTimeText, displayItem.StartDate); + setDisplayTime(endTimeText, displayItem.EndDate); + startTimeText.classList.remove("hide"); + endTimeText.classList.remove("hide"); + programStartDateMs = displayItem.StartDate ? datetime.parseISO8601Date(displayItem.StartDate).getTime() : 0; + programEndDateMs = displayItem.EndDate ? datetime.parseISO8601Date(displayItem.EndDate).getTime() : 0; + } else { + startTimeText.classList.add("hide"); + endTimeText.classList.add("hide"); + startTimeText.innerHTML = ""; + endTimeText.innerHTML = ""; + programStartDateMs = 0; + programEndDateMs = 0; + } } function getDisplayTimeWithoutAmPm(date, showSeconds) { - return showSeconds ? datetime.toLocaleTimeString(date, { - hour: "numeric", - minute: "2-digit", - second: "2-digit" - }).toLowerCase().replace("am", "").replace("pm", "").trim() : datetime.getDisplayTime(date).toLowerCase().replace("am", "").replace("pm", "").trim() + if (showSeconds) { + return datetime.toLocaleTimeString(date, { + hour: "numeric", + minute: "2-digit", + second: "2-digit" + }).toLowerCase().replace("am", "").replace("pm", "").trim(); + } + + return datetime.getDisplayTime(date).toLowerCase().replace("am", "").replace("pm", "").trim(); } function setDisplayTime(elem, date) { var html; - date && (date = datetime.parseISO8601Date(date), html = getDisplayTimeWithoutAmPm(date)), elem.innerHTML = html || "" + + if (date) { + date = datetime.parseISO8601Date(date); + html = getDisplayTimeWithoutAmPm(date); + } + + elem.innerHTML = html || ""; } function shouldEnableProgressByTimeOfDay(item) { - return !("TvChannel" !== item.Type || !item.CurrentProgram) + return !("TvChannel" !== item.Type || !item.CurrentProgram); } function updateNowPlayingInfo(player, state) { var item = state.NowPlayingItem; - if (currentItem = item, !item) return setPoster(null), updateRecordingButton(null), Emby.Page.setTitle(""), nowPlayingVolumeSlider.disabled = !0, nowPlayingPositionSlider.disabled = !0, btnFastForward.disabled = !0, btnRewind.disabled = !0, view.querySelector(".btnSubtitles").classList.add("hide"), view.querySelector(".btnAudio").classList.add("hide"), view.querySelector(".osdTitle").innerHTML = "", void(view.querySelector(".osdMediaInfo").innerHTML = ""); - enableProgressByTimeOfDay = shouldEnableProgressByTimeOfDay(item), getDisplayItem(item).then(updateDisplayItem), nowPlayingVolumeSlider.disabled = !1, nowPlayingPositionSlider.disabled = !1, btnFastForward.disabled = !1, btnRewind.disabled = !1, playbackManager.subtitleTracks(player).length ? view.querySelector(".btnSubtitles").classList.remove("hide") : view.querySelector(".btnSubtitles").classList.add("hide"), playbackManager.audioTracks(player).length > 1 ? view.querySelector(".btnAudio").classList.remove("hide") : view.querySelector(".btnAudio").classList.add("hide") + + currentItem = item; + if (!item) { + setPoster(null); + updateRecordingButton(null); + Emby.Page.setTitle(""); + nowPlayingVolumeSlider.disabled = true; + nowPlayingPositionSlider.disabled = true; + btnFastForward.disabled = true; + btnRewind.disabled = true; + view.querySelector(".btnSubtitles").classList.add("hide"); + view.querySelector(".btnAudio").classList.add("hide"); + view.querySelector(".osdTitle").innerHTML = ""; + view.querySelector(".osdMediaInfo").innerHTML = ""; + return; + } + + enableProgressByTimeOfDay = shouldEnableProgressByTimeOfDay(item); + getDisplayItem(item).then(updateDisplayItem); + nowPlayingVolumeSlider.disabled = false; + nowPlayingPositionSlider.disabled = false; + btnFastForward.disabled = false; + btnRewind.disabled = false; + + if (playbackManager.subtitleTracks(player).length) { + view.querySelector(".btnSubtitles").classList.remove("hide"); + } else { + view.querySelector(".btnSubtitles").classList.add("hide"); + } + + if (playbackManager.audioTracks(player).length > 1) { + view.querySelector(".btnAudio").classList.remove("hide"); + } else { + view.querySelector(".btnAudio").classList.add("hide"); + } } function setTitle(item, parentName) { var url = logoImageUrl(item, connectionManager.getApiClient(item.ServerId), {}); + if (url) { Emby.Page.setTitle(""); var pageTitle = document.querySelector(".pageTitle"); - pageTitle.style.backgroundImage = "url('" + url + "')", pageTitle.classList.add("pageTitleWithLogo"), pageTitle.classList.remove("pageTitleWithDefaultLogo"), pageTitle.innerHTML = "" - } else Emby.Page.setTitle(parentName || ""); + pageTitle.style.backgroundImage = "url('" + url + "')"; + pageTitle.classList.add("pageTitleWithLogo"); + pageTitle.classList.remove("pageTitleWithDefaultLogo"); + pageTitle.innerHTML = ""; + } else { + Emby.Page.setTitle(parentName || ""); + } + var documentTitle = parentName || (item ? item.Name : null); - documentTitle && (document.title = documentTitle) + + if (documentTitle) { + document.title = documentTitle; + } } function setPoster(item, secondaryItem) { var osdPoster = view.querySelector(".osdPoster"); + if (item) { var imgUrl = seriesImageUrl(item, { type: "Primary" @@ -155,105 +338,160 @@ define(["playbackManager", "dom", "inputmanager", "datetime", "itemHelper", "med }) || imageUrl(item, { type: "Primary" }); + if (!imgUrl && secondaryItem && (imgUrl = seriesImageUrl(secondaryItem, { - type: "Primary" - }) || seriesImageUrl(secondaryItem, { - type: "Thumb" - }) || imageUrl(secondaryItem, { - type: "Primary" - })), imgUrl) return void(osdPoster.innerHTML = '') + type: "Primary" + }) || seriesImageUrl(secondaryItem, { + type: "Thumb" + }) || imageUrl(secondaryItem, { + type: "Primary" + })), imgUrl) { + return void (osdPoster.innerHTML = ''); + } } - osdPoster.innerHTML = "" + + osdPoster.innerHTML = ""; } function showOsd() { - slideDownToShow(headerElement), showMainOsdControls(), startOsdHideTimer() + slideDownToShow(headerElement); + showMainOsdControls(); + startOsdHideTimer(); } function hideOsd() { - slideUpToHide(headerElement), hideMainOsdControls() + slideUpToHide(headerElement); + hideMainOsdControls(); } function toggleOsd() { - "osd" === currentVisibleMenu ? hideOsd() : currentVisibleMenu || showOsd() + if ("osd" === currentVisibleMenu) { + hideOsd(); + } else if (!currentVisibleMenu) { + showOsd(); + } } function startOsdHideTimer() { - stopOsdHideTimer(), osdHideTimeout = setTimeout(hideOsd, 5e3) + stopOsdHideTimer(); + osdHideTimeout = setTimeout(hideOsd, 5e3); } function stopOsdHideTimer() { - osdHideTimeout && (clearTimeout(osdHideTimeout), osdHideTimeout = null) + if (osdHideTimeout) { + clearTimeout(osdHideTimeout); + osdHideTimeout = null; + } } function slideDownToShow(elem) { - elem.classList.remove("osdHeader-hidden") + elem.classList.remove("osdHeader-hidden"); } function slideUpToHide(elem) { - elem.classList.add("osdHeader-hidden") + elem.classList.add("osdHeader-hidden"); } function clearHideAnimationEventListeners(elem) { dom.removeEventListener(elem, transitionEndEventName, onHideAnimationComplete, { - once: !0 - }) + once: true + }); } function onHideAnimationComplete(e) { var elem = e.target; - elem.classList.add("hide"), dom.removeEventListener(elem, transitionEndEventName, onHideAnimationComplete, { - once: !0 - }) + elem.classList.add("hide"); + dom.removeEventListener(elem, transitionEndEventName, onHideAnimationComplete, { + once: true + }); } function showMainOsdControls() { if (!currentVisibleMenu) { var elem = osdBottomElement; - currentVisibleMenu = "osd", clearHideAnimationEventListeners(elem), elem.classList.remove("hide"), elem.offsetWidth, elem.classList.remove("videoOsdBottom-hidden"), layoutManager.mobile || setTimeout(function() { - focusManager.focus(elem.querySelector(".btnPause")) - }, 50) + currentVisibleMenu = "osd"; + clearHideAnimationEventListeners(elem); + elem.classList.remove("hide"); + elem.classList.remove("videoOsdBottom-hidden"); + + if (!layoutManager.mobile) { + setTimeout(function () { + focusManager.focus(elem.querySelector(".btnPause")); + }, 50); + } } } function hideMainOsdControls() { if ("osd" === currentVisibleMenu) { var elem = osdBottomElement; - clearHideAnimationEventListeners(elem), elem.offsetWidth, elem.classList.add("videoOsdBottom-hidden"), dom.addEventListener(elem, transitionEndEventName, onHideAnimationComplete, { - once: !0 - }), currentVisibleMenu = null + clearHideAnimationEventListeners(elem); + elem.classList.add("videoOsdBottom-hidden"); + dom.addEventListener(elem, transitionEndEventName, onHideAnimationComplete, { + once: true + }); + currentVisibleMenu = null; } } function onPointerMove(e) { if ("mouse" === (e.pointerType || (layoutManager.mobile ? "touch" : "mouse"))) { - var eventX = e.screenX || 0, - eventY = e.screenY || 0, - obj = lastPointerMoveData; - if (!obj) return void(lastPointerMoveData = { - x: eventX, - y: eventY - }); - if (Math.abs(eventX - obj.x) < 10 && Math.abs(eventY - obj.y) < 10) return; - obj.x = eventX, obj.y = eventY, showOsd() + var eventX = e.screenX || 0; + var eventY = e.screenY || 0; + var obj = lastPointerMoveData; + + if (!obj) { + lastPointerMoveData = { + x: eventX, + y: eventY + }; + return; + } + + if (Math.abs(eventX - obj.x) < 10 && Math.abs(eventY - obj.y) < 10) { + return; + } + + obj.x = eventX; + obj.y = eventY; + showOsd(); } } function onInputCommand(e) { var player = currentPlayer; + switch (e.detail.command) { case "left": - "osd" === currentVisibleMenu ? showOsd() : currentVisibleMenu || (e.preventDefault(), playbackManager.rewind(player)); - break; + if ("osd" === currentVisibleMenu) { + showOsd(); + } else { + if (!currentVisibleMenu) { + e.preventDefault(); + playbackManager.rewind(player); + } + } + + break; + case "right": - "osd" === currentVisibleMenu ? showOsd() : currentVisibleMenu || (e.preventDefault(), playbackManager.fastForward(player)); - break; + if ("osd" === currentVisibleMenu) { + showOsd(); + } else if (!currentVisibleMenu) { + e.preventDefault(); + playbackManager.fastForward(player); + } + + break; + case "pageup": - playbackManager.nextChapter(player); - break; + playbackManager.nextChapter(player); + break; + case "pagedown": - playbackManager.previousChapter(player); - break; + playbackManager.previousChapter(player); + break; + case "up": case "down": case "select": @@ -266,89 +504,144 @@ define(["playbackManager", "dom", "inputmanager", "datetime", "itemHelper", "med case "rewind": case "next": case "previous": - showOsd(); - break; + showOsd(); + break; + case "record": - onRecordingCommand(), showOsd(); - break; + onRecordingCommand(); + showOsd(); + break; + case "togglestats": - toggleStats() + toggleStats(); } } function onRecordingCommand() { var btnRecord = view.querySelector(".btnRecord"); - btnRecord.classList.contains("hide") || btnRecord.click() + + if (!btnRecord.classList.contains("hide")) { + btnRecord.click(); + } } function updateFullscreenIcon() { - playbackManager.isFullscreen(currentPlayer) ? (view.querySelector(".btnFullscreen").setAttribute("title", globalize.translate("ExitFullscreen")), view.querySelector(".btnFullscreen i").innerHTML = "") : (view.querySelector(".btnFullscreen").setAttribute("title", globalize.translate("Fullscreen")), view.querySelector(".btnFullscreen i").innerHTML = "") + if (playbackManager.isFullscreen(currentPlayer)) { + view.querySelector(".btnFullscreen").setAttribute("title", globalize.translate("ExitFullscreen")); + view.querySelector(".btnFullscreen i").innerHTML = ""; + } else { + view.querySelector(".btnFullscreen").setAttribute("title", globalize.translate("Fullscreen")); + view.querySelector(".btnFullscreen i").innerHTML = ""; + } } function onPlayerChange() { - bindToPlayer(playbackManager.getCurrentPlayer()) + bindToPlayer(playbackManager.getCurrentPlayer()); } function onStateChanged(event, state) { var player = this; - state.NowPlayingItem && (isEnabled = !0, updatePlayerStateInternal(event, player, state), updatePlaylist(player), enableStopOnBack(!0)) + + if (state.NowPlayingItem) { + isEnabled = true; + updatePlayerStateInternal(event, player, state); + updatePlaylist(player); + enableStopOnBack(true); + } } function onPlayPauseStateChanged(e) { if (isEnabled) { - updatePlayPauseState(this.paused()) + updatePlayPauseState(this.paused()); } } function onVolumeChanged(e) { if (isEnabled) { var player = this; - updatePlayerVolumeState(player, player.isMuted(), player.getVolume()) + updatePlayerVolumeState(player, player.isMuted(), player.getVolume()); } } function onPlaybackStart(e, state) { console.log("nowplaying event: " + e.type); var player = this; - onStateChanged.call(player, e, state), resetUpNextDialog() + onStateChanged.call(player, e, state); + resetUpNextDialog(); } function resetUpNextDialog() { - comingUpNextDisplayed = !1; + comingUpNextDisplayed = false; var dlg = currentUpNextDialog; - dlg && (dlg.destroy(), currentUpNextDialog = null) + + if (dlg) { + dlg.destroy(); + currentUpNextDialog = null; + } } function onPlaybackStopped(e, state) { - currentRuntimeTicks = null, resetUpNextDialog(), console.log("nowplaying event: " + e.type), "Video" !== state.NextMediaType && (view.removeEventListener("viewbeforehide", onViewHideStopPlayback), Emby.Page.back()) + currentRuntimeTicks = null; + resetUpNextDialog(); + console.log("nowplaying event: " + e.type); + + if ("Video" !== state.NextMediaType) { + view.removeEventListener("viewbeforehide", onViewHideStopPlayback); + Emby.Page.back(); + } } function onMediaStreamsChanged(e) { - var player = this, - state = playbackManager.getPlayerState(player); + var player = this; + var state = playbackManager.getPlayerState(player); onStateChanged.call(player, { type: "init" - }, state) + }, state); } function bindToPlayer(player) { - if (player !== currentPlayer && (releaseCurrentPlayer(), currentPlayer = player, player)) { - var state = playbackManager.getPlayerState(player); - onStateChanged.call(player, { - type: "init" - }, state), events.on(player, "playbackstart", onPlaybackStart), events.on(player, "playbackstop", onPlaybackStopped), events.on(player, "volumechange", onVolumeChanged), events.on(player, "pause", onPlayPauseStateChanged), events.on(player, "unpause", onPlayPauseStateChanged), events.on(player, "timeupdate", onTimeUpdate), events.on(player, "fullscreenchange", updateFullscreenIcon), events.on(player, "mediastreamschange", onMediaStreamsChanged), resetUpNextDialog() + if (player !== currentPlayer) { + releaseCurrentPlayer(); + currentPlayer = player; + if (!player) return; } + var state = playbackManager.getPlayerState(player); + onStateChanged.call(player, { + type: "init" + }, state); + events.on(player, "playbackstart", onPlaybackStart); + events.on(player, "playbackstop", onPlaybackStopped); + events.on(player, "volumechange", onVolumeChanged); + events.on(player, "pause", onPlayPauseStateChanged); + events.on(player, "unpause", onPlayPauseStateChanged); + events.on(player, "timeupdate", onTimeUpdate); + events.on(player, "fullscreenchange", updateFullscreenIcon); + events.on(player, "mediastreamschange", onMediaStreamsChanged); + resetUpNextDialog(); } function releaseCurrentPlayer() { - destroyStats(), resetUpNextDialog(); + destroyStats(); + resetUpNextDialog(); var player = currentPlayer; - player && (events.off(player, "playbackstart", onPlaybackStart), events.off(player, "playbackstop", onPlaybackStopped), events.off(player, "volumechange", onVolumeChanged), events.off(player, "pause", onPlayPauseStateChanged), events.off(player, "unpause", onPlayPauseStateChanged), events.off(player, "timeupdate", onTimeUpdate), events.off(player, "fullscreenchange", updateFullscreenIcon), events.off(player, "mediastreamschange", onMediaStreamsChanged), currentPlayer = null) + + if (player) { + events.off(player, "playbackstart", onPlaybackStart); + events.off(player, "playbackstop", onPlaybackStopped); + events.off(player, "volumechange", onVolumeChanged); + events.off(player, "pause", onPlayPauseStateChanged); + events.off(player, "unpause", onPlayPauseStateChanged); + events.off(player, "timeupdate", onTimeUpdate); + events.off(player, "fullscreenchange", updateFullscreenIcon); + events.off(player, "mediastreamschange", onMediaStreamsChanged); + currentPlayer = null; + } } function onTimeUpdate(e) { if (isEnabled) { - var now = (new Date).getTime(); + var now = new Date().getTime(); + if (!(now - lastUpdateTime < 700)) { lastUpdateTime = now; var player = this; @@ -356,248 +649,457 @@ define(["playbackManager", "dom", "inputmanager", "datetime", "itemHelper", "med var currentTime = playbackManager.currentTime(player); updateTimeDisplay(currentTime, currentRuntimeTicks, playbackManager.playbackStartTime(player), playbackManager.getBufferedRanges(player)); var item = currentItem; - refreshProgramInfoIfNeeded(player, item), showComingUpNextIfNeeded(player, item, currentTime, currentRuntimeTicks) + refreshProgramInfoIfNeeded(player, item); + showComingUpNextIfNeeded(player, item, currentTime, currentRuntimeTicks); } } } 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, - showAtTicks = runtimeTicks - 1e3 * showAtSecondsLeft * 1e4, - timeRemainingTicks = runtimeTicks - currentTimeTicks; - currentTimeTicks >= showAtTicks && runtimeTicks >= 6e9 && timeRemainingTicks >= 2e8 && showComingUpNext(player) + var showAtSecondsLeft = runtimeTicks >= 3e10 ? 40 : runtimeTicks >= 24e9 ? 35 : 30; + var showAtTicks = runtimeTicks - 1e3 * showAtSecondsLeft * 1e4; + var timeRemainingTicks = runtimeTicks - currentTimeTicks; + + if (currentTimeTicks >= showAtTicks && runtimeTicks >= 6e9 && timeRemainingTicks >= 2e8) { + showComingUpNext(player); + } } } function onUpNextHidden() { - "upnext" === currentVisibleMenu && (currentVisibleMenu = null) + if ("upnext" === currentVisibleMenu) { + currentVisibleMenu = null; + } } function showComingUpNext(player) { - require(["upNextDialog"], function(UpNextDialog) { - currentVisibleMenu || currentUpNextDialog || (currentVisibleMenu = "upnext", comingUpNextDisplayed = !0, playbackManager.nextItem(player).then(function(nextItem) { - currentUpNextDialog = new UpNextDialog({ - parent: view.querySelector(".upNextContainer"), - player: player, - nextItem: nextItem - }), events.on(currentUpNextDialog, "hide", onUpNextHidden) - }, onUpNextHidden)) - }) + require(["upNextDialog"], function (UpNextDialog) { + if (!(currentVisibleMenu || currentUpNextDialog)) { + currentVisibleMenu = "upnext"; + comingUpNextDisplayed = true; + playbackManager.nextItem(player).then(function (nextItem) { + currentUpNextDialog = new UpNextDialog({ + parent: view.querySelector(".upNextContainer"), + player: player, + nextItem: nextItem + }); + events.on(currentUpNextDialog, "hide", onUpNextHidden); + }, onUpNextHidden); + } + }); } function refreshProgramInfoIfNeeded(player, item) { if ("TvChannel" === item.Type) { var program = item.CurrentProgram; - if (program && program.EndDate) try { - var endDate = datetime.parseISO8601Date(program.EndDate); - if ((new Date).getTime() >= endDate.getTime()) { - console.log("program info needs to be refreshed"); - var state = playbackManager.getPlayerState(player); - onStateChanged.call(player, { - type: "init" - }, state) + + if (program && program.EndDate) { + try { + var endDate = datetime.parseISO8601Date(program.EndDate); + + if (new Date().getTime() >= endDate.getTime()) { + console.log("program info needs to be refreshed"); + var state = playbackManager.getPlayerState(player); + onStateChanged.call(player, { + type: "init" + }, state); + } + } catch (e) { + console.log("Error parsing date: " + program.EndDate); } - } catch (e) { - console.log("Error parsing date: " + program.EndDate) } } } function updatePlayPauseState(isPaused) { - view.querySelector(".btnPause i").innerHTML = isPaused ? "" : "" + view.querySelector(".btnPause i").innerHTML = isPaused ? "" : ""; } function updatePlayerStateInternal(event, player, state) { var playState = state.PlayState || {}; updatePlayPauseState(playState.IsPaused); var supportedCommands = playbackManager.getSupportedCommands(player); - currentPlayerSupportedCommands = supportedCommands, supportsBrightnessChange = -1 !== supportedCommands.indexOf("SetBrightness"), updatePlayerVolumeState(player, playState.IsMuted, playState.VolumeLevel), nowPlayingPositionSlider && !nowPlayingPositionSlider.dragging && (nowPlayingPositionSlider.disabled = !playState.CanSeek), btnFastForward.disabled = !playState.CanSeek, btnRewind.disabled = !playState.CanSeek; + currentPlayerSupportedCommands = supportedCommands; + supportsBrightnessChange = -1 !== supportedCommands.indexOf("SetBrightness"); + updatePlayerVolumeState(player, playState.IsMuted, playState.VolumeLevel); + + if (nowPlayingPositionSlider && !nowPlayingPositionSlider.dragging) { + nowPlayingPositionSlider.disabled = !playState.CanSeek; + } + + btnFastForward.disabled = !playState.CanSeek; + btnRewind.disabled = !playState.CanSeek; var nowPlayingItem = state.NowPlayingItem || {}; - playbackStartTimeTicks = playState.PlaybackStartTimeTicks, updateTimeDisplay(playState.PositionTicks, nowPlayingItem.RunTimeTicks, playState.PlaybackStartTimeTicks, playState.BufferedRanges || []), updateNowPlayingInfo(player, state), state.MediaSource && state.MediaSource.SupportsTranscoding && -1 !== supportedCommands.indexOf("SetMaxStreamingBitrate") ? view.querySelector(".btnVideoOsdSettings").classList.remove("hide") : view.querySelector(".btnVideoOsdSettings").classList.add("hide"); + playbackStartTimeTicks = playState.PlaybackStartTimeTicks; + updateTimeDisplay(playState.PositionTicks, nowPlayingItem.RunTimeTicks, playState.PlaybackStartTimeTicks, playState.BufferedRanges || []); + updateNowPlayingInfo(player, state); + + if (state.MediaSource && state.MediaSource.SupportsTranscoding && -1 !== supportedCommands.indexOf("SetMaxStreamingBitrate")) { + view.querySelector(".btnVideoOsdSettings").classList.remove("hide"); + } else { + view.querySelector(".btnVideoOsdSettings").classList.add("hide"); + } + var isProgressClear = state.MediaSource && null == state.MediaSource.RunTimeTicks; - nowPlayingPositionSlider.setIsClear(isProgressClear), -1 === supportedCommands.indexOf("ToggleFullscreen") || player.isLocalPlayer && layoutManager.tv && playbackManager.isFullscreen(player) ? view.querySelector(".btnFullscreen").classList.add("hide") : view.querySelector(".btnFullscreen").classList.remove("hide"), -1 === supportedCommands.indexOf("PictureInPicture") ? view.querySelector(".btnPip").classList.add("hide") : view.querySelector(".btnPip").classList.remove("hide"), updateFullscreenIcon() + nowPlayingPositionSlider.setIsClear(isProgressClear); + + if (-1 === supportedCommands.indexOf("ToggleFullscreen") || player.isLocalPlayer && layoutManager.tv && playbackManager.isFullscreen(player)) { + view.querySelector(".btnFullscreen").classList.add("hide"); + } else { + view.querySelector(".btnFullscreen").classList.remove("hide"); + } + + if (-1 === supportedCommands.indexOf("PictureInPicture")) { + view.querySelector(".btnPip").classList.add("hide"); + } else { + view.querySelector(".btnPip").classList.remove("hide"); + } + + updateFullscreenIcon(); } function getDisplayPercentByTimeOfDay(programStartDateMs, programRuntimeMs, currentTimeMs) { - return (currentTimeMs - programStartDateMs) / programRuntimeMs * 100 + return (currentTimeMs - programStartDateMs) / programRuntimeMs * 100; } function updateTimeDisplay(positionTicks, runtimeTicks, playbackStartTimeTicks, bufferedRanges) { if (enableProgressByTimeOfDay) { - if (nowPlayingPositionSlider && !nowPlayingPositionSlider.dragging) + if (nowPlayingPositionSlider && !nowPlayingPositionSlider.dragging) { if (programStartDateMs && programEndDateMs) { - var currentTimeMs = (playbackStartTimeTicks + (positionTicks || 0)) / 1e4, - programRuntimeMs = programEndDateMs - programStartDateMs; + var currentTimeMs = (playbackStartTimeTicks + (positionTicks || 0)) / 1e4; + var programRuntimeMs = programEndDateMs - programStartDateMs; + if (nowPlayingPositionSlider.value = getDisplayPercentByTimeOfDay(programStartDateMs, programRuntimeMs, currentTimeMs), bufferedRanges.length) { - var rangeStart = getDisplayPercentByTimeOfDay(programStartDateMs, programRuntimeMs, (playbackStartTimeTicks + (bufferedRanges[0].start || 0)) / 1e4), - rangeEnd = getDisplayPercentByTimeOfDay(programStartDateMs, programRuntimeMs, (playbackStartTimeTicks + (bufferedRanges[0].end || 0)) / 1e4); + var rangeStart = getDisplayPercentByTimeOfDay(programStartDateMs, programRuntimeMs, (playbackStartTimeTicks + (bufferedRanges[0].start || 0)) / 1e4); + var rangeEnd = getDisplayPercentByTimeOfDay(programStartDateMs, programRuntimeMs, (playbackStartTimeTicks + (bufferedRanges[0].end || 0)) / 1e4); nowPlayingPositionSlider.setBufferedRanges([{ start: rangeStart, end: rangeEnd - }]) - } else nowPlayingPositionSlider.setBufferedRanges([]) - } else nowPlayingPositionSlider.value = 0, nowPlayingPositionSlider.setBufferedRanges([]); - nowPlayingPositionText.innerHTML = "", nowPlayingDurationText.innerHTML = "" + }]); + } else { + nowPlayingPositionSlider.setBufferedRanges([]); + } + } else { + nowPlayingPositionSlider.value = 0; + nowPlayingPositionSlider.setBufferedRanges([]); + } + } + + nowPlayingPositionText.innerHTML = ""; + nowPlayingDurationText.innerHTML = ""; } else { if (nowPlayingPositionSlider && !nowPlayingPositionSlider.dragging) { if (runtimeTicks) { var pct = positionTicks / runtimeTicks; - pct *= 100, nowPlayingPositionSlider.value = pct - } else nowPlayingPositionSlider.value = 0; - runtimeTicks && null != positionTicks && currentRuntimeTicks && !enableProgressByTimeOfDay && currentItem.RunTimeTicks && "Recording" !== currentItem.Type ? endsAtText.innerHTML = "  -  " + mediaInfo.getEndsAtFromPosition(runtimeTicks, positionTicks, !0) : endsAtText.innerHTML = "" + pct *= 100; + nowPlayingPositionSlider.value = pct; + } else { + nowPlayingPositionSlider.value = 0; + } + + if (runtimeTicks && null != positionTicks && currentRuntimeTicks && !enableProgressByTimeOfDay && currentItem.RunTimeTicks && "Recording" !== currentItem.Type) { + endsAtText.innerHTML = "  -  " + mediaInfo.getEndsAtFromPosition(runtimeTicks, positionTicks, true); + } else { + endsAtText.innerHTML = ""; + } + } + + if (nowPlayingPositionSlider) { + nowPlayingPositionSlider.setBufferedRanges(bufferedRanges, runtimeTicks, positionTicks); } - nowPlayingPositionSlider && nowPlayingPositionSlider.setBufferedRanges(bufferedRanges, runtimeTicks, positionTicks), updateTimeText(nowPlayingPositionText, positionTicks), updateTimeText(nowPlayingDurationText, runtimeTicks, !0) + + updateTimeText(nowPlayingPositionText, positionTicks); + updateTimeText(nowPlayingDurationText, runtimeTicks, true); } } function updatePlayerVolumeState(player, isMuted, volumeLevel) { - var supportedCommands = currentPlayerSupportedCommands, - showMuteButton = !0, - showVolumeSlider = !0; - 1 === supportedCommands.indexOf("Mute") && (showMuteButton = !1), -1 === supportedCommands.indexOf("SetVolume") && (showVolumeSlider = !1), player.isLocalPlayer && appHost.supports("physicalvolumecontrol") && (showMuteButton = !1, showVolumeSlider = !1), isMuted ? (view.querySelector(".buttonMute").setAttribute("title", globalize.translate("Unmute")), view.querySelector(".buttonMute i").innerHTML = "") : (view.querySelector(".buttonMute").setAttribute("title", globalize.translate("Mute")), view.querySelector(".buttonMute i").innerHTML = ""), showMuteButton ? view.querySelector(".buttonMute").classList.remove("hide") : view.querySelector(".buttonMute").classList.add("hide"), nowPlayingVolumeSlider && (showVolumeSlider ? nowPlayingVolumeSliderContainer.classList.remove("hide") : nowPlayingVolumeSliderContainer.classList.add("hide"), nowPlayingVolumeSlider.dragging || (nowPlayingVolumeSlider.value = volumeLevel || 0)) + var supportedCommands = currentPlayerSupportedCommands; + var showMuteButton = true; + var showVolumeSlider = true; + var volumeSlider = view.querySelector('.osdVolumeSliderContainer'); + var progressElement = volumeSlider.querySelector('.mdl-slider-background-lower'); + + + if (-1 === supportedCommands.indexOf("Mute")) { + showMuteButton = false; + } + + if (-1 === supportedCommands.indexOf("SetVolume")) { + showVolumeSlider = false; + } + + if (player.isLocalPlayer && appHost.supports("physicalvolumecontrol")) { + showMuteButton = false; + showVolumeSlider = false; + } + + if (isMuted) { + view.querySelector(".buttonMute").setAttribute("title", globalize.translate("Unmute")); + view.querySelector(".buttonMute i").innerHTML = ""; + } else { + view.querySelector(".buttonMute").setAttribute("title", globalize.translate("Mute")); + view.querySelector(".buttonMute i").innerHTML = ""; + } + + if (progressElement) { + progressElement.style.width = (volumeLevel || 0) + '%'; + } + + if (showMuteButton) { + view.querySelector(".buttonMute").classList.remove("hide"); + } else { + view.querySelector(".buttonMute").classList.add("hide"); + } + + if (nowPlayingVolumeSlider) { + if (showVolumeSlider) { + nowPlayingVolumeSliderContainer.classList.remove("hide"); + } else { + nowPlayingVolumeSliderContainer.classList.add("hide"); + } + + if (!nowPlayingVolumeSlider.dragging) { + nowPlayingVolumeSlider.value = volumeLevel || 0; + } + } } function updatePlaylist(player) { - var btnPreviousTrack = view.querySelector(".btnPreviousTrack"), - btnNextTrack = view.querySelector(".btnNextTrack"); - btnPreviousTrack.classList.remove("hide"), btnNextTrack.classList.remove("hide"), btnNextTrack.disabled = !1, btnPreviousTrack.disabled = !1 + var btnPreviousTrack = view.querySelector(".btnPreviousTrack"); + var btnNextTrack = view.querySelector(".btnNextTrack"); + btnPreviousTrack.classList.remove("hide"); + btnNextTrack.classList.remove("hide"); + btnNextTrack.disabled = false; + btnPreviousTrack.disabled = false; } function updateTimeText(elem, ticks, divider) { - if (null == ticks) return void(elem.innerHTML = ""); + if (null == ticks) { + elem.innerHTML = ""; + return; + } + var html = datetime.getDisplayRunningTime(ticks); - divider && (html = " / " + html), elem.innerHTML = html + + if (divider) { + html = " / " + html; + } + + elem.innerHTML = html; } function onSettingsButtonClick(e) { var btn = this; - require(["playerSettingsMenu"], function(playerSettingsMenu) { + + require(["playerSettingsMenu"], function (playerSettingsMenu) { var player = currentPlayer; - player && playerSettingsMenu.show({ - mediaType: "Video", - player: player, - positionTo: btn, - stats: !0, - onOption: onSettingsOption - }) - }) + + if (player) { + playerSettingsMenu.show({ + mediaType: "Video", + player: player, + positionTo: btn, + stats: true, + onOption: onSettingsOption + }); + } + }); } function onSettingsOption(selectedOption) { - "stats" === selectedOption && toggleStats() + if ("stats" === selectedOption) { + toggleStats(); + } } function toggleStats() { - require(["playerStats"], function(PlayerStats) { + require(["playerStats"], function (PlayerStats) { var player = currentPlayer; - player && (statsOverlay ? statsOverlay.toggle() : statsOverlay = new PlayerStats({ - player: player - })) - }) + + if (player) { + if (statsOverlay) { + statsOverlay.toggle(); + } else { + statsOverlay = new PlayerStats({ + player: player + }); + } + } + }); } function destroyStats() { - statsOverlay && (statsOverlay.destroy(), statsOverlay = null) + if (statsOverlay) { + statsOverlay.destroy(); + statsOverlay = null; + } } function showAudioTrackSelection() { - var player = currentPlayer, - audioTracks = playbackManager.audioTracks(player), - currentIndex = playbackManager.getAudioStreamIndex(player), - menuItems = audioTracks.map(function(stream) { - var opt = { - name: stream.DisplayTitle, - id: stream.Index - }; - return stream.Index === currentIndex && (opt.selected = !0), opt - }), - positionTo = this; - require(["actionsheet"], function(actionsheet) { + var player = currentPlayer; + var audioTracks = playbackManager.audioTracks(player); + var currentIndex = playbackManager.getAudioStreamIndex(player); + var menuItems = audioTracks.map(function (stream) { + var opt = { + name: stream.DisplayTitle, + id: stream.Index + }; + + if (stream.Index === currentIndex) { + opt.selected = true; + } + + return opt; + }); + var positionTo = this; + + require(["actionsheet"], function (actionsheet) { actionsheet.show({ items: menuItems, title: globalize.translate("Audio"), positionTo: positionTo - }).then(function(id) { + }).then(function (id) { var index = parseInt(id); - index !== currentIndex && playbackManager.setAudioStreamIndex(index, player) - }) - }) + + if (index !== currentIndex) { + playbackManager.setAudioStreamIndex(index, player); + } + }); + }); } function showSubtitleTrackSelection() { - var player = currentPlayer, - streams = playbackManager.subtitleTracks(player), - currentIndex = playbackManager.getSubtitleStreamIndex(player); - null == currentIndex && (currentIndex = -1), streams.unshift({ + var player = currentPlayer; + var streams = playbackManager.subtitleTracks(player); + var currentIndex = playbackManager.getSubtitleStreamIndex(player); + + if (null == currentIndex) { + currentIndex = -1; + } + + streams.unshift({ Index: -1, DisplayTitle: globalize.translate("Off") }); - var menuItems = streams.map(function(stream) { - var opt = { - name: stream.DisplayTitle, - id: stream.Index - }; - return stream.Index === currentIndex && (opt.selected = !0), opt - }), - positionTo = this; - require(["actionsheet"], function(actionsheet) { + var menuItems = streams.map(function (stream) { + var opt = { + name: stream.DisplayTitle, + id: stream.Index + }; + + if (stream.Index === currentIndex) { + opt.selected = true; + } + + return opt; + }); + var positionTo = this; + + require(["actionsheet"], function (actionsheet) { actionsheet.show({ title: globalize.translate("Subtitles"), items: menuItems, positionTo: positionTo - }).then(function(id) { + }).then(function (id) { var index = parseInt(id); - index !== currentIndex && playbackManager.setSubtitleStreamIndex(index, player) - }) - }) + + if (index !== currentIndex) { + playbackManager.setSubtitleStreamIndex(index, player); + } + }); + }); } function onWindowKeyDown(e) { - if (!currentVisibleMenu && (32 === e.keyCode || 13 === e.keyCode)) return playbackManager.playPause(currentPlayer), void showOsd(); + if (!currentVisibleMenu && (32 === e.keyCode || 13 === e.keyCode)) { + playbackManager.playPause(currentPlayer); + return void showOsd(); + } + switch (e.key) { case "f": - e.ctrlKey || playbackManager.toggleFullscreen(currentPlayer); - break; + if (!e.ctrlKey) { + playbackManager.toggleFullscreen(currentPlayer); + } + + break; + case "m": - playbackManager.toggleMute(currentPlayer); - break; + playbackManager.toggleMute(currentPlayer); + break; + case "ArrowLeft": case "Left": case "NavigationLeft": case "GamepadDPadLeft": case "GamepadLeftThumbstickLeft": - e.shiftKey && playbackManager.rewind(currentPlayer); - break; + if (e.shiftKey) { + playbackManager.rewind(currentPlayer); + } + + break; + case "ArrowRight": case "Right": case "NavigationRight": case "GamepadDPadRight": case "GamepadLeftThumbstickRight": - e.shiftKey && playbackManager.fastForward(currentPlayer) + if (e.shiftKey) { + playbackManager.fastForward(currentPlayer); + } + } } function getImgUrl(item, chapter, index, maxWidth, apiClient) { - return chapter.ImageTag ? apiClient.getScaledImageUrl(item.Id, { - maxWidth: maxWidth, - tag: chapter.ImageTag, - type: "Chapter", - index: index - }) : null + if (chapter.ImageTag) { + return apiClient.getScaledImageUrl(item.Id, { + maxWidth: maxWidth, + tag: chapter.ImageTag, + type: "Chapter", + index: index + }); + } + + return null; } function getChapterBubbleHtml(apiClient, item, chapters, positionTicks) { - for (var chapter, index = -1, i = 0, length = chapters.length; i < length; i++) { + var chapter; + var index = -1; + + for (var i = 0, length = chapters.length; i < length; i++) { var currentChapter = chapters[i]; - positionTicks >= currentChapter.StartPositionTicks && (chapter = currentChapter, index = i) + + if (positionTicks >= currentChapter.StartPositionTicks) { + chapter = currentChapter; + index = i; + } + } + + if (!chapter) { + return null; } - if (!chapter) return null; + var src = getImgUrl(item, chapter, index, 400, apiClient); + if (src) { var html = '
'; - return html += '', html += '
', html += '
', html += chapter.Name, html += "
", html += '

', html += datetime.getDisplayRunningTime(positionTicks), html += "

", html += "
", html += "
" + html += ''; + html += '
'; + html += '
'; + html += chapter.Name; + html += "
"; + html += '

'; + html += datetime.getDisplayRunningTime(positionTicks); + html += "

"; + html += "
"; + return html + ""; } - return null + + return null; } function onViewHideStopPlayback() { @@ -605,128 +1107,249 @@ define(["playbackManager", "dom", "inputmanager", "datetime", "itemHelper", "med require(['shell'], function (shell) { shell.disableFullscreen(); }); + var player = currentPlayer; - view.removeEventListener("viewbeforehide", onViewHideStopPlayback), releaseCurrentPlayer(), playbackManager.stop(player) + view.removeEventListener("viewbeforehide", onViewHideStopPlayback); + releaseCurrentPlayer(); + playbackManager.stop(player); } } function enableStopOnBack(enabled) { - view.removeEventListener("viewbeforehide", onViewHideStopPlayback), enabled && playbackManager.isPlayingVideo(currentPlayer) && view.addEventListener("viewbeforehide", onViewHideStopPlayback) + view.removeEventListener("viewbeforehide", onViewHideStopPlayback); + + if (enabled && playbackManager.isPlayingVideo(currentPlayer)) { + view.addEventListener("viewbeforehide", onViewHideStopPlayback); + } } require(['shell'], function (shell) { shell.enableFullscreen(); }); - var currentPlayer, comingUpNextDisplayed, currentUpNextDialog, isEnabled, currentItem, recordingButtonManager, enableProgressByTimeOfDay, supportsBrightnessChange, currentVisibleMenu, statsOverlay, osdHideTimeout, lastPointerMoveData, self = this, - currentPlayerSupportedCommands = [], - currentRuntimeTicks = 0, - lastUpdateTime = 0, - programStartDateMs = 0, - programEndDateMs = 0, - playbackStartTimeTicks = 0, - nowPlayingVolumeSlider = view.querySelector(".osdVolumeSlider"), - nowPlayingVolumeSliderContainer = view.querySelector(".osdVolumeSliderContainer"), - nowPlayingPositionSlider = view.querySelector(".osdPositionSlider"), - nowPlayingPositionText = view.querySelector(".osdPositionText"), - nowPlayingDurationText = view.querySelector(".osdDurationText"), - startTimeText = view.querySelector(".startTimeText"), - endTimeText = view.querySelector(".endTimeText"), - endsAtText = view.querySelector(".endsAtText"), - btnRewind = view.querySelector(".btnRewind"), - btnFastForward = view.querySelector(".btnFastForward"), - transitionEndEventName = dom.whichTransitionEvent(), - headerElement = document.querySelector(".skinHeader"), - osdBottomElement = document.querySelector(".videoOsdBottom-maincontrols"); - view.addEventListener("viewbeforeshow", function(e) { - headerElement.classList.add("osdHeader"), Emby.Page.setTransparency("full") - }), view.addEventListener("viewshow", function(e) { - events.on(playbackManager, "playerchange", onPlayerChange), bindToPlayer(playbackManager.getCurrentPlayer()), dom.addEventListener(document, window.PointerEvent ? "pointermove" : "mousemove", onPointerMove, { - passive: !0 - }), document.body.classList.add("autoScrollY"), showOsd(), inputManager.on(window, onInputCommand), dom.addEventListener(window, "keydown", onWindowKeyDown, { - passive: !0 - }) - }), view.addEventListener("viewbeforehide", function() { - statsOverlay && statsOverlay.enabled(!1), dom.removeEventListener(window, "keydown", onWindowKeyDown, { - passive: !0 - }), stopOsdHideTimer(), headerElement.classList.remove("osdHeader"), headerElement.classList.remove("osdHeader-hidden"), dom.removeEventListener(document, window.PointerEvent ? "pointermove" : "mousemove", onPointerMove, { - passive: !0 - }), document.body.classList.remove("autoScrollY"), inputManager.off(window, onInputCommand), events.off(playbackManager, "playerchange", onPlayerChange), releaseCurrentPlayer() - }), view.querySelector(".btnFullscreen").addEventListener("click", function() { - playbackManager.toggleFullscreen(currentPlayer) - }), view.querySelector(".btnPip").addEventListener("click", function() { - playbackManager.togglePictureInPicture(currentPlayer) - }), view.querySelector(".btnVideoOsdSettings").addEventListener("click", onSettingsButtonClick), view.addEventListener("viewhide", function() { - headerElement.classList.remove("hide") - }), view.addEventListener("viewdestroy", function() { - self.touchHelper && (self.touchHelper.destroy(), self.touchHelper = null), recordingButtonManager && (recordingButtonManager.destroy(), recordingButtonManager = null), destroyStats() + + 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 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"); + view.addEventListener("viewbeforeshow", function (e) { + headerElement.classList.add("osdHeader"); + Emby.Page.setTransparency("full"); + }); + view.addEventListener("viewshow", function (e) { + events.on(playbackManager, "playerchange", onPlayerChange); + bindToPlayer(playbackManager.getCurrentPlayer()); + dom.addEventListener(document, window.PointerEvent ? "pointermove" : "mousemove", onPointerMove, { + passive: true + }); + document.body.classList.add("autoScrollY"); + showOsd(); + inputManager.on(window, onInputCommand); + dom.addEventListener(window, "keydown", onWindowKeyDown, { + passive: true + }); + }); + view.addEventListener("viewbeforehide", function () { + if (statsOverlay) { + statsOverlay.enabled(false); + } + + dom.removeEventListener(window, "keydown", onWindowKeyDown, { + passive: true + }); + stopOsdHideTimer(); + headerElement.classList.remove("osdHeader"); + headerElement.classList.remove("osdHeader-hidden"); + dom.removeEventListener(document, window.PointerEvent ? "pointermove" : "mousemove", onPointerMove, { + passive: true + }); + document.body.classList.remove("autoScrollY"); + inputManager.off(window, onInputCommand); + events.off(playbackManager, "playerchange", onPlayerChange); + releaseCurrentPlayer(); + }); + view.querySelector(".btnFullscreen").addEventListener("click", function () { + playbackManager.toggleFullscreen(currentPlayer); + }); + view.querySelector(".btnPip").addEventListener("click", function () { + playbackManager.togglePictureInPicture(currentPlayer); + }); + view.querySelector(".btnVideoOsdSettings").addEventListener("click", onSettingsButtonClick); + view.addEventListener("viewhide", function () { + headerElement.classList.remove("hide"); + }); + view.addEventListener("viewdestroy", function () { + if (self.touchHelper) { + self.touchHelper.destroy(); + self.touchHelper = null; + } + + if (recordingButtonManager) { + recordingButtonManager.destroy(); + recordingButtonManager = null; + } + + destroyStats(); }); var lastPointerDown = 0; - 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"), - now = (new Date).getTime(); + 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(); + switch (pointerType) { case "touch": - now - lastPointerDown > 300 && (lastPointerDown = now, toggleOsd()); - break; + if (now - lastPointerDown > 300) { + lastPointerDown = now; + toggleOsd(); + } + + break; + case "mouse": - e.button || (playbackManager.playPause(currentPlayer), showOsd()); - break; + if (!e.button) { + playbackManager.playPause(currentPlayer); + showOsd(); + } + + break; + default: - playbackManager.playPause(currentPlayer), showOsd() + playbackManager.playPause(currentPlayer); + showOsd(); } }, { - passive: !0 - }), browser.touch && dom.addEventListener(view, "dblclick", onDoubleClick, {}), view.querySelector(".buttonMute").addEventListener("click", function() { - playbackManager.toggleMute(currentPlayer) - }), nowPlayingVolumeSlider.addEventListener("change", function() { - playbackManager.setVolume(this.value, currentPlayer) - }), nowPlayingPositionSlider.addEventListener("change", function() { + passive: true + }); + + if (browser.touch) { + dom.addEventListener(view, "dblclick", onDoubleClick, {}); + } + + view.querySelector(".buttonMute").addEventListener("click", function () { + playbackManager.toggleMute(currentPlayer); + }); + nowPlayingVolumeSlider.addEventListener("change", function () { + playbackManager.setVolume(this.value, currentPlayer); + }); + nowPlayingVolumeSlider.addEventListener("mousemove", function () { + playbackManager.setVolume(this.value, currentPlayer); + }); + nowPlayingVolumeSlider.addEventListener("touchmove", function () { + playbackManager.setVolume(this.value, currentPlayer); + }); + nowPlayingPositionSlider.addEventListener("change", function () { var player = currentPlayer; + if (player) { var newPercent = parseFloat(this.value); + if (enableProgressByTimeOfDay) { var seekAirTimeTicks = newPercent / 100 * (programEndDateMs - programStartDateMs) * 1e4; - seekAirTimeTicks += 1e4 * programStartDateMs, seekAirTimeTicks -= playbackStartTimeTicks, playbackManager.seek(seekAirTimeTicks, player) - } else playbackManager.seekPercent(newPercent, player) + seekAirTimeTicks += 1e4 * programStartDateMs; + seekAirTimeTicks -= playbackStartTimeTicks; + playbackManager.seek(seekAirTimeTicks, player); + } else { + playbackManager.seekPercent(newPercent, player); + } } - }), nowPlayingPositionSlider.getBubbleHtml = function(value) { - if (showOsd(), enableProgressByTimeOfDay) { + }); + + nowPlayingPositionSlider.getBubbleHtml = function (value) { + showOsd(); + if (enableProgressByTimeOfDay) { if (programStartDateMs && programEndDateMs) { var ms = programEndDateMs - programStartDateMs; - ms /= 100, ms *= value, ms += programStartDateMs; - return '

' + getDisplayTimeWithoutAmPm(new Date(parseInt(ms)), !0) + "

" + ms /= 100; + ms *= value; + ms += programStartDateMs; + return '

' + getDisplayTimeWithoutAmPm(new Date(parseInt(ms)), true) + "

"; } - return "--:--" + + return "--:--"; } - if (!currentRuntimeTicks) return "--:--"; + + if (!currentRuntimeTicks) { + return "--:--"; + } + var ticks = currentRuntimeTicks; - ticks /= 100, ticks *= value; + ticks /= 100; + ticks *= value; var item = currentItem; + if (item && item.Chapters && item.Chapters.length && item.Chapters[0].ImageTag) { var html = getChapterBubbleHtml(connectionManager.getApiClient(item.ServerId), item, item.Chapters, ticks); - if (html) return html - } - return '

' + datetime.getDisplayRunningTime(ticks) + "

" - }, view.querySelector(".btnPreviousTrack").addEventListener("click", function() { - playbackManager.previousTrack(currentPlayer) - }), view.querySelector(".btnPause").addEventListener("click", function() { - playbackManager.playPause(currentPlayer) - }), view.querySelector(".btnNextTrack").addEventListener("click", function() { - playbackManager.nextTrack(currentPlayer) - }), btnRewind.addEventListener("click", function() { - playbackManager.rewind(currentPlayer) - }), btnFastForward.addEventListener("click", function() { - playbackManager.fastForward(currentPlayer) - }), view.querySelector(".btnAudio").addEventListener("click", showAudioTrackSelection), view.querySelector(".btnSubtitles").addEventListener("click", showSubtitleTrackSelection), browser.touch && function() { - require(["touchHelper"], function(TouchHelper) { - self.touchHelper = new TouchHelper(view, { - swipeYThreshold: 30, - triggerOnMove: !0, - preventDefaultOnMove: !0, - ignoreTagNames: ["BUTTON", "INPUT", "TEXTAREA"] - }), events.on(self.touchHelper, "swipeup", onVerticalSwipe), events.on(self.touchHelper, "swipedown", onVerticalSwipe) - }) - }() - } -}); \ No newline at end of file + + if (html) { + return html; + } + } + + return '

' + datetime.getDisplayRunningTime(ticks) + "

"; + }; + + view.querySelector(".btnPreviousTrack").addEventListener("click", function () { + playbackManager.previousTrack(currentPlayer); + }); + view.querySelector(".btnPause").addEventListener("click", function () { + playbackManager.playPause(currentPlayer); + }); + view.querySelector(".btnNextTrack").addEventListener("click", function () { + playbackManager.nextTrack(currentPlayer); + }); + btnRewind.addEventListener("click", function () { + playbackManager.rewind(currentPlayer); + }); + btnFastForward.addEventListener("click", function () { + playbackManager.fastForward(currentPlayer); + }); + view.querySelector(".btnAudio").addEventListener("click", showAudioTrackSelection); + view.querySelector(".btnSubtitles").addEventListener("click", showSubtitleTrackSelection); + + if (browser.touch) { + (function () { + require(["touchHelper"], function (TouchHelper) { + self.touchHelper = new TouchHelper(view, { + swipeYThreshold: 30, + triggerOnMove: true, + preventDefaultOnMove: true, + ignoreTagNames: ["BUTTON", "INPUT", "TEXTAREA"] + }); + events.on(self.touchHelper, "swipeup", onVerticalSwipe); + events.on(self.touchHelper, "swipedown", onVerticalSwipe); + }); + })(); + } + }; +});