This commit is contained in:
tikuf 2014-04-16 10:14:20 +10:00
commit 4afc9f601e
52 changed files with 2722 additions and 1319 deletions

View file

@ -1,7 +1,7 @@
<!DOCTYPE html>
<html>
<head>
<title>Auto-Organize</title>
<title>${TitleAutoOrganize}</title>
</head>
<body>
<div id="libraryFileOrganizerLogPage" data-role="page" class="page type-interior adminPage organizePage">
@ -10,8 +10,8 @@
<div class="content-primary">
<div data-role="controlgroup" data-type="horizontal" class="localnav" data-mini="true">
<a href="#" data-role="button" class="ui-btn-active">Activity Log</a>
<a href="autoorganizetv.html" data-role="button">TV Settings</a>
<a href="#" data-role="button" class="ui-btn-active">${TabActivityLog}</a>
<a href="autoorganizetv.html" data-role="button">${TabTV}</a>
</div>
<div style="margin: -25px 0 1em; text-align: right;">
@ -25,9 +25,9 @@
<thead>
<tr>
<th data-priority="1"></th>
<th data-priority="2">Date</th>
<th data-priority="1">Source</th>
<th data-priority="3">Destination</th>
<th data-priority="2">${HeaderDate}</th>
<th data-priority="1">${HeaderSource}</th>
<th data-priority="3">${HeaderDestination}</th>
</tr>
</thead>
<tbody class="resultBody">
@ -36,11 +36,11 @@
<br />
<div style="text-align: right;" class="legend">
<div style="display: inline-block; height: 10px; width: 10px; background: green;"></div>
<span>Completed</span>
<span>${LabelCompleted}</span>
<div style="display: inline-block; height: 10px; width: 10px; background: red; margin-left: 1em;"></div>
<span>Failed</span>
<span>${LabelFailed}</span>
<div style="display: inline-block; height: 10px; width: 10px; background: blue; margin-left: 1em;"></div>
<span>Skipped</span>
<span>${LabelSkipped}</span>
</div>
<div class="listBottomPaging">
</div>
@ -50,7 +50,7 @@
<div data-role="popup" data-transition="slidefade" class="popup episodeCorrectionPopup">
<div class="ui-bar-a" style="text-align: center; padding: 0 20px;">
<h3>Episode Organization</h3>
<h3>${HeaderEpisodeOrganization}</h3>
</div>
<div data-role="content">
@ -59,33 +59,29 @@
<p><span class="inputFile"></span></p>
<div style="margin: 1em 0 1em; min-width: 250px;">
<label for="selectSeries">Series:</label>
<label for="selectSeries">${LabelSeries}</label>
<select id="selectSeries" data-mini="true" required="required"></select>
</div>
<div style="margin: 1em 0;">
<label for="txtSeason">Season number:</label>
<label for="txtSeason">${LabelSeasonNumber}</label>
<input id="txtSeason" type="number" data-mini="true" pattern="[0-9]*" required="required" min="0" />
</div>
<div style="margin: 1em 0;">
<label for="txtEpisode">Episode number:</label>
<label for="txtEpisode">${LabelEpisodeNumber}</label>
<input id="txtEpisode" type="number" data-mini="true" pattern="[0-9]*" required="required" min="0" />
</div>
<div style="margin: 1em 0;">
<label for="txtEndingEpisode">Ending episode number:</label>
<label for="txtEndingEpisode">${LabelEndingEpisodeNumber}</label>
<input id="txtEndingEpisode" type="number" data-mini="true" pattern="[0-9]*" min="0" />
<div class="fieldDescription">Only required for multi-episode files</div>
<div class="fieldDescription">${LabelEndingEpisodeNumberHelp}</div>
</div>
<div style="margin: 1em 0;" id="fldRememberCorrection">
<label for="chkRememberEpisodeCorrection">Remember this correction future episodes of the same series.</label>
<input id="chkRememberEpisodeCorrection" type="checkbox" data-mini="true" />
</div>
<p>
<button type="submit" data-theme="b" data-icon="check" data-mini="true">
Ok
${ButtonOk}
</button>
<button type="button" data-icon="delete" onclick="$(this).parents('.popup').popup('close');" data-mini="true">
Cancel
${ButtonCancel}
</button>
</p>
<input id="hfResultId" type="hidden" />

View file

@ -1,7 +1,7 @@
<!DOCTYPE html>
<html>
<head>
<title>Auto-Organize</title>
<title>${TitleAutoOrganize}</title>
</head>
<body>
<div id="libraryFileOrganizerPage" data-role="page" class="page type-interior organizePage">
@ -9,70 +9,70 @@
<div data-role="content">
<div class="content-primary">
<div data-role="controlgroup" data-type="horizontal" class="localnav" data-mini="true">
<a href="autoorganizelog.html" data-role="button">Activity Log</a>
<a href="#" data-role="button" class="ui-btn-active">TV Settings</a>
<a href="autoorganizelog.html" data-role="button">${TabActivityLog}</a>
<a href="#" data-role="button" class="ui-btn-active">${TabTV}</a>
</div>
<form class="libraryFileOrganizerForm">
<p>Auto-organize monitors your download folders for new files and moves them to your media directories.</p>
<p>${AutoOrganizeHelp}</p>
<p>TV file organizing will only add episodes to existing series. It will not create new series folders.</p>
<p>${AutoOrganizeTvHelp}</p>
<ul data-role="listview" class="ulForm" style="margin-bottom: 0!important;">
<li>
<input type="checkbox" id="chkEnableTvSorting" name="chkEnableTvSorting" />
<label for="chkEnableTvSorting">Enable new episode organization</label>
<label for="chkEnableTvSorting">${OptionEnableEpisodeOrganization}</label>
</li>
<li>
<label for="txtWatchFolder">Watch folder: </label>
<label for="txtWatchFolder">${LabelWatchFolder}</label>
<div style="display: inline-block; width: 92%;">
<input type="text" id="txtWatchFolder" name="txtWatchFolder" />
</div>
<button id="btnSelectWatchFolder" type="button" data-icon="search" data-iconpos="notext" data-inline="true">${ButtonSelectDirectory}</button>
<div class="fieldDescription">
The server will poll this folder during the "Organize new media files" <a href="scheduledtasks.html">scheduled task</a>.
<div>${LabelWatchFolderHelp}</div>
</div>
</li>
<li>
<label for="txtMinFileSize">Minimum file size (MB): </label>
<label for="txtMinFileSize">${LabelMinFileSizeForOrganize}</label>
<input type="number" id="txtMinFileSize" name="txtMinFileSize" pattern="[0-9]*" required="required" min="0" data-mini="true" />
<div class="fieldDescription">Files under this size will be ignored.</div>
<div class="fieldDescription">${LabelMinFileSizeForOrganizeHelp}</div>
</li>
<li>
<label for="txtSeasonFolderPattern">Season folder pattern: </label>
<label for="txtSeasonFolderPattern">${LabelSeasonFolderPattern}</label>
<input type="text" id="txtSeasonFolderPattern" name="txtSeasonFolderPattern" required="required" data-mini="true" />
<div class="fieldDescription seasonFolderFieldDescription"></div>
</li>
<li>
<label for="txtSeasonZeroName">Season zero folder name: </label>
<label for="txtSeasonZeroName">${LabelSeasonZeroFolderName}</label>
<input type="text" id="txtSeasonZeroName" name="txtSeasonZeroName" required="required" data-mini="true" />
</li>
</ul>
<div data-role="collapsible">
<h3>Episode file pattern</h3>
<h3>${HeaderEpisodeFilePattern}</h3>
<div>
<br />
<div>
<label for="txtEpisodePattern">Episode pattern: </label>
<label for="txtEpisodePattern">${LabelEpisodePattern}</label>
<input type="text" id="txtEpisodePattern" name="txtEpisodePattern" required="required" data-mini="true" />
<div class="fieldDescription episodePatternDescription"></div>
</div>
<br />
<div>
<label for="txtMultiEpisodePattern">Multi-Episode pattern: </label>
<label for="txtMultiEpisodePattern">${LabelMultiEpisodePattern}</label>
<input type="text" id="txtMultiEpisodePattern" name="txtMultiEpisodePattern" required="required" data-mini="true" />
<div class="fieldDescription multiEpisodePatternDescription"></div>
</div>
<br />
<p>Supported Patterns</p>
<p>${HeaderSupportedPatterns}</p>
<table data-role="table" id="movie-table" data-mode="reflow" class="ui-responsive">
<thead>
<tr>
<th>Term</th>
<th>Pattern</th>
<th>Result</th>
<th>${HeaderTerm}</th>
<th>${HeaderPattern}</th>
<th>${HeaderResult}</th>
</tr>
</thead>
<tbody>
@ -144,36 +144,36 @@
<br />
<ul data-role="listview" class="ulForm">
<li>
<label for="copyOrMoveFile">Transfer Method</label>
<label for="copyOrMoveFile">${LabelTransferMethod}</label>
<select id="copyOrMoveFile" data-mini="true">
<option value="true">Copy</option>
<option value="false">Move</option>
<option value="true">${OptionCopy}</option>
<option value="false">${OptionMove}</option>
</select>
<div class="fieldDescription">Copy or move files from the watch folder</div>
<div class="fieldDescription">${LabelTransferMethodHelp}</div>
</li>
<li>
<input type="checkbox" id="chkOverwriteExistingEpisodes" name="chkOverwriteExistingEpisodes" />
<label for="chkOverwriteExistingEpisodes">Overwrite existing episodes</label>
<label for="chkOverwriteExistingEpisodes">${OptionOverwriteExistingEpisodes}</label>
</li>
<li>
<label for="txtDeleteLeftOverFiles">Delete left over files with the following extensions: </label>
<label for="txtDeleteLeftOverFiles">${LabelDeleteLeftOverFiles}</label>
<input type="text" id="txtDeleteLeftOverFiles" name="txtDeleteLeftOverFiles" data-mini="true" />
<div class="fieldDescription">Separate with ;. For example: .nfo;.txt</div>
<div class="fieldDescription">${LabelDeleteLeftOverFilesHelp}</div>
</li>
<li>
<input type="checkbox" id="chkDeleteEmptyFolders" name="chkDeleteEmptyFolders" data-mini="true" />
<label for="chkDeleteEmptyFolders">Delete empty folders after organizing</label>
<div class="fieldDescription">Enable this to keep the download directory clean.</div>
<label for="chkDeleteEmptyFolders">${LabelDeleteEmptyFolders}</label>
<div class="fieldDescription">${LabelDeleteEmptyFoldersHelp}</div>
</li>
</ul>
<ul data-role="listview" class="ulForm">
<li>
<button type="submit" data-theme="b" data-icon="check" data-mini="true">
Save
${ButtonSave}
</button>
<button type="button" onclick="Dashboard.navigate('dashboard.html');" data-icon="delete" data-mini="true">
Cancel
${ButtonCancel}
</button>
</li>

View file

@ -56,6 +56,11 @@
white-space: nowrap;
}
.detailTableButtonsCell button {
margin-top: 0;
margin-bottom: 0;
}
.detailTableButtonsCell button + button {
margin-left: .5em;
}

View file

@ -1,5 +1,7 @@
.ui-icon-play:after {
background-image: url("images/icons/play.png");
background-image: url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%20Tiny%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11-tiny.dtd%22%3E%3Csvg%20version%3D%221.1%22%20baseProfile%3D%22tiny%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20width%3D%2216px%22%20height%3D%2216px%22%20viewBox%3D%220%200%20500%20500%22%20xml%3Aspace%3D%22preserve%22%3E%20%3Cpath%20d%3D%22M386.161%20258.649l-370.536%20205.915q-6.417%203.627-11.021%200.837t-4.604-10.044v-410.714q0-7.254%204.604-10.044t11.021%200.837l370.536%20205.915q6.417%203.627%206.417%208.649t-6.417%208.649z%22%20fill%3D%22%23ffffff%22%20%2F%3E%3C%2Fsvg%3E");
background-repeat: no-repeat;
background-position: 6px 3px;
}
/* Fallback */
.ui-nosvg .ui-icon-play:after {
@ -7,7 +9,9 @@
}
.ui-icon-stop:after {
background-image: url("images/icons/stop.png");
background-image: url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%20Tiny%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11-tiny.dtd%22%3E%3Csvg%20version%3D%221.1%22%20baseProfile%3D%22tiny%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20width%3D%2216px%22%20height%3D%2216px%22%20viewBox%3D%220%200%20500%20500%22%20xml%3Aspace%3D%22preserve%22%3E%20%3Cpath%20d%3D%22M428.571%2053.571v392.857q0%207.254-5.301%2012.556t-12.556%205.301h-392.857q-7.254%200-12.556-5.301t-5.301-12.556v-392.857q0-7.254%205.301-12.556t12.556-5.301h392.857q7.254%200%2012.556%205.301t5.301%2012.556z%22%20fill%3D%22%23ffffff%22%20%2F%3E%3C%2Fsvg%3E");
background-repeat: no-repeat;
background-position: 4px 3px;
}
/* Fallback */
.ui-nosvg .ui-icon-stop:after {
@ -15,14 +19,19 @@
}
.ui-icon-pause:after {
background-image: url("images/icons/pause.png");
background-image: url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%20Tiny%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11-tiny.dtd%22%3E%3Csvg%20version%3D%221.1%22%20baseProfile%3D%22tiny%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20width%3D%2216px%22%20height%3D%2216px%22%20viewBox%3D%220%200%20500%20500%22%20xml%3Aspace%3D%22preserve%22%3E%20%3Cpath%20d%3D%22M428.571%2053.571v392.857q0%207.254-5.301%2012.556t-12.556%205.301h-142.857q-7.254%200-12.556-5.301t-5.301-12.556v-392.857q0-7.254%205.301-12.556t12.556-5.301h142.857q7.254%200%2012.556%205.301t5.301%2012.556zM178.571%2053.571v392.857q0%207.254-5.301%2012.556t-12.556%205.301h-142.857q-7.254%200-12.556-5.301t-5.301-12.556v-392.857q0-7.254%205.301-12.556t12.556-5.301h142.857q7.254%200%2012.556%205.301t5.301%2012.556z%22%20fill%3D%22%23ffffff%22%20%2F%3E%3C%2Fsvg%3E");
background-repeat: no-repeat;
background-position: 4px 3px;
}
/* Fallback */
.ui-nosvg .ui-icon-pause:after {
background-image: url("images/icons/pause.png");
}
.ui-icon-volume-off:after {
background-image: url("images/icons/mute.png");
background-image: url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%20Tiny%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11-tiny.dtd%22%3E%3Csvg%20version%3D%221.1%22%20baseProfile%3D%22tiny%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20width%3D%2216px%22%20height%3D%2216px%22%20viewBox%3D%220%200%20500%20500%22%20xml%3Aspace%3D%22preserve%22%3E%20%3Cpath%20d%3D%22M214.286%2098.214v303.571q0%207.254-5.301%2012.556t-12.556%205.301-12.556-5.301l-92.913-92.913h-73.103q-7.254%200-12.556-5.301t-5.301-12.556v-107.143q0-7.254%205.301-12.556t12.556-5.301h73.103l92.913-92.913q5.301-5.301%2012.556-5.301t12.556%205.301%205.301%2012.556z%22%20fill%3D%22%23ffffff%22%20%2F%3E%3C%2Fsvg%3E");
background-repeat: no-repeat;
background-position: 6px 3px;
}
/* Fallback */
.ui-nosvg .ui-icon-volume-off:after {
@ -30,47 +39,63 @@
}
.ui-icon-volume-up:after {
background-image: url("images/icons/volumeup.png");
background-image: url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%20Tiny%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11-tiny.dtd%22%3E%3Csvg%20version%3D%221.1%22%20baseProfile%3D%22tiny%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20width%3D%2216px%22%20height%3D%2216px%22%20viewBox%3D%220%200%20500%20500%22%20xml%3Aspace%3D%22preserve%22%3E%20%3Cpath%20d%3D%22M214.286%2098.214v303.571q0%207.254-5.301%2012.556t-12.556%205.301-12.556-5.301l-92.913-92.913h-73.103q-7.254%200-12.556-5.301t-5.301-12.556v-107.143q0-7.254%205.301-12.556t12.556-5.301h73.103l92.913-92.913q5.301-5.301%2012.556-5.301t12.556%205.301%205.301%2012.556zM321.429%20250q0%2021.206-11.858%2039.481t-31.39%2026.088q-2.79%201.395-6.976%201.395-7.254%200-12.556-5.162t-5.301-12.695q0-5.859%203.348-9.905t8.091-6.976%209.487-6.417%208.091-9.905%203.348-15.904-3.348-15.904-8.091-9.905-9.487-6.417-8.091-6.976-3.348-9.905q0-7.534%205.301-12.695t12.556-5.162q4.185%200%206.976%201.395%2019.531%207.534%2031.39%2025.949t11.858%2039.621zM392.857%20250q0%2042.69-23.716%2078.823t-62.779%2052.595q-3.627%201.395-6.976%201.395-7.534%200-12.835-5.301t-5.301-12.556q0-10.882%2010.882-16.462%2015.625-8.091%2021.206-12.277%2020.647-15.067%2032.227-37.807t11.579-48.41-11.579-48.41-32.227-37.807q-5.581-4.185-21.206-12.277-10.882-5.581-10.882-16.462%200-7.254%205.301-12.556t12.556-5.301q3.627%200%207.254%201.395%2039.063%2016.462%2062.779%2052.595t23.716%2078.823zM464.286%20250q0%2064.174-35.435%20117.885t-94.308%2079.102q-3.627%201.395-7.254%201.395-7.254%200-12.556-5.301t-5.301-12.556q0-10.044%2010.882-16.462%201.953-1.116%206.278-2.93t6.278-2.93q12.835-6.976%2022.879-14.23%2034.319-25.391%2053.571-63.337t19.252-80.636-19.252-80.636-53.571-63.337q-10.044-7.254-22.879-14.23-1.953-1.116-6.278-2.93t-6.278-2.93q-10.882-6.417-10.882-16.462%200-7.254%205.301-12.556t12.556-5.301q3.627%200%207.254%201.395%2058.873%2025.391%2094.308%2079.102t35.435%20117.885z%22%20fill%3D%22%23ffffff%22%20%2F%3E%3C%2Fsvg%3E");
background-repeat: no-repeat;
}
/* Fallback */
.ui-nosvg .ui-icon-volume-up:after {
background-image: url("images/icons/volumeup.png");
}
.ui-icon-volume-down:after {
background-image: url("images/icons/volumedown.png");
background-image: url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%20Tiny%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11-tiny.dtd%22%3E%3Csvg%20version%3D%221.1%22%20baseProfile%3D%22tiny%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20width%3D%2216px%22%20height%3D%2216px%22%20viewBox%3D%220%200%20500%20500%22%20xml%3Aspace%3D%22preserve%22%3E%20%3Cpath%20d%3D%22M214.286%2098.214v303.571q0%207.254-5.301%2012.556t-12.556%205.301-12.556-5.301l-92.913-92.913h-73.103q-7.254%200-12.556-5.301t-5.301-12.556v-107.143q0-7.254%205.301-12.556t12.556-5.301h73.103l92.913-92.913q5.301-5.301%2012.556-5.301t12.556%205.301%205.301%2012.556zM321.429%20250q0%2021.206-11.858%2039.481t-31.39%2026.088q-2.79%201.395-6.976%201.395-7.254%200-12.556-5.162t-5.301-12.695q0-5.859%203.348-9.905t8.091-6.976%209.487-6.417%208.091-9.905%203.348-15.904-3.348-15.904-8.091-9.905-9.487-6.417-8.091-6.976-3.348-9.905q0-7.534%205.301-12.695t12.556-5.162q4.185%200%206.976%201.395%2019.531%207.534%2031.39%2025.949t11.858%2039.621z%22%20fill%3D%22%23ffffff%22%20%2F%3E%3C%2Fsvg%3E");
background-repeat: no-repeat;
}
/* Fallback */
.ui-nosvg .ui-icon-volume-down:after {
background-image: url("images/icons/volumedown.png");
}
.ui-icon-previous-track:after {
background-image: url("images/icons/previoustrack.png");
background-image: url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%20Tiny%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11-tiny.dtd%22%3E%3Csvg%20version%3D%221.1%22%20baseProfile%3D%22tiny%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20width%3D%2216px%22%20height%3D%2216px%22%20viewBox%3D%220%200%20500%20500%22%20xml%3Aspace%3D%22preserve%22%3E%20%3Cpath%20d%3D%22M273.159%2039.341q5.301-5.301%208.929-3.627t3.627%208.929v410.714q0%207.254-3.627%208.929t-8.929-3.627l-198.103-198.103q-2.511-2.511-3.627-5.301v189.174q0%207.254-5.301%2012.556t-12.556%205.301h-35.714q-7.254%200-12.556-5.301t-5.301-12.556v-392.857q0-7.254%205.301-12.556t12.556-5.301h35.714q7.254%200%2012.556%205.301t5.301%2012.556v189.174q1.116-3.069%203.627-5.301z%22%20fill%3D%22%23ffffff%22%20%2F%3E%3C%2Fsvg%3E");
background-repeat: no-repeat;
background-position: 6px 3px;
}
/* Fallback */
.ui-nosvg .ui-icon-previous-track:after {
background-image: url("images/icons/previoustrack.png");
}
.ui-icon-next-track:after {
background-image: url("images/icons/nexttrack.png");
background-image: url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%20Tiny%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11-tiny.dtd%22%3E%3Csvg%20version%3D%221.1%22%20baseProfile%3D%22tiny%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20width%3D%2216px%22%20height%3D%2216px%22%20viewBox%3D%220%200%20500%20500%22%20xml%3Aspace%3D%22preserve%22%3E%20%3Cpath%20d%3D%22M12.556%20460.659q-5.301%205.301-8.929%203.627t-3.627-8.929v-410.714q0-7.254%203.627-8.929t8.929%203.627l198.103%20198.103q2.232%202.232%203.627%205.301v-189.174q0-7.254%205.301-12.556t12.556-5.301h35.714q7.254%200%2012.556%205.301t5.301%2012.556v392.857q0%207.254-5.301%2012.556t-12.556%205.301h-35.714q-7.254%200-12.556-5.301t-5.301-12.556v-189.174q-1.395%202.79-3.627%205.301z%22%20fill%3D%22%23ffffff%22%20%2F%3E%3C%2Fsvg%3E");
background-repeat: no-repeat;
background-position: 6px 3px;
}
/* Fallback */
.ui-nosvg .ui-icon-next-track:after {
background-image: url("images/icons/nexttrack.png");
}
.ui-icon-sort:after {
background-image: url("images/icons/sort.png");
background-image: url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%20Tiny%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11-tiny.dtd%22%3E%3Csvg%20version%3D%221.1%22%20baseProfile%3D%22tiny%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20width%3D%2216px%22%20height%3D%2216px%22%20viewBox%3D%220%200%20500%20500%22%20xml%3Aspace%3D%22preserve%22%3E%20%3Cpath%20d%3D%22M285.714%20303.571q0%207.254-5.301%2012.556l-125%20125q-5.301%205.301-12.556%205.301t-12.556-5.301l-125-125q-5.301-5.301-5.301-12.556t5.301-12.556%2012.556-5.301h250q7.254%200%2012.556%205.301t5.301%2012.556zM285.714%20196.429q0%207.254-5.301%2012.556t-12.556%205.301h-250q-7.254%200-12.556-5.301t-5.301-12.556%205.301-12.556l125-125q5.301-5.301%2012.556-5.301t12.556%205.301l125%20125q5.301%205.301%205.301%2012.556z%22%20fill%3D%22%23ffffff%22%20%2F%3E%3C%2Fsvg%3E");
background-repeat: no-repeat;
background-position: 6px 3px;
}
/* Fallback */
.ui-nosvg .ui-icon-sort:after {
background-image: url("images/icons/sort.png");
}
.ui-icon-filter:after {
background-image: url("images/icons/filter.png");
background-image: url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%20Tiny%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11-tiny.dtd%22%3E%3Csvg%20version%3D%221.1%22%20baseProfile%3D%22tiny%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20width%3D%2216px%22%20height%3D%2216px%22%20viewBox%3D%220%200%20500%20500%22%20xml%3Aspace%3D%22preserve%22%3E%20%3Cpath%20d%3D%22M391.462%2082.31q4.743%2011.44-3.906%2019.531l-137.556%20137.556v207.031q0%2011.719-10.882%2016.462-3.627%201.395-6.976%201.395-7.534%200-12.556-5.301l-71.429-71.429q-5.301-5.301-5.301-12.556v-135.603l-137.556-137.556q-8.649-8.091-3.906-19.531%204.743-10.882%2016.462-10.882h357.143q11.719%200%2016.462%2010.882z%22%20fill%3D%22%23ffffff%22%20%2F%3E%3C%2Fsvg%3E");
background-repeat: no-repeat;
background-position: 4px 3px;
}
/* Fallback */
.ui-nosvg .ui-icon-filter:after {
background-image: url("images/icons/filter.png");
}
.ui-icon-audiocd:after {
background-image: url("images/icons/audiocd.png");
}
@ -78,17 +103,31 @@
.ui-nosvg .ui-icon-audiocd:after {
background-image: url("images/icons/audiocd.png");
}
.ui-icon-subtitles:after {
background-image: url("images/icons/subtitles.png");
background-image: url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%20Tiny%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11-tiny.dtd%22%3E%3Csvg%20version%3D%221.1%22%20baseProfile%3D%22tiny%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20width%3D%2216px%22%20height%3D%2216px%22%20viewBox%3D%220%200%20500%20500%22%20xml%3Aspace%3D%22preserve%22%3E%20%3Cpath%20d%3D%22M22.601%2035.993l15.067%207.534q5.581%201.395%2058.873%201.395h36.272l5.301-0.837%2032.087-0.279%20213.169%200.279%209.487%200.558q3.906%200.279%207.813-1.953t5.859-4.464l1.953-2.232%2011.719-0.279q4.185%200%207.813%200.279v29.157t0.279%2036.691l0.279%2027.902-0.279%2016.183q0%208.929-1.116%2014.23-10.882%204.185-18.973%205.022-6.976-11.998-15.067-35.714-2.232-6.696-4.325-17.438t-3.208-18.276-1.674-8.091q-3.627-4.185-7.534-5.301-1.953-0.558-16.323-0.558t-38.644%200.279-35.714%200.279q-26.228%200-35.435%201.395-2.79%2027.065-2.232%2037.946l0.279%2042.411v-14.509l0.837%20100.167-0.279%2041.016q-0.279%2012.835%203.069%2023.716%2013.672%206.976%2024.833%208.929%200.558%200%205.022%201.395t12.277%203.627%2011.998%203.348q8.371%202.232%2013.951%205.022%201.395%2012.556%201.395%2013.951%200%202.79-0.837%208.091-3.906%200.279-9.487%200.279-30.692%200-52.176-2.79-20.089-2.232-66.406-2.232-22.879%200-65.011%203.627-12.556%201.395-19.531%201.395-0.558-6.138-0.558-7.254l-0.279-7.254v-2.511q5.859-9.208%2022.042-13.672%2038.784-10.603%2044.364-13.951%202.511-5.859%203.348-15.625%201.674-38.226%201.674-120.815l-1.395-12.277q0-73.94-0.558-77.567-0.558-3.069-1.674-4.185-1.674-1.395-3.906-1.674-10.603-1.674-41.294-1.674-13.951%200-47.015%203.906t-36.97%206.696q-3.627%202.511-6.138%209.208t-6.138%2020.926-6.696%2023.438q-1.674%205.301-5.441%208.929t-5.72%203.627q-12.277-7.534-15.625-12.277v-106.864zM419.922%20397.042q7.254%205.581%207.254%2013.672t-7.254%2013.672l-45.201%2035.156q-7.254%205.581-12.417%203.069t-5.162-11.719v-22.321h-285.714v22.321q0%209.208-5.162%2011.719t-12.417-3.069l-45.201-35.156q-7.254-5.581-7.254-13.672t7.254-13.672l45.201-35.156q7.254-5.581%2012.417-3.069t5.162%2011.719v22.321h285.714v-22.321q0-9.208%205.162-11.719t12.417%203.069z%22%20fill%3D%22%23ffffff%22%20%2F%3E%3C%2Fsvg%3E");
background-repeat: no-repeat;
background-position: 4px 3px;
}
/* Fallback */
.ui-nosvg .ui-icon-subtitles:after {
background-image: url("images/icons/subtitles.png");
}
.ui-icon-wireless:after {
background-image: url("images/icons/wireless.png");
}
/* Fallback */
.ui-nosvg .ui-icon-wireless:after {
background-image: url("images/icons/wireless.png");
}
}
.ui-icon-expand:after {
background-image: url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%20Tiny%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11-tiny.dtd%22%3E%3Csvg%20version%3D%221.1%22%20baseProfile%3D%22tiny%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20width%3D%2216px%22%20height%3D%2216px%22%20viewBox%3D%220%200%20500%20500%22%20xml%3Aspace%3D%22preserve%22%3E%20%3Cpath%20d%3D%22M210.659%20294.643q0%203.627-2.79%206.417l-92.634%2092.634%2040.179%2040.179q5.301%205.301%205.301%2012.556t-5.301%2012.556-12.556%205.301h-125q-7.254%200-12.556-5.301t-5.301-12.556v-125q0-7.254%205.301-12.556t12.556-5.301%2012.556%205.301l40.179%2040.179%2092.634-92.634q2.79-2.79%206.417-2.79t6.417%202.79l31.808%2031.808q2.79%202.79%202.79%206.417zM428.571%2053.571v125q0%207.254-5.301%2012.556t-12.556%205.301-12.556-5.301l-40.179-40.179-92.634%2092.634q-2.79%202.79-6.417%202.79t-6.417-2.79l-31.808-31.808q-2.79-2.79-2.79-6.417t2.79-6.417l92.634-92.634-40.179-40.179q-5.301-5.301-5.301-12.556t5.301-12.556%2012.556-5.301h125q7.254%200%2012.556%205.301t5.301%2012.556z%22%20fill%3D%22%23ffffff%22%20%2F%3E%3C%2Fsvg%3E");
background-repeat: no-repeat;
background-position: 4px 3px;
}
.ui-nosvg .ui-icon-expand:after {
background-image: url("images/icons/expand.png");
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 313 B

View file

@ -590,7 +590,7 @@ a.itemTag:hover {
}
.lblDetailTab {
font-size: 16px!important;
font-size: 15px!important;
font-weight: 400!important;
font-family: 'Open Sans';
padding: .5em 1em;
@ -710,14 +710,12 @@ a.itemTag:hover {
}
.itemBackdrop {
background-image: none!important;
height: auto;
}
.itemBackdropContent {
position: static;
padding: 1em 1em 0;
background-color: transparent;
padding: 1em 1em .5em;
}
.itemDetailImage {

View file

@ -26,15 +26,15 @@
.itemVideo {
background-color: #000;
margin: 20px 20px 80px;
margin: 5px 5px 75px;
width: 320px;
height: 181px;
}
#videoControls {
z-index: 99999;
padding: 0 20px 5px;
height: 80px;
padding: 0 5px 5px;
height: 75px;
position: absolute;
top: auto;
right: 0;
@ -54,7 +54,7 @@
#videoControls #video-basic-controls {
position: absolute;
top: 30px;
top: 25px;
left: 20px;
bottom: 0;
width: 600px;
@ -63,7 +63,7 @@
#videoControls #video-advanced-controls {
position: absolute;
top: 30px;
top: 25px;
right: 20px;
bottom: 0;
width: 400px;
@ -104,14 +104,14 @@
max-height: 100%;
}
#mediaPlayer .ui-slider-track {
#mediaPlayer .ui-slider-track, .nowPlayingBar .ui-slider-track {
border-color: #2ad !important;
height: 10px!important;
height: 2px!important;
}
#mediaPlayer .ui-slider-handle {
height: 12px !important;
margin-top: -7px !important;
#mediaPlayer .ui-slider-handle, .nowPlayingBar .ui-slider-handle {
height: 10px !important;
margin-top: -6px !important;
}
#videoPlayer.fullscreenVideo #videoControls {
@ -139,7 +139,12 @@
text-align: left;
margin-left: 0;
right: 0;
bottom: 83px;
bottom: 85px;
}
#mediaPlayer .volumeSliderContainer {
position: relative;
top: 5px;
}
/* Media queries
@ -191,10 +196,6 @@
margin-left: -550px;
margin-top: -329px;
}
#video-videoPlayerMenuButton {
display: none;
}
}
@media all and (min-width: 1440px) and (min-height: 720px) {
@ -212,10 +213,6 @@
/****************************************/
@media all and (max-width: 1200px), all and (max-height: 720px) {
#videoControls .nowPlayingMediaInfo {
display: none;
}
#videoControls .currentTime {
margin-right: 0;
min-width: 120px;
@ -249,17 +246,13 @@
width: 250px;
}
#mediaPlayer #video-basic-controls .volumeSliderContainer {
margin-top: 8px;
}
#mediaPlayer #video-basic-controls, #mediaPlayer #video-advanced-controls {
width: 200px;
height: 120px;
}
#mediaPlayer #videoControls .mediaPlayerFlyout {
bottom: 148px;
bottom: 150px;
}
}
@ -273,14 +266,18 @@
}
}
@media all and (max-width: 500px) {
#mediaPlayer .previousTrackButton, #mediaPlayer .nextTrackButton {
@media all and (max-width: 600px) {
#mediaPlayer .volumeSliderContainer, #mediaPlayer .muteButton, #mediaPlayer .unmuteButton {
display: none!important;
}
#mediaPlayer .nowPlayingImage, #mediaPlayer .nowPlayingText {
display: none!important;
}
}
@media all and (max-width: 400px) {
#mediaPlayer .playlistButton {
@media all and (max-width: 500px) {
#mediaPlayer .previousTrackButton, #mediaPlayer .nextTrackButton {
display: none!important;
}
}
@ -371,3 +368,86 @@
.cursor-inactive {
cursor: none;
}
.mediaFlyoutContainer {
display: inline-block;
}
.mediaPlayerFlyout {
width: 200px;
color: #000;
background-color: #fff;
border: 1px solid #999;
position: absolute;
z-index: 99999;
bottom: 78px;
margin-left: -125px;
max-height: 300px;
overflow-y: auto;
font-size: 13px;
}
.chaptersFlyout, .audioTracksFlyout {
width: 250px;
margin-left: -150px;
}
.mediaFlyoutOption {
display: block;
text-decoration: none;
color: #000;
border-bottom: 1px solid #eee;
cursor: pointer;
}
.mediaFlyoutOption:hover, .mediaFlyoutOption:focus {
background-color: #eee;
}
.selectedMediaFlyoutOption {
background-color: #d9F4FF;
background-image: url(images/media/selected.png);
background-repeat: no-repeat;
background-position: right top;
background-size: 16px 16px;
}
.mediaFlyoutOptionImage {
display: inline-block;
width: 15%;
vertical-align: middle;
}
.mediaFlyoutOptionImage + .mediaFlyoutOptionContent {
vertical-align: top;
display: inline-block;
width: 85%;
}
.chaptersFlyout .mediaFlyoutOptionImage {
width: 40%;
}
.chaptersFlyout .mediaFlyoutOptionImage + .mediaFlyoutOptionContent {
width: 60%;
}
.mediaFlyoutOptionName {
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
padding-left: 5px;
font-size: 13px;
font-weight: normal;
}
.mediaFlyoutOptionSecondaryText {
font-size: 13px;
color: #333;
font-weight: normal;
margin-top: 3px;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
padding-left: 5px;
}

View file

@ -1,21 +1,9 @@
/* Now playing bar */
.nowPlayingBar {
padding: 6px 0 20px 0;
padding: 6px 0 14px 0;
border-top: 2px solid green;
}
.nowPlayingBar .barBackground {
border-top: 2px solid green;
position: absolute;
margin: -8px -0.5em -22px !important;
width: 100%;
height: 100%;
}
.nowPlayingBar > *:not(#mediaElement):not(.mediaFlyoutContainer):not(.barBackground ) {
position: relative;
}
.nowPlayingBarImage {
vertical-align: bottom;
}
@ -29,27 +17,32 @@
position: relative;
}
.nowPlayingMediaInfo div {
display: inline-block;
}
.nowPlayingMediaInfo a {
margin-right: .25em;
}
.nowPlayingMediaInfo {
display: inline-block;
}
.nowPlayingText {
position: relative;
top: -3px;
margin-left: 3px;
margin-right: 2em;
display: inline-block;
font-weight: normal;
position: relative;
top: -7px;
margin-left: 3px;
max-width: 200px;
overflow: hidden;
margin-right: 2em;
white-space: nowrap;
}
.nowPlayingDoubleText {
top: -3px;
}
.nowPlayingImage {
display: inline-block;
}
.nowPlayingImage img {
height: 40px;
margin-right: .5em;
vertical-align: bottom;
}
.mediaButton img {
height: 24px;
}
@ -60,10 +53,13 @@
top: -10px;
max-width: 110px;
margin-right: 2em;
font-size: 14px;
font-weight: normal;
}
.nowPlayingBar .currentTime {
top: -15px;
}
.mediaSlider {
position: relative;
top: -10px;
@ -79,8 +75,8 @@
width: 130px;
}
#nowPlayingBar .positionSliderContainer {
margin-top: 8px;
#nowPlayingBar .sliderContainer {
margin-top: 14px;
}
.volumeSliderContainer {
@ -127,125 +123,27 @@ input[type="range"]::-ms-fill-upper {
}
@media all and (max-width: 800px) {
#nowPlayingBar .volumeButton, #nowPlayingBar .volumeSliderContainer, #nowPlayingBar .muteButton, #nowPlayingBar .unmuteButton, #nowPlayingBar .nowPlayingMediaInfo {
display: none; /*!important;*/
}
}
@media all and (max-width: 650px) {
#nowPlayingBar .nowPlayingMediaInfo {
display: none;
}
}
@media all and (max-width: 600px) {
#nowPlayingBar .chaptersButton, #nowPlayingBar .audioTracksButton {
display: none; /*!important;*/
#nowPlayingBar .mediaButton {
margin-top: 0;
margin-bottom: 0;
}
#nowPlayingBar .positionSliderContainer, #nowPlayingBar .currentTime {
top: 0!important;
position: relative!important;
}
}
#nowPlayingBar .mediaButton:not(#playButton):not(#pauseButton) {
display: none;
}
@media all and (max-width: 500px) {
#nowPlayingBar .positionSliderContainer {
width: 80px;
#nowPlayingBar #playButton, #nowPlayingBar #pauseButton {
float: right;
}
#nowPlayingBar .previousTrackButton, #nowPlayingBar .nextTrackButton {
display: none; /*!important;*/
}
}
@media all and (max-width: 400px) {
#nowPlayingBar .playlistButton {
display: none; /*!important;*/
}
}
.mediaFlyoutContainer {
display: inline-block;
}
.mediaPlayerFlyout {
width: 200px;
color: #000;
background-color: #fff;
border: 1px solid #999;
position: absolute;
z-index: 99999;
bottom: 78px;
margin-left: -125px;
max-height: 300px;
overflow-y: auto;
font-size: 13px;
}
.chaptersFlyout,.audioTracksFlyout {
width: 250px;
margin-left: -150px;
}
.mediaFlyoutOption {
display: block;
text-decoration: none;
color: #000;
border-bottom: 1px solid #eee;
cursor: pointer;
}
.mediaFlyoutOption:hover, .mediaFlyoutOption:focus {
background-color: #eee;
#nowPlayingBar .currentTime, #nowPlayingBar .positionSliderContainer, #nowPlayingBar .volumeSliderContainer, #nowPlayingBar .muteButton, #nowPlayingBar .unmuteButton {
display: none !important;
}
.selectedMediaFlyoutOption {
background-color: #d9F4FF;
background-image: url(images/media/selected.png);
background-repeat: no-repeat;
background-position: right top;
background-size: 16px 16px;
}
.mediaFlyoutOptionImage {
display: inline-block;
width: 15%;
vertical-align: middle;
}
.mediaFlyoutOptionImage + .mediaFlyoutOptionContent {
vertical-align: top;
display: inline-block;
width: 85%;
.nowPlayingBar {
padding: 10px 5px 10px 0;
}
.chaptersFlyout .mediaFlyoutOptionImage {
width: 40%;
}
.chaptersFlyout .mediaFlyoutOptionImage + .mediaFlyoutOptionContent {
width: 60%;
}
.mediaFlyoutOptionName {
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
padding-left: 5px;
font-size: 13px;
font-weight: normal;
}
.mediaFlyoutOptionSecondaryText {
font-size: 13px;
color: #333;
font-weight: normal;
margin-top: 3px;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
padding-left: 5px;
}
@media (min-width: 1440px) {
@ -253,3 +151,16 @@ input[type="range"]::-ms-fill-upper {
width: 300px;
}
}
.mediaPlayerAudioContainer {
position: fixed;
top: 40%;
text-align: center;
left: 0;
right: 0;
}
.mediaPlayerAudioContainerInner {
padding: 1em;
background: #222;
}

View file

@ -655,24 +655,6 @@ h1 .imageLink {
top: -3px;
}
/* Dashboard home */
.tblConnections td {
padding: 1em 0 1em .75em;
vertical-align: top;
}
.tblConnections td:first-child {
padding-left: 0;
}
.tblConnections img:not(.clientNowPlayingImage) {
height: 28px;
}
.clientNowPlayingImage {
height: 52px;
}
/* Footer */
#footer {
position: fixed;
@ -870,3 +852,142 @@ progress {
.btnShowStatusMessage:hover {
text-decoration: underline;
}
.activeSession {
display: inline-block;
position: relative;
margin: 5px;
width: 250px;
height: 140.625px;
}
.sessionNowPlayingContent {
background-size: cover;
background-repeat: no-repeat;
background-position: center center;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
border-radius: 3px;
}
.sessionNowPlayingInnerContent {
background-color: rgba(0, 0, 0, .6);
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
color: #fff;
font-weight: 400;
border-radius: 3px;
}
.sessionAppInfo {
padding: .5em;
overflow: hidden;
}
.sessionAppName {
vertical-align: top;
max-width: 200px;
}
.sessionUserInfo {
position: absolute;
right: 0;
bottom: 7px;
padding: .5em;
text-align: right;
}
.sessionUserInfo img {
height: 24px;
}
.sessionNowPlayingInfo {
position: absolute;
left: 0;
bottom: 7px;
padding: .5em;
max-width: 150px;
overflow: hidden;
text-overflow: ellipsis;
}
.sessionAppInfo img {
max-width: 32px;
max-height: 32px;
margin-right: 5px;
}
.activeSession progress {
position: absolute;
right: 0;
bottom: 0;
left: 0;
height: 7px;
width: 100%;
opacity: .95;
}
.notPlayingSession .sessionNowPlayingContent {
display: none;
}
.notPlayingSession .sessionNowPlayingInnerContent {
background-color: #f0f0f0;
color: #000;
}
.notPlayingSession .sessionUserInfo, .notPlayingSession .sessionNowPlayingInfo {
bottom: 0;
}
.activeSession:hover {
-moz-box-shadow: 0 0 20px 1px #38c;
-webkit-box-shadow: 0 0 20px 1px #38c;
box-shadow: 0 0 20px 1px #38c;
}
@media all and (max-width: 1000px) {
.activeSession {
width: 230px;
height: 129.375px;
}
}
@media all and (max-width: 550px) {
.activeSession {
width: 210px;
height: 118.125px;
}
.sessionAppName {
max-width: 160px;
}
}
@media all and (max-width: 500px) {
.activeSession {
width: 200px;
height: 112.5px;
}
.sessionAppName {
max-width: 150px;
}
}
@media all and (max-width: 400px) {
.activeSession {
width: 250px;
height: 140.625px;
}
}

View file

@ -19,67 +19,63 @@
<div class="readOnlyContent dashboardHomeLeftColumn">
<div data-role="collapsible" data-collapsed="false">
<h3>Server Information</h3>
<h3>${HeaerServerInformation}</h3>
<div>
<p>
Version <span id="appVersionNumber"></span>
<p id="appVersionNumber">
</p>
<p id="pUpToDate" style="display: none;">
<img src="css/images/checkmarkgreen.png" style="height: 20px; margin-right: 3px; position: relative; top: 5px; border-radius: 3px;" />
Media Browser Server is up to date
${ServerUpToDate}
</p>
<div id="pUpdateNow" style="display: none;">
<p><strong>A new version of Media Browser Server is available!</strong></p>
<p><strong>${NewServerVersionAvailable}</strong></p>
<p id="newVersionNumber"></p>
<div id="btnUpdateApplicationContainer">
<button id="btnUpdateApplication" type="button" data-icon="arrow-d" data-theme="b" onclick="DashboardPage.updateApplication();">Update Now</button>
<button id="btnUpdateApplication" type="button" data-icon="arrow-d" data-theme="b" onclick="DashboardPage.updateApplication();">${ButtonUpdateNow}</button>
</div>
<div id="btnManualUpdateContainer">
Please shutdown the server and <a href="http://www.mediabrowser3.com/download" target="_blank">update manually.</a>
<a href="http://www.mediabrowser3.com/download" target="_blank">${PleaseUpdateManually}</a>
</div>
</div>
<div id="updateFail" style="color: #cc0000; display: none;">There was an error connecting to the remote Media Browser repository.</div>
<div id="updateFail" style="color: #cc0000; display: none;">${ErrorConnectingToMediaBrowserRepository}</div>
<p id="ports"></p>
<div id="pPluginUpdates"></div>
<p class="externalUrl"></p>
<div style="margin-top: 1em;">
<button class="btnRestartContainer hide" id="btnRestartServer" type="button" data-icon="refresh" data-mini="true" data-inline="true" onclick="DashboardPage.restart();">Restart</button>
<button id="btnShutdown" type="button" data-icon="delete" data-mini="true" data-inline="true" onclick="DashboardPage.shutdown();">Shutdown</button>
<button class="btnRestartContainer hide" id="btnRestartServer" type="button" data-icon="refresh" data-mini="true" data-inline="true" onclick="DashboardPage.restart();">${ButtonRestart}</button>
<button id="btnShutdown" type="button" data-icon="delete" data-mini="true" data-inline="true" onclick="DashboardPage.shutdown();">${ButtonShutdown}</button>
</div>
</div>
</div>
<div id="collapsiblePendingInstallations" data-role="collapsible" data-collapsed="false" style="margin-top: 2em; display: none;">
<h3>Pending Installations</h3>
<p>The following components have been installed or updated:</p>
<h3>${HeaderPendingInstallations}</h3>
<p>${LabelComponentsUpdated}</p>
<div id="pendingInstallations">
</div>
<p>Please restart the server to finish applying updates.</p>
<p>${MessagePleaseRestartServerToFinishUpdating}</p>
<div class="btnRestartContainer hide">
<button type="button" data-icon="refresh" data-theme="b" onclick="Dashboard.restartServer();" data-mini="true" data-inline="true">Restart Now</button>
<button type="button" data-icon="refresh" data-theme="b" onclick="Dashboard.restartServer();" data-mini="true" data-inline="true">${ButtonRestartNow}</button>
</div>
</div>
<div data-role="collapsible" data-collapsed="false" style="margin-top: 2em;">
<h3>Active Devices</h3>
<div>
<table class="tblConnections" style="border-collapse: collapse;">
</table>
<h3>${HeaderActiveDevices}</h3>
<div class="activeDevices">
</div>
</div>
<div id="runningTasksCollapsible" data-role="collapsible" data-collapsed="false" style="margin-top: 2em; display: none;">
<h3>Running Tasks</h3>
<h3>${HeaderRunningTasks}</h3>
<div>
<div id="divRunningTasks">
</div>
<p><a href="scheduledtasks.html">Manage Scheduled Tasks</a></p>
</div>
</div>
<div id="contribute" style="margin-top: 4em; display: none;">
<h2 style="margin: 0 0 .35em;">Help Improve Media Browser</h2>
<h2 style="margin: 0 0 .35em;">${HeaderHelpImproveMediaBrowser}</h2>
<div>
<a data-role="button" data-icon="mail" data-mini="true" href="supporter.html">
<img src="css/images/supporter/donatepaypal.png" /></a>
@ -113,7 +109,7 @@
<div class="readOnlyContent dashboardHomeRightColumn">
<div data-role="collapsible" data-collapsed="false">
<h3>Latest News</h3>
<h3>${HeaderLatestNews}</h3>
<div class="latestNewsItems">
</div>
</div>

View file

@ -138,19 +138,18 @@
<a class="btnPlayExternal hide" data-role="button" data-icon="play" data-inline="true" data-mini="true" href="#" target="_blank">${ButtonPlay}</a>
<a class="btnEdit hide" data-role="button" data-icon="edit" data-inline="true" data-mini="true" href="#">${ButtonEdit}</a>
</div>
<p class="itemGenres mobileGenres"></p>
<p class="itemOverview mobileOverview"></p>
</div>
<a href="#" id="lnkPreviousItem" class="lnkPreviousItem lnkSibling hide" data-role="button" title="${ButtonPrevious}" data-icon="carat-l" data-mini="true" data-inline="true" data-iconpos="notext">${ButtonPrevious}</a>
<a href="#" id="lnkNextItem" class="lnkNextItem lnkSibling hide" data-role="button" title="${ButtonNext}" data-icon="carat-r" data-mini="true" data-inline="true" data-iconpos="notext">${ButtonNext}</a>
<p class="itemGenres mobileGenres"></p>
<p class="itemOverview mobileOverview"></p>
</div>
<div data-role="content">
<div class="detailPageContent">
<div id="detailsSection" class="detailSection hide">
<br />
<div class="tabButtons"></div>
<div class="tabButtons" style="margin-top: .75em;"></div>
<div class="detailSectionContent" style="padding: .25em .7em 0;">

View file

@ -37,11 +37,11 @@
<table data-role="table" data-mode="reflow" class="tblTuners stripedTable ui-responsive table-stroke">
<thead>
<tr>
<th>Name</th>
<th>Source</th>
<th>Status</th>
<th>Program</th>
<th>Clients</th>
<th>${HeaderName}</th>
<th>${HeaderSource}</th>
<th>${HeaderStatus}</th>
<th>${HeaderProgram}</th>
<th>${HeaderClients}</th>
<th></th>
</tr>
</thead>

View file

@ -0,0 +1,13 @@
<!DOCTYPE html>
<html>
<head>
<title>${TitleMediaBrowser}</title>
</head>
<body>
<div id="nowPlayingPage" data-role="page" class="page libraryPage" data-theme="b">
<div data-role="content">
</div>
</div>
</body>
</html>

View file

@ -1,7 +1,7 @@
<!DOCTYPE html>
<html>
<head>
<title></title>
<title>${TitleMediaBrowser}</title>
</head>
<body>
<div id="playlistPage" data-role="page" class="page libraryPage" data-theme="b">

View file

@ -80,14 +80,6 @@
$('#hfResultId', popup).val(item.Id);
if (item.ExtractedName) {
$('#fldRememberCorrection', popup).hide();
} else {
$('#fldRememberCorrection', popup).hide();
}
$('#chkRememberEpisodeCorrection', popup).checked(false).checkboxradio('refresh');
var seriesHtml = allSeries.map(function (s) {
return '<option value="' + s.Id + '">' + s.Name + '</option>';
@ -157,8 +149,7 @@
SeriesId: $('#selectSeries', form).val(),
SeasonNumber: $('#txtSeason', form).val(),
EpisodeNumber: $('#txtEpisode', form).val(),
EndingEpisodeNumber: $('#txtEndingEpisode', form).val(),
RememberCorrection: $('#chkRememberEpisodeCorrection', form).checked()
EndingEpisodeNumber: $('#txtEndingEpisode', form).val()
};
ApiClient.performEpisodeOrganization(resultId, options).done(function () {

View file

@ -66,6 +66,17 @@
this.hasReceivers = false;
this.currentMediaOffset = 0;
// Progress bar element id
this.progressBar = "positionSlider";
// Timec display element id
this.duration = "currentTime";
// Playback display element id
this.playback = "playTime";
this.initializeCastPlayer();
};
@ -89,7 +100,7 @@
// v1 Id AE4DA10A
// v2 Id 472F0435
var applicationID = 'AE4DA10A';
var applicationID = '472F0435';
// request session
var sessionRequest = new chrome.cast.SessionRequest(applicationID);
@ -230,6 +241,7 @@
};
function getCodecLimits() {
return {
maxVideoAudioChannels: 6,
@ -445,6 +457,8 @@
function getMetadata(item) {
console.log("md item", item);
var metadata = {};
if (item.Type == 'Episode') {
@ -512,7 +526,7 @@
else if (item.MediaType == 'Movie') {
metadata = new chrome.cast.media.MovieMediaMetadata();
metadata.type = chrome.cast.media.MetadataType.MUSIC_TRACK;
metadata.type = chrome.cast.media.MetadataType.MOVIE;
if (item.ProductionYear) {
metadata.releaseYear = item.ProductionYear;
@ -595,7 +609,7 @@
url += '&maxheight=' + codecLimits.maxHeight;
url += '&videoCodec=h264';
url += '&audioCodec=aac';
url += '&audioCodec=aac,mp3';
url += '&audiosamplerate=' + codecLimits.maxSampleRate;
url += '&mediasourceid=' + mediaSourceInfo.mediaSource.Id;
@ -617,6 +631,8 @@
return;
}
this.currentMediaOffset = startTimeTicks || 0;
var maxBitrate = 12000000;
var mediaInfo = getMediaSourceInfo(user, item, maxBitrate, mediaSourceId, audioStreamIndex, subtitleStreamIndex);
@ -653,40 +669,62 @@
console.log("chromecast new media session ID:" + mediaSession.mediaSessionId + ' (' + how + ')');
this.currentMediaSession = mediaSession;
this.currentMediaTime = this.session.media[0].currentTime;
if (how == 'loadMedia') {
this.castPlayerState = PLAYER_STATE.PLAYING;
clearInterval(this.timer);
this.startProgressTimer(this.incrementMediaTime);
}
if (how == 'activeSession') {
this.castPlayerState = this.session.media[0].playerState;
this.currentMediaTime = this.session.media[0].currentTime;
}
if (this.castPlayerState == PLAYER_STATE.PLAYING) {
// start progress timer
//this.startProgressTimer(this.incrementMediaTime);
this.startProgressTimer(this.incrementMediaTime);
}
this.currentMediaSession.addUpdateListener(this.onMediaStatusUpdate.bind(this));
this.currentMediaDuration = this.currentMediaSession.media.duration;
//this.currentMediaDuration = this.currentMediaSession.media.duration;
//var duration = this.currentMediaDuration;
//var hr = parseInt(duration / 3600);
//duration -= hr * 3600;
//var min = parseInt(duration / 60);
//var sec = parseInt(duration % 60);
//if (hr > 0) {
// duration = hr + ":" + min + ":" + sec;
//var playTime = document.getElementById(this.playback);
//if (!playTime) {
// // Set duration time
// var totalTime = document.getElementById(this.duration);
// totalTime.innerHTML = " / " + formatTime(this.currentMediaDuration);
// // Set play time
// playTime = document.createElement("div");
// playTime.id = this.playback;
// playTime.className = "currentTime";
// playTime.style.marginRight = "5px";
// totalTime.parentNode.insertBefore(playTime, totalTime);
// playTime.innerHTML = formatTime(this.currentMediaTime);
//}
//else {
// if (min > 0) {
// duration = min + ":" + sec;
// }
// else {
// duration = sec;
// }
//}
//document.getElementById("duration").innerHTML = duration;
};
function formatTime(duration) {
var hr = parseInt(duration / 3600);
duration -= hr * 3600;
var min = parseInt(duration / 60);
var sec = parseInt(duration % 60);
hr = "" + hr;
min = "" + min;
sec = "" + sec;
var hh = pad(hr);
var mm = pad(min);
var ss = pad(sec);
duration = hh + ":" + mm + ":" + ss;
return duration;
};
function pad(s) {
return "00".substring(0, 2 - s.length) + s;
};
/**
@ -707,7 +745,7 @@
this.castPlayerState = PLAYER_STATE.IDLE;
}
console.log("chromecast updating media");
//this.updateProgressBar(e);
this.updateProgressBarByTimer();
};
/**
@ -745,6 +783,7 @@
this.currentMediaSession.addUpdateListener(this.onMediaStatusUpdate.bind(this));
this.castPlayerState = PLAYER_STATE.PLAYING;
// start progress timer
clearInterval(this.timer);
this.startProgressTimer(this.incrementMediaTime);
break;
case PLAYER_STATE.IDLE:
@ -791,6 +830,10 @@
this.onError.bind(this));
this.castPlayerState = PLAYER_STATE.STOPPED;
clearInterval(this.timer);
//var playTime = document.getElementById(this.playback);
//if (playTime) {
// playTime.parentNode.removeChild(playTime);
//}
};
/**
@ -849,19 +892,9 @@
* @param {Event} e An event object from seek
*/
CastPlayer.prototype.seekMedia = function (event) {
var pos = parseInt(event.offsetX);
var pi = document.getElementById("progress_indicator");
var p = document.getElementById("progress");
if (event.currentTarget.id == 'progress_indicator') {
var curr = parseInt(this.currentMediaTime + this.currentMediaDuration * pos / PROGRESS_BAR_WIDTH);
var pp = parseInt(pi.style.marginLeft) + pos;
var pw = parseInt(p.style.width) + pos;
}
else {
var curr = parseInt(pos * this.currentMediaDuration / PROGRESS_BAR_WIDTH);
var pp = pos - 21 - PROGRESS_BAR_WIDTH;
var pw = pos;
}
var pos = parseInt(event);
var curr = parseInt(this.currentMediaTime + this.currentMediaDuration * pos);
if (this.castPlayerState != PLAYER_STATE.PLAYING && this.castPlayerState != PLAYER_STATE.PAUSED) {
return;
@ -899,21 +932,21 @@
* @param {Object} e An media status update object
*/
CastPlayer.prototype.updateProgressBar = function (e) {
var p = document.getElementById("progress");
var pi = document.getElementById("progress_indicator");
if (e.idleReason == 'FINISHED' && e.playerState == 'IDLE') {
p.style.width = '0px';
pi.style.marginLeft = -21 - PROGRESS_BAR_WIDTH + 'px';
clearInterval(this.timer);
this.castPlayerState = PLAYER_STATE.STOPPED;
}
else {
p.style.width = Math.ceil(PROGRESS_BAR_WIDTH * e.currentTime / this.currentMediaSession.media.duration + 1) + 'px';
this.progressFlag = false;
setTimeout(this.setProgressFlag.bind(this), 1000); // don't update progress in 1 second
var pp = Math.ceil(PROGRESS_BAR_WIDTH * e.currentTime / this.currentMediaSession.media.duration);
pi.style.marginLeft = -21 - PROGRESS_BAR_WIDTH + pp + 'px';
}
//var p = document.getElementById(this.progressBar);
//if (e.idleReason == 'FINISHED' && e.playerState == 'IDLE') {
// p.value = 0;
// clearInterval(this.timer);
// this.castPlayerState = PLAYER_STATE.STOPPED;
// if (e.idleReason == 'FINISHED') {
// $.publish("/playback/complete", e);
// console.log("playback complete", e);
// }
//}
//else {
// p.value = Number(e.currentTime / this.currentMediaSession.media.duration + 1).toFixed(3);
// this.progressFlag = false;
// setTimeout(this.setProgressFlag.bind(this), 1000); // don't update progress in 1 second
//}
};
/**
@ -928,26 +961,46 @@
* Update progress bar based on timer
*/
CastPlayer.prototype.updateProgressBarByTimer = function () {
var p = document.getElementById("progress");
if (isNaN(parseInt(p.style.width))) {
p.style.width = 0;
}
if (this.currentMediaDuration > 0) {
var pp = Math.floor(PROGRESS_BAR_WIDTH * this.currentMediaTime / this.currentMediaDuration);
}
//var p = document.getElementById(this.progressBar);
//if (isNaN(parseInt(p.value))) {
// p.value = 0;
//}
if (this.progressFlag) {
// don't update progress if it's been updated on media status update event
p.style.width = pp + 'px';
var pi = document.getElementById("progress_indicator");
pi.style.marginLeft = -21 - PROGRESS_BAR_WIDTH + pp + 'px';
}
//if (this.currentMediaDuration > 0) {
// var pp = Number(this.currentMediaTime / this.currentMediaDuration).toFixed(3);
if (pp > PROGRESS_BAR_WIDTH) {
// var startTime = this.currentMediaOffset / 10000000;
// var playTime = document.getElementById(this.playback);
// if (playTime) {
// playTime.innerHTML = formatTime(startTime + this.currentMediaTime);
// }
//}
//if (this.progressFlag) {
// // don't update progress if it's been updated on media status update event
// p.value = pp;
//}
//if (pp > 100 || this.castPlayerState == PLAYER_STATE.IDLE) {
// clearInterval(this.timer);
// this.deviceState = DEVICE_STATE.IDLE;
// this.castPlayerState = PLAYER_STATE.IDLE;
// $.publish("/playback/complete", true);
// console.log("playback complete");
//}
};
/**
* @param {function} A callback function for the fucntion to start timer
*/
CastPlayer.prototype.startProgressTimer = function(callback) {
if(this.timer) {
clearInterval(this.timer);
this.deviceState = DEVICE_STATE.IDLE;
this.castPlayerState = PLAYER_STATE.IDLE;
this.timer = null;
}
// start progress timer
this.timer = setInterval(callback.bind(this), this.timerStep);
};
var castPlayer = new CastPlayer();
@ -956,19 +1009,112 @@
var self = this;
var isPositionSliderActive = false;
var currentPlaylistIndex;
self.name = PlayerName;
self.play = function (options) {
self.isPaused = false;
if (options.items) {
self.playlist = [];
Dashboard.getCurrentUser().done(function (user) {
self.playlistIndex = 0;
castPlayer.loadMedia(user, options.items[0], options.startTimeTicks);
//$.subscribe("/playback/complete", function (e) {
// if (self.playlistIndex < (self.playlist.items || []).length) {
// self.play(self.playlist);
// }
//});
////$(".positionSlider", "#footer").off("slidestart slidestop")
//// .on('slidestart', function (e) {
//// isPositionSliderActive = true;
////}).on('slidestop', positionSliderChange);
////function positionSliderChange() {
//// isPositionSliderActive = false;
//// var newPercent = parseInt(this.value);
//// self.changeStream(newPercent);
////}
function getItemsForPlayback(query) {
var userId = Dashboard.getCurrentUserId();
query.Limit = query.Limit || 100;
query.Fields = getItemFields;
query.ExcludeLocationTypes = "Virtual";
return ApiClient.getItems(userId, query);
}
function queueItems (items) {
for (var i = 0, length = items.length; i < length; i++) {
self.playlist.push(items[i]);
}
}
function queueItemsNext(items) {
var insertIndex = 1;
for (var i = 0, length = items.length; i < length; i++) {
self.playlist.splice(insertIndex, 0, items[i]);
insertIndex++;
}
}
function translateItemsForPlayback(items) {
var deferred = $.Deferred();
var firstItem = items[0];
var promise;
if (firstItem.IsFolder) {
promise = self.getItemsForPlayback({
ParentId: firstItem.Id,
Filters: "IsNotFolder",
Recursive: true,
SortBy: "SortName",
MediaTypes: "Audio,Video"
});
}
else if (firstItem.Type == "MusicArtist") {
promise = self.getItemsForPlayback({
Artists: firstItem.Name,
Filters: "IsNotFolder",
Recursive: true,
SortBy: "SortName",
MediaTypes: "Audio"
});
}
else if (firstItem.Type == "MusicGenre") {
promise = self.getItemsForPlayback({
Genres: firstItem.Name,
Filters: "IsNotFolder",
Recursive: true,
SortBy: "SortName",
MediaTypes: "Audio"
});
}
if (promise) {
promise.done(function (result) {
deferred.resolveWith(null, [result.Items]);
});
} else {
deferred.resolveWith(null, [items]);
}
return deferred.promise();
}
self.play = function (options) {
console.log("play", options);
$("#nowPlayingBar", "#footer").show();
if (self.isPaused) {
self.isPaused = !self.isPaused;
castPlayer.playMedia();
} else if (options.items) {
Dashboard.getCurrentUser().done(function (user) {
castPlayer.loadMedia(user, options.items[self.playlistIndex++], options.startPositionTicks);
});
} else {
var userId = Dashboard.getCurrentUserId();
var query = {};
@ -978,46 +1124,158 @@
query.Ids = options.ids.join(',');
ApiClient.getItems(userId, query).done(function (result) {
options.items = result.Items;
self.play(options);
});
}
};
self.unpause = function () {
console.log("unpause");
self.isPaused = !self.isPaused;
castPlayer.playMedia();
};
self.pause = function () {
console.log("pause");
self.isPaused = true;
castPlayer.pauseMedia();
};
self.shuffle = function (id) {
self.play({ ids: [id] });
var userId = Dashboard.getCurrentUserId();
ApiClient.getItem(userId, id).done(function (item) {
var query = {
UserId: userId,
Fields: getItemFields,
Limit: 50,
Filters: "IsNotFolder",
Recursive: true,
SortBy: "Random"
};
if (item.IsFolder) {
query.ParentId = id;
}
else if (item.Type == "MusicArtist") {
query.MediaTypes = "Audio";
query.Artists = item.Name;
}
else if (item.Type == "MusicGenre") {
query.MediaTypes = "Audio";
query.Genres = item.Name;
} else {
return;
}
self.getItemsForPlayback(query).done(function (result) {
self.playlist = { items: result.Items };
console.log("shuffle items", result.Items);
self.play(self.playlist);
});
});
};
self.instantMix = function (id) {
self.play({ ids: [id] });
};
var userId = Dashboard.getCurrentUserId();
ApiClient.getItem(userId, id).done(function (item) {
var promise;
var getItemFields = "MediaSources,Chapters";
var mixLimit = 3;
self.queue = function (options) {
if (item.Type == "MusicArtist") {
promise = ApiClient.getInstantMixFromArtist(name, {
UserId: userId,
Fields: getItemFields,
Limit: mixLimit
});
}
else if (item.Type == "MusicGenre") {
promise = ApiClient.getInstantMixFromMusicGenre(name, {
UserId: userId,
Fields: getItemFields,
Limit: mixLimit
});
}
else if (item.Type == "MusicAlbum") {
promise = ApiClient.getInstantMixFromAlbum(id, {
UserId: userId,
Fields: getItemFields,
Limit: mixLimit
});
}
else if (item.Type == "Audio") {
promise = ApiClient.getInstantMixFromSong(id, {
UserId: userId,
Fields: getItemFields,
Limit: mixLimit
});
}
else {
return;
}
};
self.queueNext = function (options) {
};
self.stop = function () {
castPlayer.stop();
promise.done(function (result) {
self.playlist = { items: result.Items };
console.log("instant mix items", result.Items);
self.play(self.playlist);
});
});
};
self.canQueueMediaType = function (mediaType) {
return mediaType == "Audio";
};
self.queue = function (options) {
Dashboard.getCurrentUser().done(function (user) {
if (options.items) {
translateItemsForPlayback(options.items).done(function (items) {
queueItems(items);
});
} else {
getItemsForPlayback({
Ids: options.ids.join(',')
}).done(function (result) {
translateItemsForPlayback(result.Items).done(function (items) {
queueItems(items);
});
});
}
});
};
self.queueNext = function (options) {
Dashboard.getCurrentUser().done(function (user) {
if (options.items) {
queueItemsNext(options.items);
} else {
self.getItemsForPlayback({
Ids: options.ids.join(',')
}).done(function (result) {
options.items = result.Items;
queueItemsNext(options.items);
});
}
});
};
self.stop = function () {
$("#nowPlayingBar", "#footer").hide();
self.playlist = [];
self.playlistIndex = 0;
castPlayer.stopMedia();
};
self.displayContent = function (options) {
return false;
};
self.mute = function () {
castPlayer.mute();
};
self.unMute = function () {
self.unmute = function () {
castPlayer.unMute();
};
@ -1026,18 +1284,20 @@
};
self.getTargets = function () {
var targets = [];
targets.push(self.getCurrentTargetInfo());
if (castPlayer.hasReceivers) {
targets.push(self.getCurrentTargetInfo());
}
return targets;
};
self.getCurrentTargetInfo = function () {
var appName = null;
if (castPlayer.session && castPlayer.session.receiver && castPlayer.session.friendlyName) {
appName = castPlayer.session.friendlyName;
}
@ -1048,9 +1308,105 @@
playerName: self.name,
playableMediaTypes: ["Audio", "Video"],
isLocalPlayer: false,
appName: appName
appName: appName,
supportedCommands: []
};
};
self.setCurrentTime = function (ticks, item, updateSlider) {
// Convert to ticks
ticks = Math.floor(ticks);
var timeText = Dashboard.getDisplayTime(ticks);
if (self.currentDurationTicks) {
timeText += " / " + Dashboard.getDisplayTime(self.currentDurationTicks);
if (updateSlider) {
var percent = ticks / self.currentDurationTicks;
percent *= 100;
self.positionSlider.val(percent).slider('enable').slider('refresh');
}
} else {
self.positionSlider.slider('disable').slider('refresh');
}
self.currentTimeElement.html(timeText);
};
self.changeStream = function (position) {
console.log("seek", position);
////castPlayer.seekMedia(position);
};
self.removeFromPlaylist = function (i) {
self.playlist.remove(i);
};
self.currentPlaylistIndex = function (i) {
if (i == null) {
return currentPlaylistIndex;
}
var newItem = self.playlist[i];
Dashboard.getCurrentUser().done(function (user) {
self.playInternal(newItem, 0, user);
currentPlaylistIndex = i;
});
};
self.nextTrack = function () {
var newIndex = currentPlaylistIndex + 1;
var newItem = self.playlist[newIndex];
if (newItem) {
Dashboard.getCurrentUser().done(function (user) {
self.playInternal(newItem, 0, user);
currentPlaylistIndex = newIndex;
});
}
};
self.previousTrack = function () {
var newIndex = currentPlaylistIndex - 1;
if (newIndex >= 0) {
var newItem = self.playlist[newIndex];
if (newItem) {
Dashboard.getCurrentUser().done(function (user) {
self.playInternal(newItem, 0, user);
currentPlaylistIndex = newIndex;
});
}
}
};
self.beginPlayerUpdates = function () {
// Setup polling here
};
self.endPlayerUpdates = function () {
// Stop polling here
};
self.volumeDown = function () {
};
self.volumeUp = function () {
};
self.getPlayerState = function () {
var deferred = $.Deferred();
var result = self.getPlayerStateInternal();
deferred.resolveWith(null, [result]);
return deferred.promise();
};
self.getPlayerStateInternal = function () {
return {};
};
}
MediaController.registerPlayer(new chromecastPlayer());

View file

@ -40,7 +40,7 @@
Dashboard.updateSystemInfo(systemInfo);
$('#appVersionNumber', page).html(systemInfo.Version);
$('#appVersionNumber', page).html('Version ' + systemInfo.Version);
var port = systemInfo.HttpServerPortNumber;
@ -190,17 +190,15 @@
var html = '';
var table = $('.tblConnections', page);
var parentElement = $('.activeDevices', page);
$('.trSession', table).addClass('deadSession');
var deviceId = ApiClient.deviceId();
$('.activeSession', parentElement).addClass('deadSession');
for (var i = 0, length = sessions.length; i < length; i++) {
var connection = sessions[i];
var rowId = 'trSession' + connection.Id;
var rowId = 'session' + connection.Id;
var elem = $('#' + rowId, page);
@ -209,93 +207,184 @@
continue;
}
html += '<tr class="trSession" id="' + rowId + '">';
var nowPlayingItem = connection.NowPlayingItem;
html += '<td class="clientType" style="text-align:center;">';
html += DashboardPage.getClientType(connection);
html += '</td>';
var className = nowPlayingItem ? 'activeSession' : 'notPlayingSession activeSession';
html += '<td>';
html += '<a class="' + className + '" id="' + rowId + '" href="nowplaying.html">';
html += '<div style="max-width:200px;">';
if (deviceId == connection.DeviceId) {
html += connection.DeviceName;
html += '<div class="sessionNowPlayingContent"';
var imgUrl = DashboardPage.getNowPlayingImageUrl(nowPlayingItem);
if (imgUrl) {
html += ' data-src="' + imgUrl + '" style="display:inline-block;background-image:url(\'' + imgUrl + '\');"';
}
html += '></div>';
html += '<div class="sessionNowPlayingInnerContent">';
html += '<div class="sessionAppInfo">';
var clientImage = DashboardPage.getClientImage(connection);
if (clientImage) {
html += clientImage;
}
html += '<div class="sessionAppName" style="display:inline-block;">' + connection.DeviceName;
html += '<br/>' + connection.ApplicationVersion;
html += '</div>';
html += '</div>';
html += '<div class="sessionUserInfo">';
var userImage = DashboardPage.getUserImage(connection);
if (userImage) {
html += '<div class="sessionUserImage" data-src="' + userImage + '">';
html += '<img src="' + userImage + '" />';
} else {
html += '<a href="#" onclick="RemoteControl.showMenu({sessionId:\'' + connection.Id + '\'});">' + connection.DeviceName + '</a>';
html += '<div class="sessionUserImage">';
}
html += '</div>';
html += '<div>' + connection.ApplicationVersion + '</div>';
html += '<div class="username">';
html += '<div class="sessionUserName">';
html += DashboardPage.getUsersHtml(connection);
html += '</div>';
html += '</td>';
var nowPlayingItem = connection.NowPlayingItem;
html += '<td>';
html += '<div class="nowPlayingImage">';
html += DashboardPage.getNowPlayingImage(nowPlayingItem);
html += '</div>';
html += '<div class="clientNowPlayingText">';
html += DashboardPage.getNowPlayingText(connection, nowPlayingItem);
html += '<div class="sessionNowPlayingInfo">';
if (nowPlayingItem) {
html += DashboardPage.getNowPlayingName(connection);
}
html += '</div>';
html += '</td>';
if (nowPlayingItem) {
var value = (100 * connection.NowPlayingPositionTicks) / nowPlayingItem.RunTimeTicks;
html += '</tr>';
html += '<progress class="itemProgressBar" min="0" max="100" value="' + value + '"></progress>';
} else {
html += '<progress class="itemProgressBar" min="0" max="100" style="display:none;"></progress>';
}
html += '</div>';
html += '</a>';
}
table.append(html).trigger('create');
parentElement.append(html).trigger('create');
$('.deadSession', parentElement).remove();
},
getNowPlayingName: function (session) {
var nowPlayingItem = session.NowPlayingItem;
if (!nowPlayingItem) {
return 'Last seen ' + humane_date(session.LastActivityDate);
}
var topText = nowPlayingItem.Name;
if (nowPlayingItem.MediaType == 'Video') {
if (nowPlayingItem.IndexNumber != null) {
topText = nowPlayingItem.IndexNumber + " - " + topText;
}
if (nowPlayingItem.ParentIndexNumber != null) {
topText = nowPlayingItem.ParentIndexNumber + "." + topText;
}
}
var bottomText = '';
if (nowPlayingItem.Artists && nowPlayingItem.Artists.length) {
bottomText = topText;
topText = nowPlayingItem.Artists[0];
}
else if (nowPlayingItem.SeriesName || nowPlayingItem.Album) {
bottomText = topText;
topText = nowPlayingItem.SeriesName || nowPlayingItem.Album;
}
else if (nowPlayingItem.ProductionYear) {
bottomText = nowPlayingItem.ProductionYear;
}
return bottomText ? topText + '<br/>' + bottomText : topText;
$('.deadSession', table).remove();
},
getUsersHtml: function (session) {
var html = '';
var html = [];
if (session.UserId) {
html += '<div>' + session.UserName + '</div>';
html.push(session.UserName);
}
html += session.AdditionalUsers.map(function (currentSession) {
for (var i = 0, length = session.AdditionalUsers.length; i < length; i++) {
return '<div>' + currentSession.UserName + '</div>';
});
html.push(session.AdditionalUsers[i].UserName);
}
return html;
return html.join(', ');
},
getUserImage: function (session) {
if (session.UserId && session.UserPrimaryImageTag) {
return ApiClient.getUserImageUrl(session.UserId, {
tag: session.UserPrimaryImageTag,
height: 24,
type: 'Primary'
});
}
return null;
},
updateSession: function (row, session) {
row.removeClass('deadSession');
$('.username', row).html(DashboardPage.getUsersHtml(session));
var nowPlayingItem = session.NowPlayingItem;
$('.clientNowPlayingText', row).html(DashboardPage.getNowPlayingText(session, nowPlayingItem)).trigger('create');
if (nowPlayingItem) {
row.removeClass('notPlayingSession');
} else {
row.addClass('notPlayingSession');
}
var imageRow = $('.nowPlayingImage', row);
$('.sessionUserName', row).html(DashboardPage.getUsersHtml(session));
var image = $('img', imageRow)[0];
$('.sessionNowPlayingInfo', row).html(DashboardPage.getNowPlayingName(session));
var nowPlayingItemId = nowPlayingItem ? nowPlayingItem.Id : null;
var nowPlayingItemImageTag = nowPlayingItem ? nowPlayingItem.PrimaryImageTag : null;
if (nowPlayingItem && nowPlayingItem.RunTimeTicks) {
if (!image || image.getAttribute('data-itemid') != nowPlayingItemId || image.getAttribute('data-tag') != nowPlayingItemImageTag) {
imageRow.html(DashboardPage.getNowPlayingImage(nowPlayingItem));
var value = (100 * session.NowPlayingPositionTicks) / nowPlayingItem.RunTimeTicks;
$('progress', row).show().val(value);
} else {
$('progress', row).hide();
}
var imgUrl = DashboardPage.getNowPlayingImageUrl(nowPlayingItem) || '';
var imgElem = $('.sessionNowPlayingContent', row)[0];
if (imgUrl != imgElem.getAttribute('data-src')) {
imgElem.style.backgroundImage = imgUrl ? 'url(\'' + imgUrl + '\')' : '';
imgElem.setAttribute('data-src', imgUrl);
}
},
getClientType: function (connection) {
getClientImage: function (connection) {
var clientLowered = connection.Client.toLowerCase();
@ -325,89 +414,81 @@
}
if (clientLowered == "mb-classic") {
return "<img src='css/images/clients/mbc.png' alt='Media Browser Classic' />";
return "<img src='css/images/clients/mbc.png' />";
}
if (clientLowered == "media browser theater") {
return "<img src='css/images/clients/mb.png' alt='Media Browser Theater' />";
return "<img src='css/images/clients/mb.png' />";
}
if (clientLowered == "android") {
return "<img src='css/images/clients/android.png' alt='Android' />";
return "<img src='css/images/clients/android.png' />";
}
if (clientLowered == "roku") {
return "<img src='css/images/clients/roku.jpg' alt='Roku' />";
return "<img src='css/images/clients/roku.jpg' />";
}
if (clientLowered == "ios") {
return "<img src='css/images/clients/ios.png' alt='iOS' />";
return "<img src='css/images/clients/ios.png' />";
}
if (clientLowered == "windows rt") {
return "<img src='css/images/clients/windowsrt.png' alt='Windows RT' />";
return "<img src='css/images/clients/windowsrt.png' />";
}
if (clientLowered == "windows phone") {
return "<img src='css/images/clients/windowsphone.png' alt='Windows Phone' />";
return "<img src='css/images/clients/windowsphone.png' />";
}
if (clientLowered == "dlna") {
return "<img src='css/images/clients/dlna.png' alt='Dlna' />";
return "<img src='css/images/clients/dlna.png' />";
}
if (clientLowered == "mbkinect") {
return "<img src='css/images/clients/mbkinect.png' alt='MB Kinect' />";
return "<img src='css/images/clients/mbkinect.png' />";
}
if (clientLowered == "xbmc") {
return "<img src='css/images/clients/xbmc.png' alt='Xbmc' />";
return "<img src='css/images/clients/xbmc.png' />";
}
if (clientLowered == "chromecast") {
return "<img src='css/images/chromecast/ic_media_route_on_holo_light.png' alt='Chromecast' />";
return "<img src='css/images/chromecast/ic_media_route_on_holo_light.png' />";
}
return connection.Client;
return null;
},
getNowPlayingImage: function (item) {
getNowPlayingImageUrl: function (item) {
if (item && item.BackdropImageTag) {
return ApiClient.getImageUrl(item.BackdropItemId, {
type: "Backdrop",
width: 810,
tag: item.BackdropImageTag
});
}
if (item && item.ThumbImageTag) {
return ApiClient.getImageUrl(item.ThumbItemId, {
type: "Thumb",
width: 810,
tag: item.ThumbImageTag
});
}
if (item && item.PrimaryImageTag) {
var url = ApiClient.getImageUrl(item.Id, {
return ApiClient.getImageUrl(item.PrimaryImageItemId, {
type: "Primary",
height: 100,
width: 810,
tag: item.PrimaryImageTag
});
url += "&xxx=" + new Date().getTime();
return "<img data-itemid='" + item.Id + "' data-tag='" + item.PrimaryImageTag + "' class='clientNowPlayingImage' src='" + url + "' alt='" + item.Name + "' title='" + item.Name + "' />";
}
return "";
},
getNowPlayingText: function (connection, item) {
var html = "";
if (item) {
html += "<div><a href='itemdetails.html?id=" + item.Id + "'>" + item.Name + "</a></div>";
html += "<div>";
if (item.RunTimeTicks) {
html += Dashboard.getDisplayTime(connection.NowPlayingPositionTicks || 0) + " / ";
html += Dashboard.getDisplayTime(item.RunTimeTicks);
}
html += "</div>";
}
return html;
return null;
},
systemUpdateTaskKey: "SystemUpdateTask",

View file

@ -57,7 +57,7 @@
if (person.PrimaryImageTag) {
imgUrl = ApiClient.getPersonImageUrl(person.Name, {
height: 280,
width: 150,
tag: person.PrimaryImageTag,
type: "primary"
});

View file

@ -34,7 +34,8 @@
showTitle: true,
showParentTitle: true,
overlayText: true,
selectionPanel: true
selectionPanel: true,
lazy: true
});
$('.itemsContainer', page).removeClass('timelineItemsContainer');

View file

@ -66,18 +66,11 @@
renderDetails(page, item);
renderTabs(page, item);
if (ApiClient.isWebSocketOpen()) {
$(page).trigger('displayingitem', [{
var vals = [item.Type, item.Id, item.Name];
var context = getParameterByName('context');
if (context) {
vals.push(vals);
}
ApiClient.sendWebSocketMessage("Context", vals.join('|'));
}
item: item,
context: getParameterByName('context')
}]);
Dashboard.getCurrentUser().done(function (user) {
@ -403,7 +396,7 @@
};
query = $.extend(query, options || {});
if (query.IncludeItemTypes == "Audio") {
query.SortBy = "Album,SortName";
}
@ -426,7 +419,8 @@
html += LibraryBrowser.getSongTableHtml(result.Items, {
showAlbum: true,
showArtist: true
showArtist: true,
showAlbumArtist: true
});
}

View file

@ -75,11 +75,11 @@
}
if (!item.LocalTrailerCount && item.RemoteTrailers.length && item.PlayAccess == 'Full') {
$('.btnPlayExternalTrailer', page).removeClass('hide').attr('href', item.RemoteTrailers[0].Url);
} else {
$('.btnPlayExternalTrailer', page).addClass('hide').attr('href', '#');
}
@ -120,9 +120,11 @@
setPeopleHeader(page, item);
if (ApiClient.isWebSocketOpen()) {
ApiClient.sendWebSocketMessage("Context", [item.Type, item.Id, item.Name, context].join('|'));
}
$(page).trigger('displayingitem', [{
item: item,
context: context
}]);
Dashboard.hideLoadingMsg();
});
@ -265,8 +267,7 @@
$('#musicVideosCollapsible', page).hide();
}
renderThemeSongs(page, item, user);
renderThemeVideos(page, item, user);
renderThemeMedia(page, item, user);
renderCriticReviews(page, item, 1);
}
@ -904,22 +905,51 @@
$('#criticReviewsContent', page).html(html).trigger('create');
}
function renderThemeMedia(page, item) {
ApiClient.getThemeMedia(Dashboard.getCurrentUserId(), item.Id, true).done(function (result) {
function renderThemeSongs(page, item) {
var themeSongs = result.ThemeSongsResult.OwnerId == item.Id ?
result.ThemeSongsResult.Items :
[];
var themeVideos = result.ThemeVideosResult.OwnerId == item.Id ?
result.ThemeVideosResult.Items :
[];
ApiClient.getThemeSongs(Dashboard.getCurrentUserId(), item.Id).done(function (result) {
if (result.Items.length) {
renderThemeSongs(page, themeSongs);
renderThemeVideos(page, themeVideos);
$('#themeSongsCollapsible', page).show();
$('#themeSongsContent', page).html(LibraryBrowser.getSongTableHtml(result.Items, { showArtist: true, showAlbum: true })).trigger('create');
} else {
$('#themeSongsCollapsible', page).hide();
}
$(page).trigger('thememediadownload', [result]);
});
}
function renderThemeSongs(page, items) {
if (items.length) {
$('#themeSongsCollapsible', page).show();
$('#themeSongsContent', page).html(LibraryBrowser.getSongTableHtml(items, { showArtist: true, showAlbum: true, showAlbumArtist: true })).trigger('create');
} else {
$('#themeSongsCollapsible', page).hide();
}
}
function renderThemeVideos(page, items, user) {
if (items.length) {
$('#themeVideosCollapsible', page).show();
$('#themeVideosContent', page).html(getVideosHtml(items, user)).trigger('create');
} else {
$('#themeVideosCollapsible', page).hide();
}
}
function renderMusicVideos(page, item, user) {
ApiClient.getItems(user.Id, {
@ -944,21 +974,6 @@
}
function renderThemeVideos(page, item, user) {
ApiClient.getThemeVideos(user.Id, item.Id).done(function (result) {
if (result.Items.length) {
$('#themeVideosCollapsible', page).show();
$('#themeVideosContent', page).html(getVideosHtml(result.Items, user)).trigger('create');
} else {
$('#themeVideosCollapsible', page).hide();
}
});
}
function renderAdditionalParts(page, item, user) {
ApiClient.getAdditionalVideoParts(user.Id, item.Id).done(function (result) {
@ -1238,7 +1253,7 @@
if (cast.PrimaryImageTag) {
imgUrl = ApiClient.getPersonImageUrl(cast.Name, {
width: 130,
width: 100,
tag: cast.PrimaryImageTag,
type: "primary"
});

View file

@ -93,9 +93,10 @@
Dashboard.setPageTitle(name);
if (ApiClient.isWebSocketOpen()) {
ApiClient.sendWebSocketMessage("Context", [item.Type, item.Id, item.Name].join('|'));
}
$(page).trigger('displayingitem', [{
item: item
}]);
});
@ -203,7 +204,7 @@
}).on('pageshow', "#itemListPage", function () {
var page = this;
query.Limit = LibraryBrowser.getDefaultPageSize();
query.ParentId = getParameterByName('parentId');
query.Filters = "";

View file

@ -1,5 +1,11 @@
var LibraryBrowser = (function (window, document, $, screen, localStorage) {
$(function() {
$("body").on("create", function () {
$(".lazy").unveil(200);
});
});
var defaultBackground = "#333";
return {
@ -185,14 +191,17 @@
html += '<tr>';
html += LibraryBrowser.getSongHeaderCellHtml('', '', options.enableColumnSorting);
html += LibraryBrowser.getSongHeaderCellHtml('', '', options.enableColumnSorting);
html += LibraryBrowser.getSongHeaderCellHtml('Disc', 'desktopColumn', options.enableColumnSorting);
html += LibraryBrowser.getSongHeaderCellHtml('#', 'desktopColumn', options.enableColumnSorting);
html += LibraryBrowser.getSongHeaderCellHtml('Track', '', options.enableColumnSorting, 'Name', options.sortBy, options.sortOrder);
if (options.showAlbum) {
html += LibraryBrowser.getSongHeaderCellHtml('Album', '', options.enableColumnSorting, 'Album,SortName', options.sortBy, options.sortOrder);
}
if (options.showArtist) {
html += LibraryBrowser.getSongHeaderCellHtml('Artist', '', options.enableColumnSorting, 'Artist,Album,SortName', options.sortBy, options.sortOrder);
html += LibraryBrowser.getSongHeaderCellHtml('Artist', 'tabletColumn', options.enableColumnSorting, 'Artist,Album,SortName', options.sortBy, options.sortOrder);
}
if (options.showAlbumArtist) {
html += LibraryBrowser.getSongHeaderCellHtml('Album Artist', 'tabletColumn', options.enableColumnSorting, 'AlbumArtist,Album,SortName', options.sortBy, options.sortOrder);
}
@ -214,12 +223,8 @@
html += '<button class="btnQueue" data-icon="plus" type="button" data-iconpos="notext" onclick="MediaController.queue(\'' + item.Id + '\');" data-inline="true" title="Queue">Queue</button>';
html += '</td>';
var num = item.IndexNumber;
if (num && item.ParentIndexNumber) {
num = item.ParentIndexNumber + "." + num;
}
html += '<td>' + (num || "") + '</td>';
html += '<td class="desktopColumn">' + (item.ParentIndexNumber || "") + '</td>';
html += '<td class="desktopColumn">' + (item.IndexNumber || "") + '</td>';
html += '<td><a href="' + LibraryBrowser.getHref(item, "music") + '">' + (item.Name || "") + '</a></td>';
@ -237,14 +242,14 @@
var artistLinksHtml = LibraryBrowser.getArtistLinksHtml(item.Artists);
html += '<td>' + artistLinksHtml + '</td>';
html += '<td class="tabletColumn">' + artistLinksHtml + '</td>';
}
else {
html += '<td></td>';
html += '<td class="tabletColumn"></td>';
}
}
if (options.showArtist) {
if (options.showAlbumArtist) {
if (item.AlbumArtist) {
@ -667,8 +672,8 @@
html += '<a data-itemid="' + item.Id + '" class="' + cssClass + '" data-mediasourcecount="' + mediaSourceCount + '" href="' + href + '">';
var style = "";
if (imgUrl) {
options.lazy = false;
if (imgUrl && !options.lazy) {
style += 'background-image:url(\'' + imgUrl + '\');';
}
@ -681,9 +686,16 @@
imageCssClass += " coveredPosterItemImage";
}
var dataSrc = "";
if (options.lazy) {
imageCssClass += " lazy";
dataSrc = ' data-src="' + imgUrl + '"';
}
var progressHtml = options.showProgress === false ? '' : LibraryBrowser.getItemProgressBarHtml(item);
html += '<div class="' + imageCssClass + '" style="' + style + '">';
html += '<div class="' + imageCssClass + '" style="' + style + '"' + dataSrc + '>';
html += '<div class="posterItemOverlayTarget"></div>';
@ -756,6 +768,10 @@
var itemCountHtml = LibraryBrowser.getItemCountsHtml(options, item);
if (item.Type == "Person" && !itemCountHtml) {
itemCountHtml = "&nbsp;";
}
if (itemCountHtml) {
html += "<div class='" + cssClass + "'>";
html += itemCountHtml;

View file

@ -16,7 +16,7 @@
html += '<a class="desktopHomeLink" href="index.html"><img src="css/images/mblogoicon.png" /></a>';
html += '<button class="viewMenuRemoteControlButton" onclick="RemoteControl.showMenu();" type="button" data-icon="wireless" data-inline="true" data-iconpos="notext" title="Remote Control">Remote Control</button>';
html += '<a class="viewMenuRemoteControlButton" href="nowplaying.html" data-role="button" data-icon="wireless" data-inline="true" data-iconpos="notext" title="Now Playing">Remote Control</a>';
if (user.Configuration.IsAdministrator) {
html += '<a class="editorMenuLink" href="edititemmetadata.html" data-role="button" data-icon="edit" data-inline="true" data-iconpos="notext" title="Metadata Manager">Metadata Manager</a>';
@ -31,7 +31,7 @@
if (user.PrimaryImageTag) {
var url = ApiClient.getUserImageUrl(user.Id, {
height: 40,
height: 24,
tag: user.PrimaryImageTag,
type: "Primary"
});

View file

@ -135,14 +135,11 @@
$('.userDataIcons', page).html(LibraryBrowser.getUserDataIconsHtml(item));
if (ApiClient.isWebSocketOpen()) {
$(page).trigger('displayingitem', [{
var vals = [item.Type, item.Id, item.Name];
vals.push('livetv');
ApiClient.sendWebSocketMessage("Context", vals.join('|'));
}
item: item,
context: 'livetv'
}]);
Dashboard.getCurrentUser().done(function (user) {

View file

@ -50,14 +50,11 @@
LiveTvHelpers.renderMiscProgramInfo($('.miscTvProgramInfo', page), item);
if (ApiClient.isWebSocketOpen()) {
$(page).trigger('displayingitem', [{
var vals = [item.Type, item.Id, item.Name];
vals.push('livetv');
ApiClient.sendWebSocketMessage("Context", vals.join('|'));
}
item: item,
context: 'livetv'
}]);
if (item.TimerId) {
$('#cancelRecordingButtonContainer', page).show();

View file

@ -55,14 +55,11 @@
LiveTvHelpers.renderMiscProgramInfo($('.miscTvProgramInfo', page), item);
if (ApiClient.isWebSocketOpen()) {
$(page).trigger('displayingitem', [{
var vals = [item.Type, item.Id, item.Name];
vals.push('livetv');
ApiClient.sendWebSocketMessage("Context", vals.join('|'));
}
item: item,
context: 'livetv'
}]);
$('.recordingStatus', page).html('Status:&nbsp;&nbsp;&nbsp;' + item.Status);

View file

@ -1,11 +1,26 @@
(function ($, window) {
var enableMirrorMode;
var currentDisplayInfo;
function mirrorItem(info) {
var item = info.item;
MediaController.getCurrentPlayer().displayContent({
itemName: item.Name,
itemId: item.Id,
itemType: item.Type,
context: info.context
});
}
function mediaController() {
var self = this;
var currentPlayer;
var currentTargetInfo;
var players = [];
self.registerPlayer = function (player) {
@ -21,7 +36,8 @@
isLocalPlayer: currentPlayer.isLocalPlayer,
id: currentTargetInfo.id,
deviceName: currentTargetInfo.deviceName,
playableMediaTypes: currentTargetInfo.playableMediaTypes
playableMediaTypes: currentTargetInfo.playableMediaTypes,
supportedCommands: currentTargetInfo.supportedCommands
};
};
@ -43,12 +59,12 @@
$(self).trigger('playerchange');
};
self.setDefaultPlayerActive = function() {
self.setDefaultPlayerActive = function () {
self.setActivePlayer(self.getDefaultPlayer());
};
self.removeActivePlayer = function (name) {
if (self.getPlayerInfo().name == name) {
self.setDefaultPlayerActive();
}
@ -78,7 +94,7 @@
}
targets = targets.sort(function(a,b) {
targets = targets.sort(function (a, b) {
var aVal = a.isLocalPlayer ? 0 : 1;
var bVal = b.isLocalPlayer ? 0 : 1;
@ -174,20 +190,79 @@
return p.isDefaultPlayer;
})[0];
};
self.getCurrentPlayer = function () {
return currentPlayer;
};
self.pause = function () {
currentPlayer.pause();
};
self.stop = function () {
currentPlayer.stop();
};
self.unpause = function () {
currentPlayer.unpause();
};
self.seek = function (position) {
currentPlayer.seek(position);
};
self.currentPlaylistIndex = function (i) {
currentPlayer.currentPlaylistIndex(i);
};
self.removeFromPlaylist = function (i) {
currentPlayer.removeFromPlaylist(i);
};
self.nextTrack = function () {
currentPlayer.nextTrack();
};
self.previousTrack = function () {
currentPlayer.previousTrack();
};
self.mute = function () {
currentPlayer.mute();
};
self.unmute = function () {
currentPlayer.unmute();
};
self.toggleMute = function () {
currentPlayer.toggleMute();
};
self.volumeDown = function () {
currentPlayer.volumeDown();
};
self.volumeUp = function () {
currentPlayer.volumeUp();
};
self.shuffle = function (id) {
currentPlayer.shuffle(id);
};
}
window.MediaController = new mediaController();
function onWebSocketMessageReceived(e, msg) {
var localPlayer = msg.MessageType === "Play" ||
msg.MessageType === "Playstate" ||
msg.MessageType === "GeneralCommand" ?
MediaController.getLocalPlayer() :
null;
var localPlayer;
if (msg.MessageType === "Play") {
localPlayer = MediaController.getLocalPlayer();
if (msg.Data.PlayCommand == "PlayNext") {
localPlayer.queueNext({ ids: msg.Data.ItemIds });
}
@ -207,6 +282,8 @@
}
else if (msg.MessageType === "Playstate") {
localPlayer = MediaController.getLocalPlayer();
if (msg.Data.Command === 'Stop') {
localPlayer.stop();
}
@ -225,14 +302,13 @@
else if (msg.Data.Command === 'PreviousTrack') {
localPlayer.previousTrack();
}
else if (msg.Data.Command === 'Fullscreen') {
localPlayer.remoteFullscreen();
}
}
else if (msg.MessageType === "GeneralCommand") {
var cmd = msg.Data;
localPlayer = MediaController.getLocalPlayer();
if (cmd.Name === 'Mute') {
localPlayer.mute();
}
@ -248,6 +324,12 @@
else if (cmd.Name === 'ToggleMute') {
localPlayer.toggleMute();
}
else if (cmd.Name === 'Fullscreen') {
localPlayer.remoteFullscreen();
}
else if (cmd.Name === 'SetVolume') {
localPlayer.setVolume(parseFloat(cmd.Arguments.Volume));
}
}
}
@ -258,7 +340,9 @@
var playerInfo = MediaController.getPlayerInfo();
var html = '';
html += '<h3>Select Player:</h3>';
html += '<form>';
html += '<form><h3>Select Player:</h3>';
html += '<fieldset data-role="controlgroup" data-mini="true">';
for (var i = 0, length = targets.length; i < length; i++) {
@ -270,7 +354,9 @@
var isChecked = target.id == playerInfo.id;
var checkedHtml = isChecked ? ' checked="checked"' : '';
html += '<input type="radio" class="radioSelectPlayerTarget" name="radioSelectPlayerTarget" data-mediatypes="' + target.playableMediaTypes.join(',') + '" data-playername="' + target.playerName + '" data-targetid="' + target.id + '" data-targetname="' + target.name + '" id="' + id + '" value="' + target.id + '"' + checkedHtml + '>';
var mirror = (!target.isLocalPlayer && target.supportedCommands.indexOf('DisplayContent') != -1) ? 'true' : 'false';
html += '<input type="radio" class="radioSelectPlayerTarget" name="radioSelectPlayerTarget" data-mirror="' + mirror + '" data-commands="' + target.supportedCommands.join(',') + '" data-mediatypes="' + target.playableMediaTypes.join(',') + '" data-playername="' + target.playerName + '" data-targetid="' + target.id + '" data-targetname="' + target.name + '" id="' + id + '" value="' + target.id + '"' + checkedHtml + '>';
html += '<label for="' + id + '" style="font-weight:normal;">' + target.name;
if (target.appName) {
@ -284,6 +370,11 @@
html += '<p class="fieldDescription">All plays will be sent to the selected player.</p>';
var checkedHtml = enableMirrorMode ? ' checked="checked"' : '';
html += '<div style="margin-top:1.5em;" class="fldMirrorMode"><label for="chkEnableMirrorMode">Enable Mirror Mode</label><input type="checkbox" class="chkEnableMirrorMode" id="chkEnableMirrorMode" data-mini="true"' + checkedHtml + ' /></div>';
html += '</form>';
return html;
}
@ -308,17 +399,47 @@
$('.players', elem).html(getTargetsHtml(targets)).trigger('create');
$('.chkEnableMirrorMode', elem).on().on('change', function () {
enableMirrorMode = this.checked;
if (this.checked && currentDisplayInfo) {
mirrorItem(currentDisplayInfo);
}
});
$('.radioSelectPlayerTarget', elem).on('change', function () {
var supportsMirror = this.getAttribute('data-mirror') == 'true';
if (supportsMirror) {
$('.fldMirrorMode', elem).show();
} else {
$('.fldMirrorMode', elem).hide();
$('.chkEnableMirrorMode', elem).checked(false).trigger('change').checkboxradio('refresh');
}
}).each(function () {
if (this.checked) {
$(this).trigger('change');
}
}).on('change', function () {
var playerName = this.getAttribute('data-playername');
var targetId = this.getAttribute('data-targetid');
var targetName = this.getAttribute('data-targetname');
var playableMediaTypes = this.getAttribute('data-mediatypes').split(',');
var supportedCommands = this.getAttribute('data-commands').split(',');
MediaController.setActivePlayer(playerName, {
id: targetId,
name: targetName,
playableMediaTypes: playableMediaTypes
playableMediaTypes: playableMediaTypes,
supportedCommands: supportedCommands
});
});
@ -335,4 +456,21 @@
});
});
$(document).on('pagebeforeshow', ".page", function () {
var page = this;
currentDisplayInfo = null;
}).on('displayingitem', ".libraryPage", function (e, info) {
var page = this;
currentDisplayInfo = info;
if (enableMirrorMode) {
mirrorItem(info);
}
});
})(jQuery, window);

View file

@ -23,8 +23,16 @@
var idleState = true;
var remoteFullscreen = false;
var muteButton = null;
var unmuteButton = null;
var volumeSlider = null;
var positionSlider;
var isPositionSliderActive;
var currentTimeElement;
self.initVideoPlayer = function () {
video = playVideo(item, mediaSource, startPosition, user);
return video;
};
@ -66,7 +74,7 @@
self.resetEnhancements = function () {
$("#mediaPlayer").hide();
$('#videoPlayer').removeClass('fullscreenVideo');
$("#videoControls").removeClass("inactive")
$("#videoControls").removeClass("inactive");
$("video").remove();
$("html").css("cursor", "default");
$(".ui-loader").hide();
@ -155,7 +163,38 @@
}
});
function onPositionSliderChange() {
isPositionSliderActive = false;
var newPercent = parseInt(this.value);
var newPositionTicks = (newPercent / 100) * currentMediaSource.RunTimeTicks;
self.changeStream(Math.floor(newPositionTicks));
}
$(function () {
var parent = $("#mediaPlayer");
muteButton = $('.muteButton', parent);
unmuteButton = $('.unmuteButton', parent);
currentTimeElement = $('.currentTime', parent);
positionSlider = $(".positionSlider", parent).on('slidestart', function (e) {
isPositionSliderActive = true;
}).on('slidestop', onPositionSliderChange);
volumeSlider = $('.volumeSlider', parent).on('slidestop', function () {
var vol = this.value;
updateVolumeButtons(vol);
self.setVolume(vol * 100);
});
$('#video-chaptersFlyout').on('click', '.mediaFlyoutOption', function () {
var ticks = parseInt(this.getAttribute('data-positionticks'));
@ -264,6 +303,17 @@
}, 4000);
}
function updateVolumeButtons(vol) {
if (vol) {
muteButton.show();
unmuteButton.hide();
} else {
muteButton.hide();
unmuteButton.show();
}
}
function requestFullScreen(element) {
// Supports most browsers and their versions.
@ -649,7 +699,7 @@
}
// Just use the first audio stream
return audioStreams[0].Index;
return audioStreams.length ? audioStreams[0].Index : null;
}
function getVideoQualityOptions(mediaStreams) {
@ -729,7 +779,7 @@
return options;
}
function playVideo(item, mediaSource, startPosition, user) {
var mediaStreams = mediaSource.MediaStreams || [];
@ -771,7 +821,10 @@
videoBitrate: mp4Quality.videoBitrate,
audioBitrate: mp4Quality.audioBitrate,
VideoCodec: mp4Quality.videoCodec,
AudioCodec: mp4Quality.audioCodec
AudioCodec: mp4Quality.audioCodec,
// None of the browsers seem to like this
EnableAutoStreamCopy: false
})) + seekParam;
@ -781,7 +834,8 @@
AudioCodec: 'Vorbis',
maxWidth: webmQuality.maxWidth,
videoBitrate: webmQuality.videoBitrate,
audioBitrate: webmQuality.audioBitrate
audioBitrate: webmQuality.audioBitrate,
EnableAutoStreamCopy: false
})) + seekParam;
@ -808,9 +862,13 @@
// Can't autoplay in these browsers so we need to use the full controls
if (requiresControls) {
html += '<video class="itemVideo" id="itemVideo" autoplay controls preload="none">';
html += '<video class="itemVideo" id="itemVideo" preload="none" autoplay controls>';
} else {
html += '<video class="itemVideo" id="itemVideo" autoplay preload="none">';
// Chrome 35 won't play with preload none
html += '<video class="itemVideo" id="itemVideo" preload="metadata" autoplay>';
}
if (!isStatic) {
@ -837,7 +895,6 @@
$('#video-stopButton', videoControls).show();
$('#video-playButton', videoControls).hide();
$('#video-pauseButton', videoControls).show();
$('#video-playlistButton', videoControls).hide();
$('#video-previousTrackButton', videoControls).hide();
$('#video-nextTrackButton', videoControls).hide();
var videoElement = $('#videoElement', mediaPlayer).prepend(html);
@ -872,44 +929,26 @@
$('#video-fullscreenButton', videoControls).show();
}
var videoElement = $("video", videoElement);
var video = $("video", videoElement);
initialVolume = localStorage.getItem("volume") || 0.5;
initialVolume = self.getSavedVolume();
videoElement.each(function () {
video.each(function () {
this.volume = initialVolume;
});
self.volumeSlider.val(initialVolume).slider('refresh');
self.updateVolumeButtons(initialVolume);
volumeSlider.val(initialVolume).slider('refresh');
updateVolumeButtons(initialVolume);
videoElement.on("volumechange", function (e) {
var muted = this.muted;
video.on("volumechange", function (e) {
var vol = this.volume;
if (!muted && this.volume > 0) {
localStorage.setItem("volume", vol);
}
updateVolumeButtons(vol);
this.muted = this.volume == 0;
}).one("playing", function () {
self.updateVolumeButtons(vol);
}).on("play.once", function () {
videoElement.off("play.once");
}).on("playing.once", function () {
self.updateCanClientSeek(this);
videoElement.off("playing.once");
ApiClient.reportPlaybackStart(Dashboard.getCurrentUserId(), item.Id, mediaSource.Id, true, item.MediaType);
self.startProgressInterval(item.Id, mediaSource.Id);
self.onPlaybackStart(this, item, mediaSource);
}).on("pause", function (e) {
@ -939,9 +978,9 @@
}).on("timeupdate", function () {
if (!self.isPositionSliderActive) {
if (!isPositionSliderActive) {
self.setCurrentTime(self.getCurrentTicks(this), item, true);
self.setCurrentTime(self.getCurrentTicks(this), positionSlider, currentTimeElement);
}
}).on("error", function () {
@ -995,8 +1034,13 @@
$(".ui-loader").hide();
$("html").css("cursor", "default");
}).on("ended.playbackstopped", self.onPlaybackStopped)
.on('ended.playnext', self.playNextAfterEnded);
}).on("ended.playbackstopped", function () {
currentTimeElement.empty();
self.onPlaybackStopped.call(this);
}).on('ended.playnext', self.playNextAfterEnded);
// Stop playback on browser back button nav
$(window).on("popstate", function () {
@ -1037,7 +1081,7 @@
currentItem = item;
currentMediaSource = mediaSource;
return videoElement[0];
return video[0];
}
};
})();

View file

@ -13,12 +13,6 @@
var currentPlaylistIndex = 0;
self.currentDurationTicks = null;
self.currentTimeElement = null;
self.unmuteButton = null;
self.muteButton = null;
self.positionSlider = null;
self.isPositionSliderActive = null;
self.volumeSlider = null;
self.startTimeTicksOffset = null;
self.playlist = [];
@ -34,7 +28,8 @@
id: ApiClient.deviceId(),
playerName: self.name,
playableMediaTypes: ['Audio', 'Video'],
isLocalPlayer: true
isLocalPlayer: true,
supportedCommands: Dashboard.getSupportedRemoteCommands()
}];
return targets;
@ -45,22 +40,11 @@
canClientSeek = duration && !isNaN(duration) && duration != Number.POSITIVE_INFINITY && duration != Number.NEGATIVE_INFINITY;
};
self.updateVolumeButtons = function (vol) {
if (vol) {
self.muteButton.show().prop("disabled", false);
self.unmuteButton.hide().prop("disabled", true);
} else {
self.muteButton.hide().prop("disabled", true);
self.unmuteButton.show().prop("disabled", false);
}
};
self.getCurrentTicks = function (mediaElement) {
return Math.floor(10000000 * (mediaElement || currentMediaElement).currentTime) + self.startTimeTicksOffset;
};
self.clearPauseStop = function() {
self.clearPauseStop = function () {
if (self.pauseStop) {
console.log('clearing pause stop timer');
@ -69,31 +53,6 @@
}
};
self.onPlaybackStopped = function () {
self.clearPauseStop();
$(this).off('ended.playbackstopped');
self.currentTimeElement.empty();
var endTime = this.currentTime;
clearProgressInterval();
var position = Math.floor(10000000 * endTime) + self.startTimeTicksOffset;
ApiClient.reportPlaybackStopped(Dashboard.getCurrentUserId(), currentItem.Id, currentMediaSource.Id, position);
if (currentItem.MediaType == "Video") {
ApiClient.stopActiveEncodings();
if (self.isFullScreen()) {
self.exitFullScreen();
}
self.resetEnhancements();
}
};
self.playNextAfterEnded = function () {
$(this).off('ended.playnext');
@ -148,11 +107,13 @@
var currentSrc = element.currentSrc;
if (params.AudioStreamIndex != null) {
currentSrc = replaceQueryString(currentSrc, 'AudioStreamIndex', params.AudioStreamIndex);
}
if (params.SubtitleStreamIndex != null) {
currentSrc = replaceQueryString(currentSrc, 'SubtitleStreamIndex', (params.SubtitleStreamIndex == -1 ? '' : params.SubtitleStreamIndex));
if (currentItem.MediaType == "Video") {
if (params.AudioStreamIndex != null) {
currentSrc = replaceQueryString(currentSrc, 'AudioStreamIndex', params.AudioStreamIndex);
}
if (params.SubtitleStreamIndex != null) {
currentSrc = replaceQueryString(currentSrc, 'SubtitleStreamIndex', (params.SubtitleStreamIndex == -1 ? '' : params.SubtitleStreamIndex));
}
}
var maxWidth = params.MaxWidth || getParameterByName('MaxWidth', currentSrc);
@ -164,25 +125,32 @@
var transcodingExtension = self.getTranscodingExtension();
var finalParams = self.getFinalVideoParams(currentMediaSource, maxWidth, bitrate, audioStreamIndex, subtitleStreamIndex, transcodingExtension);
currentSrc = replaceQueryString(currentSrc, 'MaxWidth', finalParams.maxWidth);
currentSrc = replaceQueryString(currentSrc, 'VideoBitrate', finalParams.videoBitrate);
currentSrc = replaceQueryString(currentSrc, 'AudioBitrate', finalParams.audioBitrate);
currentSrc = replaceQueryString(currentSrc, 'Static', finalParams.isStatic);
var isStatic;
if (currentItem.MediaType == "Video") {
currentSrc = replaceQueryString(currentSrc, 'AudioCodec', finalParams.audioCodec);
currentSrc = replaceQueryString(currentSrc, 'VideoCodec', finalParams.videoCodec);
var finalParams = self.getFinalVideoParams(currentMediaSource, maxWidth, bitrate, audioStreamIndex, subtitleStreamIndex, transcodingExtension);
currentSrc = replaceQueryString(currentSrc, 'profile', finalParams.profile || '');
currentSrc = replaceQueryString(currentSrc, 'level', finalParams.level || '');
currentSrc = replaceQueryString(currentSrc, 'MaxWidth', finalParams.maxWidth);
currentSrc = replaceQueryString(currentSrc, 'VideoBitrate', finalParams.videoBitrate);
if (finalParams.isStatic) {
currentSrc = currentSrc.replace('.webm', '.mp4').replace('.m3u8', '.mp4');
} else {
currentSrc = currentSrc.replace('.mp4', transcodingExtension).replace('.m4v', transcodingExtension);
currentSrc = replaceQueryString(currentSrc, 'VideoCodec', finalParams.videoCodec);
currentSrc = replaceQueryString(currentSrc, 'profile', finalParams.profile || '');
currentSrc = replaceQueryString(currentSrc, 'level', finalParams.level || '');
if (finalParams.isStatic) {
currentSrc = currentSrc.replace('.webm', '.mp4').replace('.m3u8', '.mp4');
} else {
currentSrc = currentSrc.replace('.mp4', transcodingExtension).replace('.m4v', transcodingExtension);
}
currentSrc = replaceQueryString(currentSrc, 'AudioBitrate', finalParams.audioBitrate);
currentSrc = replaceQueryString(currentSrc, 'Static', finalParams.isStatic);
currentSrc = replaceQueryString(currentSrc, 'AudioCodec', finalParams.audioCodec);
isStatic = finalParams.isStatic;
}
if (finalParams.isStatic || !ticks) {
if (isStatic || !ticks) {
currentSrc = replaceQueryString(currentSrc, 'starttimeticks', '');
} else {
currentSrc = replaceQueryString(currentSrc, 'starttimeticks', ticks);
@ -190,27 +158,33 @@
clearProgressInterval();
$(element).off('ended.playbackstopped').off('ended.playnext').on("play.onceafterseek", function () {
$(element).off('ended.playbackstopped').off('ended.playnext').one("play", function () {
self.updateCanClientSeek(this);
$(this).off('play.onceafterseek').on('ended.playbackstopped', self.onPlaybackStopped).on('ended.playnext', self.playNextAfterEnded);
$(this).on('ended.playbackstopped', self.onPlaybackStopped).on('ended.playnext', self.playNextAfterEnded);
self.startProgressInterval(currentItem.Id, currentMediaSource.Id);
sendProgressUpdate(currentItem.Id, currentMediaSource.Id);
});
ApiClient.stopActiveEncodings().done(function () {
if (currentItem.MediaType == "Video") {
ApiClient.stopActiveEncodings().done(function () {
self.startTimeTicksOffset = ticks;
element.src = currentSrc;
});
} else {
self.startTimeTicksOffset = ticks;
element.src = currentSrc;
});
element.play();
}
}
};
self.setCurrentTime = function (ticks, item, updateSlider) {
self.setCurrentTime = function (ticks, positionSlider, currentTimeElement) {
// Convert to ticks
ticks = Math.floor(ticks);
@ -221,17 +195,28 @@
timeText += " / " + Dashboard.getDisplayTime(self.currentDurationTicks);
if (updateSlider) {
if (positionSlider) {
var percent = ticks / self.currentDurationTicks;
percent *= 100;
self.positionSlider.val(percent).slider('enable').slider('refresh');
positionSlider.val(percent).slider('enable').slider('refresh');
}
} else {
self.positionSlider.slider('disable').slider('refresh');
if (positionSlider) {
positionSlider.slider('disable').slider('refresh');
}
}
self.currentTimeElement.html(timeText);
if (currentTimeElement) {
currentTimeElement.html(timeText);
}
var state = self.getPlayerStateInternal(currentMediaElement, currentItem, currentMediaSource);
$(self).trigger('positionchange', [state]);
};
self.canPlayVideoDirect = function (mediaSource, videoStream, audioStream, subtitleStream, maxWidth, bitrate) {
@ -459,8 +444,6 @@
var mediaElement;
var mediaControls = $('#nowPlayingBar');
if (item.MediaType === "Video") {
currentItem = item;
@ -470,15 +453,12 @@
mediaElement = self.initVideoPlayer();
self.currentDurationTicks = currentMediaSource.RunTimeTicks;
mediaControls = $("#videoControls");
} else if (item.MediaType === "Audio") {
currentItem = item;
currentMediaSource = getOptimalMediaSource(item.MediaType, item.MediaSources);
mediaElement = playAudio(item, currentMediaSource, startPosition);
mediaControls.show();
self.currentDurationTicks = currentMediaSource.RunTimeTicks;
@ -488,36 +468,50 @@
currentMediaElement = mediaElement;
//display image and title
var imageTags = item.ImageTags || {};
var html = '';
if (item.MediaType === "Video") {
self.updateNowPlayingInfo(item);
}
};
self.updateNowPlayingInfo = function (item) {
if (!item) {
throw new Error('item cannot be null');
}
var mediaControls = $("#videoControls");
var state = self.getPlayerStateInternal(currentMediaElement, item, currentMediaSource);
var url = "";
if (imageTags.Primary) {
if (state.primaryImageTag) {
url = ApiClient.getImageUrl(item.Id, {
url = ApiClient.getImageUrl(state.primaryImageItemId, {
type: "Primary",
height: 80,
tag: item.ImageTags.Primary
tag: state.primaryImageTag
});
}
else if (item.BackdropImageTags && item.BackdropImageTags.length) {
else if (state.backdropImageTag) {
url = ApiClient.getImageUrl(item.Id, {
url = ApiClient.getImageUrl(state.backdropItemId, {
type: "Backdrop",
height: 80,
tag: item.BackdropImageTags[0]
tag: state.backdropImageTag,
index: 0
});
} else if (imageTags.Thumb) {
url = ApiClient.getImageUrl(item.Id, {
} else if (state.thumbImageTag) {
url = ApiClient.getImageUrl(state.thumbImageItemId, {
type: "Thumb",
height: 80,
tag: item.ImageTags.Thumb
tag: state.thumbImageTag
});
}
else if (item.Type == "TvChannel" || item.Type == "Recording") {
url = "css/images/items/detail/tv.png";
}
@ -528,40 +522,60 @@
url = "css/images/items/detail/video.png";
}
var name = item.Name;
var seriesName = '';
var nowPlayingTextElement = $('.nowPlayingText', mediaControls);
var nameHtml = self.getNowPlayingNameHtml(state);
// Channel number
if (item.Number) {
name = item.Number + ' ' + name;
}
if (item.IndexNumber != null) {
name = item.IndexNumber + " - " + name;
}
if (item.ParentIndexNumber != null) {
name = item.ParentIndexNumber + "." + name;
}
if (item.SeriesName || item.Album || item.ProductionYear) {
seriesName = item.SeriesName || item.Album || item.ProductionYear;
}
if (item.CurrentProgram) {
seriesName = item.CurrentProgram.Name;
if (nameHtml.indexOf('<br/>') != -1) {
nowPlayingTextElement.addClass('nowPlayingDoubleText');
} else {
nowPlayingTextElement.removeClass('nowPlayingDoubleText');
}
var href = LibraryBrowser.getHref(item.CurrentProgram || item);
$('.nowPlayingImage', mediaControls).html('<img src="' + url + '" />');
nowPlayingTextElement.html(nameHtml);
};
var nowPlayingText = (name ? name + "\n" : "") + (seriesName || "---");
if (item.SeriesName || item.Album || item.CurrentProgram) {
nowPlayingText = (seriesName ? seriesName : "") + "\n" + (name || "---");
self.getNowPlayingNameHtml = function (playerState) {
var topText = playerState.itemName;
if (playerState.mediaType == 'Video') {
if (playerState.indexNumber != null) {
topText = playerState.indexNumber + " - " + topText;
}
if (playerState.parentIndexNumber != null) {
topText = playerState.parentIndexNumber + "." + topText;
}
}
// Fix for apostrophes and quotes
var htmlTitle = trimTitle(nowPlayingText).replace(/'/g, '&apos;').replace(/"/g, '&quot;');
html += "<div><a href='" + href + "'><img class='nowPlayingBarImage' alt='" + htmlTitle +
"' title='" + htmlTitle + "' src='" + url + "' style='height:40px;display:inline-block;' /></a></div>";
html += "<div class='nowPlayingText' title='" + htmlTitle + "'>" + titleHtml(nowPlayingText) + "</div>";
var bottomText = '';
$('.nowPlayingMediaInfo', mediaControls).html(html);
if (playerState.artists && playerState.artists.length) {
bottomText = topText;
topText = playerState.artists[0];
}
else if (playerState.seriesName || playerState.album) {
bottomText = topText;
topText = playerState.seriesName || playerState.album;
}
else if (playerState.productionYear) {
bottomText = playerState.productionYear;
}
return bottomText ? topText + '<br/>' + bottomText : topText;
};
self.displayContent = function (options) {
// Handle it the same as a remote control command
Dashboard.onBrowseCommand({
ItemName: options.itemName,
ItemType: options.itemType,
ItemId: options.itemId,
Context: options.context
});
};
self.getItemsForPlayback = function (query) {
@ -712,6 +726,7 @@
};
self.pause = function () {
currentMediaElement.pause();
};
@ -722,56 +737,69 @@
self.seek = function (position) {
self.changeStream(position);
};
self.mute = function () {
if (currentMediaElement) {
currentMediaElement.volume = 0;
currentMediaElement.muted = true;
self.volumeSlider.val(0).slider('refresh');
}
self.setVolume(0);
};
self.unmute = function () {
self.unMute = function () {
if (currentMediaElement) {
var volume = localStorage.getItem("volume") || self.volumeSlider.val();
currentMediaElement.volume = volume;
currentMediaElement.muted = false;
self.volumeSlider.val(volume).slider('refresh');
}
self.setVolume(self.getSavedVolume() * 100);
};
self.toggleMute = function () {
if (currentMediaElement) {
var volume = localStorage.getItem("volume") || self.volumeSlider.val();
currentMediaElement.volume = currentMediaElement.volume ? 0 : volume;
currentMediaElement.muted = currentMediaElement.volume == 0;
self.volumeSlider.val(volume).slider('refresh');
if (currentMediaElement.volume) {
self.mute();
} else {
self.unMute();
}
}
};
self.volumeDown = function () {
if (currentMediaElement) {
currentMediaElement.volume = Math.max(currentMediaElement.volume - .02, 0);
localStorage.setItem("volume", currentMediaElement.volume);
self.volumeSlider.val(currentMediaElement.volume).slider('refresh');
self.setVolume(Math.max(currentMediaElement.volume - .02, 0) * 100);
}
};
self.volumeUp = function () {
if (currentMediaElement) {
currentMediaElement.volume = Math.min(currentMediaElement.volume + .02, 1);
localStorage.setItem("volume", currentMediaElement.volume);
self.volumeSlider.val(currentMediaElement.volume).slider('refresh');
self.setVolume(Math.min(currentMediaElement.volume + .02, 1) * 100);
}
};
// Sets volume using a 0-100 scale
self.setVolume = function (val) {
if (currentMediaElement) {
currentMediaElement.volume = val / 100;
self.onVolumeChanged(currentMediaElement);
self.saveVolume();
}
};
self.saveVolume = function (val) {
if (val) {
localStorage.setItem("volume", val);
}
};
self.getSavedVolume = function () {
return localStorage.getItem("volume") || 0.5;
};
self.shuffle = function (id) {
var userId = Dashboard.getCurrentUserId();
@ -880,77 +908,193 @@
elem.pause();
var isVideo = currentItem.MediaType == "Video";
$(elem).off("ended.playnext").on("ended", function () {
$(this).remove();
$(this).off();
if (this.tagName.toLowerCase() != 'audio') {
$(this).remove();
}
elem.src = "";
currentMediaElement = null;
currentItem = null;
currentMediaSource = null;
}).trigger("ended");
if (currentItem.MediaType == "Video") {
if (isVideo) {
if (self.isFullScreen()) {
self.exitFullScreen();
}
self.resetEnhancements();
} else {
$('#nowPlayingBar').hide();
}
};
self.isPlaying = function () {
return currentMediaElement;
return currentMediaElement != null;
};
self.bindPositionSlider = function () {
self.positionSlider.on('slidestart', function (e) {
self.getPlayerState = function () {
self.isPositionSliderActive = true;
var deferred = $.Deferred();
}).on('slidestop', onPositionSliderChange);
var result = self.getPlayerStateInternal(currentMediaElement, currentItem, currentMediaSource);
deferred.resolveWith(null, [result]);
return deferred.promise();
};
self.bindVolumeSlider = function () {
self.volumeSlider.on('slidestop', function () {
self.getPlayerStateInternal = function (playerElement, item, mediaSource) {
var vol = this.value;
var state = {};
self.updateVolumeButtons(vol);
currentMediaElement.volume = vol;
});
if (playerElement) {
state.volumeLevel = playerElement.volume * 100;
state.isMuted = playerElement.volume == 0;
state.isPaused = playerElement.paused;
state.positionTicks = self.getCurrentTicks(playerElement);
}
if (mediaSource) {
state.mediaSourceId = mediaSource.Id;
state.runtimeTicks = mediaSource.RunTimeTicks;
state.canSeek = mediaSource.RunTimeTicks && mediaSource.RunTimeTicks > 0;
}
if (item) {
state.itemId = item.Id;
state.mediaType = item.MediaType;
state.itemType = item.Type;
state.indexNumber = item.IndexNumber;
state.indexNumberEnd = item.IndexNumberEnd;
state.parentIndexNumber = item.ParentIndexNumber;
state.productionYear = item.ProductionYear;
state.premiereDate = item.PremiereDate;
state.seriesName = item.SeriesName;
state.album = item.Album;
state.itemName = item.Name;
state.artists = item.Artists;
var imageTags = item.ImageTags || {};
if (imageTags.Primary) {
state.primaryImageItemId = item.Id;
state.primaryImageTag = imageTags.Primary;
}
else if (item.AlbumPrimaryImageTag) {
state.primaryImageItemId = item.AlbumId;
state.primaryImageTag = item.AlbumPrimaryImageTag;
}
else if (item.SeriesPrimaryImageTag) {
state.primaryImageItemId = item.SeriesId;
state.primaryImageTag = item.SeriesPrimaryImageTag;
}
if (item.BackdropImageTags && item.BackdropImageTags.length) {
state.backdropItemId = item.Id;
state.backdropImageTag = item.BackdropImageTags[0];
}
if (imageTags.Thumb) {
state.thumbItemId = item.Id;
state.thumbImageTag = imageTags.Thumb;
}
}
return state;
};
self.beginPlayerUpdates = function () {
// Nothing to setup here
};
self.endPlayerUpdates = function () {
// Nothing to setup here
};
self.onPlaybackStart = function (playerElement, item, mediaSource) {
self.updateCanClientSeek(playerElement);
ApiClient.reportPlaybackStart(Dashboard.getCurrentUserId(), item.Id, mediaSource.Id, true, item.MediaType);
self.startProgressInterval(item.Id, mediaSource.Id);
var state = self.getPlayerStateInternal(playerElement, item, mediaSource);
$(self).trigger('playbackstart', [state]);
};
self.onVolumeChanged = function (playerElement) {
self.saveVolume(playerElement.volume);
var state = self.getPlayerStateInternal(playerElement, currentItem, currentMediaSource);
$(self).trigger('volumechange', [state]);
};
self.onPlaybackStopped = function () {
self.clearPauseStop();
var playerElement = this;
$(playerElement).off('ended.playbackstopped');
var endTime = playerElement.currentTime;
clearProgressInterval();
var position = Math.floor(10000000 * endTime) + self.startTimeTicksOffset;
var item = currentItem;
var mediaSource = currentMediaSource;
ApiClient.reportPlaybackStopped(Dashboard.getCurrentUserId(), item.Id, mediaSource.Id, position);
if (item.MediaType == "Video") {
ApiClient.stopActiveEncodings();
if (self.isFullScreen()) {
self.exitFullScreen();
}
self.resetEnhancements();
}
var state = self.getPlayerStateInternal(playerElement, item, mediaSource);
$(self).trigger('playbackstop', [state]);
};
self.onPlaystateChange = function (playerElement) {
var state = self.getPlayerStateInternal(playerElement, currentItem, currentMediaSource);
$(self).trigger('playstatechange', [state]);
};
$(window).on("beforeunload popstate", function () {
var item = currentItem;
var media = currentMediaElement;
// Try to report playback stopped before the browser closes
if (item && media && currentProgressInterval) {
if (currentItem && currentMediaElement && currentProgressInterval) {
var endTime = currentMediaElement.currentTime;
var position = Math.floor(10000000 * endTime) + self.startTimeTicksOffset;
ApiClient.reportPlaybackStopped(Dashboard.getCurrentUserId(), currentItem.Id, currentMediaSource.Id, position);
self.onPlaybackStopped.call(currentMediaElement);
}
});
$(function () {
initPlayer();
});
function initPlayer() {
self.muteButton = $('.muteButton');
self.unmuteButton = $('.unmuteButton');
self.currentTimeElement = $('.currentTime');
self.volumeSlider = $('.volumeSlider');
self.positionSlider = $(".positionSlider");
self.bindVolumeSlider();
self.bindPositionSlider();
}
function replaceQueryString(url, param, value) {
var re = new RegExp("([?|&])" + param + "=.*?(&|$)", "i");
if (url.match(re))
@ -977,17 +1121,42 @@
return testableVideoElement.canPlayType('video/webm').replace(/no/, '');
}
function onPositionSliderChange() {
self.canAutoPlayAudio = function () {
self.isPositionSliderActive = false;
if ($.browser.android || ($.browser.webkit && !$.browser.chrome)) {
return false;
}
var newPercent = parseInt(this.value);
return true;
};
var newPositionTicks = (newPercent / 100) * currentMediaSource.RunTimeTicks;
function getAudioElement() {
self.changeStream(Math.floor(newPositionTicks));
var elem = $('.mediaPlayerAudio');
if (elem.length) {
return elem;
}
var html = '';
var requiresControls = !self.canAutoPlayAudio();
if (requiresControls) {
html += '<div class="mediaPlayerAudioContainer"><div class="mediaPlayerAudioContainerInner">';;
} else {
html += '<div class="mediaPlayerAudioContainer" style="display:none;"><div class="mediaPlayerAudioContainerInner">';;
}
html += '<audio class="mediaPlayerAudio" controls>';
html += '</audio></div></div>';
$(document.body).append(html);
return $('.mediaPlayerAudio');
}
var supportsAac = document.createElement('audio').canPlayType('audio/aac').replace(/no/, '');
function playAudio(item, mediaSource, startPositionTicks) {
startPositionTicks = startPositionTicks || 0;
@ -999,130 +1168,70 @@
mediaSourceId: mediaSource.Id
};
var mp3Url = ApiClient.getUrl('Audio/' + item.Id + '/stream.mp3', $.extend({}, baseParams, {
audioCodec: 'mp3'
}));
var aacUrl = ApiClient.getUrl('Audio/' + item.Id + '/stream.aac', $.extend({}, baseParams, {
audioCodec: 'aac'
}));
var webmUrl = ApiClient.getUrl('Audio/' + item.Id + '/stream.webm', $.extend({}, baseParams, {
audioCodec: 'Vorbis'
}));
var mediaStreams = mediaSource.MediaStreams;
var sourceContainer = (mediaSource.Container || '').toLowerCase();
var isStatic = false;
var seekParam = isStatic && startPositionTicks ? '#t=' + (startPositionTicks / 10000000) : '';
for (var i = 0, length = mediaStreams.length; i < length; i++) {
if (sourceContainer == 'mp3' ||
(sourceContainer == 'aac' && supportsAac)) {
var stream = mediaStreams[i];
for (var i = 0, length = mediaSource.MediaStreams.length; i < length; i++) {
if (stream.Type == "Audio") {
var stream = mediaSource.MediaStreams[i];
var container = (mediaSource.Container || '').toLowerCase();
// Stream statically when possible
if (container == 'aac' && stream.BitRate <= 256000) {
aacUrl += "&static=true" + seekParam;
isStatic = true;
if (stream.Type == "Audio") {
// Stream statically when possible
if (stream.BitRate <= 256000) {
isStatic = true;
}
break;
}
else if (container == 'mp3' && stream.BitRate <= 256000) {
mp3Url += "&static=true" + seekParam;
isStatic = true;
}
break;
}
}
var outputContainer = isStatic ? sourceContainer : 'mp3';
var audioUrl = ApiClient.getUrl('Audio/' + item.Id + '/stream.' + outputContainer, $.extend({}, baseParams, {
audioCodec: outputContainer
}));
if (isStatic) {
var seekParam = startPositionTicks ? '#t=' + (startPositionTicks / 10000000) : '';
audioUrl += "&static=true" + seekParam;
}
self.startTimeTicksOffset = isStatic ? 0 : startPositionTicks;
var html = '';
var initialVolume = self.getSavedVolume();
var requiresControls = $.browser.android || ($.browser.webkit && !$.browser.chrome);
return getAudioElement().each(function () {
// Can't autoplay in these browsers so we need to use the full controls
if (requiresControls) {
html += '<audio preload="auto" autoplay controls>';
} else {
html += '<audio preload="auto" style="display:none;" autoplay>';
}
html += '<source type="audio/mpeg" src="' + mp3Url + '" />';
html += '<source type="audio/aac" src="' + aacUrl + '" />';
html += '<source type="audio/webm" src="' + webmUrl + '" />';
html += '</audio>';
var nowPlayingBar = $('#nowPlayingBar').show();
//show stop button
$('#stopButton', nowPlayingBar).show();
$('#playButton', nowPlayingBar).hide();
$('#pauseButton', nowPlayingBar).show();
$('#fullscreenButton', nowPlayingBar).hide();
$('#previousTrackButton', nowPlayingBar).show();
$('#nextTrackButton', nowPlayingBar).show();
$('#playlistButton', nowPlayingBar).show();
$('#qualityButton', nowPlayingBar).hide();
$('#audioTracksButton', nowPlayingBar).hide();
$('#subtitleButton', nowPlayingBar).hide();
$('#chaptersButton', nowPlayingBar).hide();
var mediaElement = $('#mediaElement', nowPlayingBar).html(html);
var audioElement = $("audio", mediaElement);
var initialVolume = localStorage.getItem("volume") || 0.5;
audioElement.each(function () {
this.src = audioUrl;
this.volume = initialVolume;
});
this.play();
self.volumeSlider.val(initialVolume).slider('refresh');
self.updateVolumeButtons(initialVolume);
}).on("volumechange", function () {
audioElement.on("volumechange", function () {
self.onVolumeChanged(this);
var vol = this.volume;
}).one("playing", function () {
localStorage.setItem("volume", vol);
$('.mediaPlayerAudioContainer').hide();
self.updateVolumeButtons(vol);
}).on("play.once", function () {
if (!requiresControls) {
audioElement.hide();
}
self.updateCanClientSeek(this);
audioElement.off("play.once");
ApiClient.reportPlaybackStart(Dashboard.getCurrentUserId(), item.Id, mediaSource.Id, true, item.MediaType);
self.startProgressInterval(item.Id, mediaSource.Id);
self.onPlaybackStart(this, item, mediaSource);
}).on("pause", function () {
$('#playButton', nowPlayingBar).show();
$('#pauseButton', nowPlayingBar).hide();
self.onPlaystateChange(this);
}).on("playing", function () {
$('#playButton', nowPlayingBar).hide();
$('#pauseButton', nowPlayingBar).show();
self.onPlaystateChange(this);
}).on("timeupdate", function () {
if (!self.isPositionSliderActive) {
self.setCurrentTime(self.getCurrentTicks(this));
self.setCurrentTime(self.getCurrentTicks(this), item, true);
}
}).on("ended.playbackstopped", self.onPlaybackStopped).on('ended.playnext', self.playNextAfterEnded);
return audioElement[0];
}).on("ended.playbackstopped", self.onPlaybackStopped).on('ended.playnext', self.playNextAfterEnded)[0];
};
function canPlayAudioStreamDirect(audioStream) {
@ -1146,27 +1255,7 @@
}
return true;
};
function trunc(string, len) {
if (string.length > 0 && string.length < len) return string;
var trimmed = $.trim(string).substring(0, len).split(" ").slice(0, -1).join(" ");
if (trimmed) {
trimmed += "...";
} else {
trimmed = "---"
}
return trimmed;
};
function trimTitle(title) {
return title.replace("\n---", "");
};
function titleHtml(title) {
var titles = title.split("\n");
return (trunc(titles[0], 30) + "<br />" + trunc(titles[1], 30)).replace("---", "&nbsp;");
};
}
var getItemFields = "MediaSources,Chapters";

View file

@ -33,7 +33,8 @@
shape: "portrait",
context: 'movies',
showTitle: true,
centerText: true
centerText: true,
lazy: true
});
html += LibraryBrowser.getPagingHtml(query, result.TotalRecordCount);

View file

@ -34,7 +34,8 @@
context: 'movies',
showTitle: true,
showItemCounts: true,
coverImage: true
coverImage: true,
lazy: true
});
html += LibraryBrowser.getPagingHtml(query, result.TotalRecordCount, false, [], false);

View file

@ -35,7 +35,8 @@
shape: "backdrop",
preferThumb: true,
context: 'movies',
selectionPanel: true
selectionPanel: true,
lazy: true
});
$('.itemsContainer', page).removeClass('timelineItemsContainer');
}
@ -45,7 +46,8 @@
items: result.Items,
shape: "banner",
preferBanner: true,
context: 'movies'
context: 'movies',
lazy: true
});
$('.itemsContainer', page).removeClass('timelineItemsContainer');
}
@ -56,7 +58,8 @@
context: 'movies',
showTitle: true,
centerText: true,
selectionPanel: true
selectionPanel: true,
lazy: true
});
$('.itemsContainer', page).removeClass('timelineItemsContainer');
}
@ -68,7 +71,8 @@
showTitle: true,
timeline: true,
centerText: true,
selectionPanel: true
selectionPanel: true,
lazy: true
});
$('.itemsContainer', page).addClass('timelineItemsContainer');
}

View file

@ -32,7 +32,8 @@
context: 'music',
showTitle: true,
coverImage: true,
centerText: true
centerText: true,
lazy: true
});
html += LibraryBrowser.getPagingHtml(query, result.TotalRecordCount);

View file

@ -34,7 +34,8 @@
shape: "square",
context: 'music',
showTitle: true,
showParentTitle: true
showParentTitle: true,
lazy: true
});
$('.itemsContainer', page).removeClass('timelineItemsContainer');
}
@ -45,7 +46,8 @@
context: 'music',
showTitle: true,
showParentTitle: true,
timeline: true
timeline: true,
lazy: true
});
$('.itemsContainer', page).addClass('timelineItemsContainer');
}

View file

@ -31,7 +31,8 @@
context: 'music',
showTitle: true,
coverImage: true,
centerText: true
centerText: true,
lazy: true
});
html += LibraryBrowser.getPagingHtml(query, result.TotalRecordCount);

View file

@ -32,7 +32,8 @@
preferThumb: true,
context: 'music',
showItemCounts: true,
centerText: true
centerText: true,
lazy: true
});
html += LibraryBrowser.getPagingHtml(query, result.TotalRecordCount);
@ -55,8 +56,8 @@
reloadItems(page);
});
LibraryBrowser.saveQueryValues('musicgenres', query);
LibraryBrowser.saveQueryValues('musicgenres', query);
Dashboard.hideLoadingMsg();
});
}

View file

@ -0,0 +1,396 @@
(function (window, document, $, setTimeout, clearTimeout) {
var currentPlayer;
var currentTimeElement;
var nowPlayingImageElement;
var nowPlayingTextElement;
var unmuteButton;
var muteButton;
var volumeSlider;
var isVolumeSliderActive;
var unpauseButton;
var pauseButton;
var positionSlider;
var isPositionSliderActive;
var lastPlayerState;
function getNowPlayingBarHtml() {
var html = '';
html += '<div id="nowPlayingBar" class="nowPlayingBar" style="display:none;">';
html += '<div style="display:inline-block;width:12px;"></div>';
html += '<a id="playlistButton" class="mediaButton playlistButton" href="playlist.html" data-role="button" data-icon="bullets" data-iconpos="notext" data-inline="true" title="Playlist">Playlist</a>';
html += '<button id="previousTrackButton" class="mediaButton previousTrackButton" title="Previous Track" type="button" data-icon="previous-track" data-iconpos="notext" data-inline="true">Previous Track</button>';
html += '<button id="playButton" class="mediaButton unpauseButton" title="Play" type="button" data-icon="play" data-iconpos="notext" data-inline="true">Play</button>';
html += '<button id="pauseButton" class="mediaButton pauseButton" title="Pause" type="button" data-icon="pause" data-iconpos="notext" data-inline="true">Pause</button>';
html += '<button id="stopButton" class="mediaButton stopButton" title="Stop" type="button" data-icon="stop" data-iconpos="notext" data-inline="true">Stop</button>';
html += '<button id="nextTrackButton" class="mediaButton nextTrackButton" title="Next Track" type="button" data-icon="next-track" data-iconpos="notext" data-inline="true">Next Track</button>';
html += '<div id="mediaElement"></div>';
html += '<div class="positionSliderContainer sliderContainer">';
html += '<input type="range" class="mediaSlider positionSlider slider" step=".001" min="0" max="100" value="0" style="display:none;" data-mini="true" data-theme="a" data-highlight="true" />';
html += '</div>';
html += '<div class="currentTime"></div>';
html += '<div class="nowPlayingImage"></div>';
html += '<div class="nowPlayingText"></div>';
html += '<button id="muteButton" class="mediaButton muteButton" title="Mute" type="button" data-icon="audio" data-iconpos="notext" data-inline="true">Mute</button>';
html += '<button id="unmuteButton" class="mediaButton unmuteButton" title="Unmute" type="button" data-icon="volume-off" data-iconpos="notext" data-inline="true">Unmute</button>';
html += '<div class="volumeSliderContainer sliderContainer">';
html += '<input type="range" class="mediaSlider volumeSlider slider" step=".05" min="0" max="100" value="0" style="display:none;" data-mini="true" data-theme="a" data-highlight="true" />';
html += '</div>';
html += '</div>';
return html;
}
function bindEvents(elem) {
currentTimeElement = $('.currentTime', elem);
nowPlayingImageElement = $('.nowPlayingImage', elem);
nowPlayingTextElement = $('.nowPlayingText', elem);
unmuteButton = $('.unmuteButton', elem).on('click', function () {
if (currentPlayer) {
currentPlayer.unMute();
}
});
muteButton = $('.muteButton', elem).on('click', function () {
if (currentPlayer) {
currentPlayer.mute();
}
});
$('.stopButton', elem).on('click', function () {
if (currentPlayer) {
currentPlayer.stop();
}
});
pauseButton = $('.pauseButton', elem).on('click', function () {
if (currentPlayer) {
currentPlayer.pause();
}
});
unpauseButton = $('.unpauseButton', elem).on('click', function () {
if (currentPlayer) {
currentPlayer.unpause();
}
});
$('.nextTrackButton', elem).on('click', function () {
if (currentPlayer) {
currentPlayer.nextTrack();
}
});
$('.previousTrackButton', elem).on('click', function () {
if (currentPlayer) {
currentPlayer.previousTrack();
}
});
volumeSlider = $('.volumeSlider', elem).on('slidestart', function () {
isVolumeSliderActive = true;
}).on('slidestop', function () {
isVolumeSliderActive = false;
if (currentPlayer) {
currentPlayer.setVolume(this.value);
}
});
positionSlider = $('.positionSlider', elem).on('slidestart', function () {
isPositionSliderActive = true;
}).on('slidestop', function () {
isPositionSliderActive = false;
if (currentPlayer && lastPlayerState) {
var newPercent = parseFloat(this.value);
var newPositionTicks = (newPercent / 100) * lastPlayerState.runtimeTicks;
currentPlayer.seek(Math.floor(newPositionTicks));
}
});
}
function getNowPlayingBar() {
var elem = $('.nowPlayingBar');
if (elem.length) {
return elem;
}
elem = $(getNowPlayingBarHtml()).insertBefore('#footerNotifications').trigger('create');
bindEvents(elem);
return elem;
}
function updatePlayerState(state) {
if (state.itemName) {
showNowPlayingBar();
} else {
hideNowPlayingBar();
return;
}
lastPlayerState = state;
if (!muteButton) {
getNowPlayingBar();
}
var playerInfo = MediaController.getPlayerInfo();
var supportedCommands = playerInfo.supportedCommands;
if (supportedCommands.indexOf('SetVolume') == -1) {
volumeSlider.prop('disabled', 'disabled');
} else {
volumeSlider.prop('disabled', '');
}
if (supportedCommands.indexOf('Mute') == -1) {
muteButton.prop('disabled', 'disabled');
} else {
muteButton.prop('disabled', '');
}
if (supportedCommands.indexOf('Unmute') == -1) {
unmuteButton.prop('disabled', 'disabled');
} else {
unmuteButton.prop('disabled', '');
}
if (state.isMuted) {
muteButton.hide();
unmuteButton.show();
} else {
muteButton.show();
unmuteButton.hide();
}
if (state.isPaused) {
pauseButton.hide();
unpauseButton.show();
} else {
pauseButton.show();
unpauseButton.hide();
}
if (!isVolumeSliderActive) {
volumeSlider.val(state.volumeLevel || 0);
}
volumeSlider.slider('refresh');
if (!isPositionSliderActive) {
if (state.canSeek) {
var pct = state.positionTicks / state.runtimeTicks;
pct *= 100;
positionSlider.val(pct).prop('disabled', '');
} else {
positionSlider.val(0).prop('disabled', 'disabled');
}
positionSlider.slider('refresh');
}
var timeText = Dashboard.getDisplayTime(state.positionTicks);
if (state.runtimeTicks) {
timeText += " / " + Dashboard.getDisplayTime(state.runtimeTicks);
}
currentTimeElement.html(timeText);
updateNowPlayingInfo(state);
}
var currentImgUrl;
function updateNowPlayingInfo(state) {
var nameHtml = MediaPlayer.getNowPlayingNameHtml(state);
if (nameHtml.indexOf('<br/>') != -1) {
nowPlayingTextElement.addClass('nowPlayingDoubleText');
} else {
nowPlayingTextElement.removeClass('nowPlayingDoubleText');
}
nowPlayingTextElement.html(nameHtml);
var url;
if (state.primaryImageTag) {
url = ApiClient.getImageUrl(state.primaryImageItemId, {
type: "Primary",
height: 80,
tag: state.primaryImageTag
});
}
else if (state.backdropImageTag) {
url = ApiClient.getImageUrl(state.backdropItemId, {
type: "Backdrop",
height: 80,
tag: state.backdropImageTag,
index: 0
});
} else if (state.thumbImageTag) {
url = ApiClient.getImageUrl(state.thumbImageItemId, {
type: "Thumb",
height: 80,
tag: state.thumbImageTag
});
}
else if (state.itemType == "TvChannel" || state.itemType == "Recording") {
url = "css/images/items/detail/tv.png";
}
else if (state.mediaType == "Audio") {
url = "css/images/items/detail/audio.png";
}
else {
url = "css/images/items/detail/video.png";
}
if (url == currentImgUrl) {
return;
}
currentImgUrl = url;
nowPlayingImageElement.html('<img src="' + url + '" />');
}
function onPlaybackStart(e, state) {
var player = this;
player.beginPlayerUpdates();
onStateChanged.call(player, e, state);
}
function showNowPlayingBar() {
var nowPlayingBar = getNowPlayingBar();
nowPlayingBar.show();
}
function hideNowPlayingBar() {
// Use a timeout to prevent the bar from hiding and showing quickly
// in the event of a stop->play command
getNowPlayingBar().hide();
}
function onPlaybackStopped(e, state) {
var player = this;
player.endPlayerUpdates();
hideNowPlayingBar();
}
function onStateChanged(e, state) {
var player = this;
if (player.isDefaultPlayer && state.mediaType == 'Video') {
return;
}
updatePlayerState(state);
}
function releaseCurrentPlayer() {
if (currentPlayer) {
$(currentPlayer).off('.nowplayingbar');
currentPlayer.endPlayerUpdates();
currentPlayer = null;
hideNowPlayingBar();
}
}
function bindToPlayer(player) {
releaseCurrentPlayer();
currentPlayer = player;
player.getPlayerState().done(function (state) {
if (state.itemName) {
player.beginPlayerUpdates();
}
onStateChanged.call(player, null, state);
});
$(player).on('playbackstart.nowplayingbar', onPlaybackStart)
.on('playbackstop.nowplayingbar', onPlaybackStopped)
.on('volumechange.nowplayingbar', onStateChanged)
.on('playstatechange.nowplayingbar', onStateChanged)
.on('positionchange.nowplayingbar', onStateChanged);
}
$(function () {
$(MediaController).on('playerchange', function () {
bindToPlayer(MediaController.getCurrentPlayer());
});
bindToPlayer(MediaController.getCurrentPlayer());
});
})(window, document, jQuery, setTimeout, clearTimeout);

View file

@ -17,7 +17,7 @@
html += '<tbody>';
$.each(MediaPlayer.playlist, function (i, item) {
$.each(MediaController.playlist, function (i, item) {
var name = LibraryBrowser.getPosterViewDisplayName(item);
@ -65,14 +65,14 @@
var index = parseInt(this.getAttribute('data-index'));
MediaPlayer.currentPlaylistIndex(index);
MediaController.currentPlaylistIndex(index);
reloadPlaylist(page);
}).on('click', '.lnkRemove', function () {
var index = parseInt(this.getAttribute('data-index'));
MediaPlayer.removeFromPlaylist(index);
MediaController.removeFromPlaylist(index);
reloadPlaylist(page);
});
@ -80,7 +80,7 @@
var page = this;
reloadPlaylist(page);
//reloadPlaylist(page);
});

View file

@ -96,14 +96,14 @@
var id = $('#selectSession', popup).val();
ApiClient.sendSystemCommand(id, 'GoHome');
ApiClient.sendCommand(id, 'GoHome');
});
$('.btnGoToSettings', popup).on('click', function () {
var id = $('#selectSession', popup).val();
ApiClient.sendSystemCommand(id, 'GoToSettings');
ApiClient.sendCommand(id, 'GoToSettings');
});
$('.btnSendMessage', popup).on('click', function () {
@ -129,21 +129,21 @@
var id = $('#selectSession', popup).val();
ApiClient.sendSystemCommand(id, 'VolumeDown');
ApiClient.sendCommand(id, 'VolumeDown');
});
$('.btnVolumeUp', popup).on('click', function () {
var id = $('#selectSession', popup).val();
ApiClient.sendSystemCommand(id, 'VolumeUp');
ApiClient.sendCommand(id, 'VolumeUp');
});
$('.btnToggleMute', popup).on('click', function () {
var id = $('#selectSession', popup).val();
ApiClient.sendSystemCommand(id, 'ToggleMute');
ApiClient.sendCommand(id, 'ToggleMute');
});
$('.btnStop', popup).on('click', function () {
@ -432,6 +432,20 @@
ApiClient.sendPlayCommand(sessionId, remoteOptions);
}
function sendPlayStateCommand(command, options) {
var sessionId = MediaController.getPlayerInfo().id;
ApiClient.sendPlayStateCommand(sessionId, command, options);
}
function sendCommand(command, options) {
var sessionId = MediaController.getPlayerInfo().id;
ApiClient.sendCommand(sessionId, command, options);
}
function remoteControlPlayer() {
var self = this;
@ -469,19 +483,126 @@
};
self.stop = function () {
sendPlayStateCommand('stop');
};
self.nextTrack = function () {
sendPlayStateCommand('nextTrack');
};
self.previousTrack = function () {
sendPlayStateCommand('previousTrack');
};
self.seek = function (positionTicks) {
sendPlayStateCommand('seek',
{
SeekPositionTicks: positionTicks
});
};
self.pause = function () {
sendPlayStateCommand('Pause');
};
self.unpause = function () {
sendPlayStateCommand('Unpause');
};
self.mute = function () {
sendCommand('Mute');
};
self.unMute = function () {
sendCommand('Unmnute');
};
self.toggleMute = function () {
sendCommand('ToggleMute');
};
self.setVolume = function (vol) {
sendCommand('SetVolume', {
Volume: vol
});
};
self.displayContent = function (options) {
sendCommand('DisplayContent', {
ItemName: options.itemName,
ItemType: options.itemType,
ItemId: options.itemId,
Context: options.context
});
};
self.getPlayerState = function () {
var deferred = $.Deferred();
ApiClient.getSessions().done(function (sessions) {
var currentTargetId = MediaController.getPlayerInfo().id;
// Update existing data
//updateSessionInfo(popup, msg.Data);
var session = sessions.filter(function (s) {
return s.Id == currentTargetId;
})[0];
if (session) {
session = getPlayerState(session);
}
deferred.resolveWith(null, [session]);
});
return deferred.promise();
};
function subscribeToPlayerUpdates() {
if (ApiClient.isWebSocketOpen()) {
ApiClient.sendWebSocketMessage("SessionsStart", "100,700");
}
}
function unsubscribeFromPlayerUpdates() {
if (ApiClient.isWebSocketOpen()) {
ApiClient.sendWebSocketMessage("SessionsStop");
}
}
var playerListenerCount = 0;
self.beginPlayerUpdates = function () {
if (playerListenerCount <= 0) {
playerListenerCount = 0;
subscribeToPlayerUpdates();
}
playerListenerCount++;
};
self.endPlayerUpdates = function () {
playerListenerCount--;
if (playerListenerCount <= 0) {
unsubscribeFromPlayerUpdates();
playerListenerCount = 0;
}
};
self.getTargets = function () {
@ -506,7 +627,8 @@
playerName: self.name,
appName: s.Client,
playableMediaTypes: s.PlayableMediaTypes,
isLocalPlayer: false
isLocalPlayer: false,
supportedCommands: s.SupportedCommands
};
});
@ -521,11 +643,75 @@
};
}
MediaController.registerPlayer(new remoteControlPlayer());
var player = new remoteControlPlayer();
MediaController.registerPlayer(player);
function getPlayerState(session) {
var state = {
volumeLevel: session.VolumeLevel,
isMuted: session.IsMuted,
isPaused: session.IsPaused,
canSeek: session.CanSeek
};
var item = session.NowPlayingItem;
if (item) {
state.itemId = item.Id;
state.mediaType = item.MediaType;
state.itemType = item.Type;
state.indexNumber = item.IndexNumber;
state.indexNumberEnd = item.IndexNumberEnd;
state.parentIndexNumber = item.ParentIndexNumber;
state.productionYear = item.ProductionYear;
state.premiereDate = item.PremiereDate;
state.seriesName = item.SeriesName;
state.album = item.Album;
state.itemName = item.Name;
state.artists = item.Artists;
state.primaryImageItemId = item.PrimaryImageItemId;
state.primaryImageTag = item.PrimaryImageTag;
state.backdropItemId = item.BackdropItemId;
state.backdropImageTag = item.BackdropImageTag;
state.thumbItemId = item.ThumbItemId;
state.thumbImageTag = item.ThumbImageTag;
state.mediaSource = item.MediaSourceId;
state.positionTicks = session.NowPlayingPositionTicks || 0;
state.runtimeTicks = item.RunTimeTicks;
}
return state;
}
function firePlaybackEvent(name, session) {
$(player).trigger(name, [getPlayerState(session)]);
}
function onWebSocketMessageReceived(e, msg) {
if (msg.MessageType === "SessionEnded") {
if (msg.MessageType === "Sessions") {
var currentTargetId = MediaController.getPlayerInfo().id;
// Update existing data
//updateSessionInfo(popup, msg.Data);
var session = msg.Data.filter(function (s) {
return s.Id == currentTargetId;
})[0];
if (session) {
firePlaybackEvent('playstatechange', session);
}
}
else if (msg.MessageType === "SessionEnded") {
console.log("Server reports another session ended");
@ -533,6 +719,12 @@
MediaController.setDefaultPlayerActive();
}
}
else if (msg.MessageType === "PlaybackStart") {
firePlaybackEvent('playbackstart', msg.Data);
}
else if (msg.MessageType === "PlaybackStopped") {
firePlaybackEvent('playbackstop', msg.Data);
}
}
$(ApiClient).on("websocketmessage", onWebSocketMessageReceived);

View file

@ -263,6 +263,8 @@ var Dashboard = {
var html = '<span style="margin-right: 1em;">Please refresh this page to receive new updates from the server.</span>';
html += '<button type="button" data-icon="refresh" onclick="$(this).buttonEnabled(false);Dashboard.reloadPage();" data-theme="b" data-inline="true" data-mini="true">Refresh</button>';
Dashboard.showFooterNotification({ id: "dashboardVersionWarning", html: html, forceShow: true, allowHide: false });
},
@ -475,14 +477,14 @@ var Dashboard = {
Dashboard.getCurrentUser().done(function (user) {
var html = '<div data-role="panel" data-position="right" data-display="overlay" id="userFlyout" data-position-fixed="true" data-theme="a">';
var html = '<div data-role="panel" data-position="right" data-display="overlay" id="userFlyout" data-position-fixed="true" data-theme="b">';
html += '<h3>';
if (user.PrimaryImageTag) {
var imageUrl = ApiClient.getUserImageUrl(user.Id, {
width: 60,
width: 28,
tag: user.PrimaryImageTag,
type: "Primary"
@ -490,21 +492,27 @@ var Dashboard = {
html += '<img style="max-width:28px;vertical-align:middle;margin-right:5px;" src="' + imageUrl + '" />';
}
html += user.Name;
html += '</h3>';
html += '<form>';
html += '<p><label for="chkEnableThemeSongs">Play theme songs</label><input onchange="ThemeSongManager.enabled(this.checked);" type="checkbox" id="chkEnableThemeSongs" data-mini="true" /></a>';
html += '<p><a data-mini="true" data-role="button" href="useredit.html?userId=' + user.Id + '" data-icon="user">Preferences</button></a>';
html += '<p><button data-mini="true" type="button" onclick="Dashboard.logout();" data-icon="lock">Sign Out</button></p>';
html += '</form>';
html += '</div>';
$(document.body).append(html);
$('#userFlyout').panel({}).trigger('create').panel("open").on("panelafterclose", function () {
var elem = $('#userFlyout').panel({}).trigger('create').panel("open").on("panelafterclose", function () {
$(this).off("panelafterclose").remove();
});
$('#chkEnableThemeSongs', elem).checked(window.ThemeSongManager.enabled()).checkboxradio('refresh');
});
},
@ -589,7 +597,7 @@ var Dashboard = {
if (user.PrimaryImageTag) {
var url = ApiClient.getUserImageUrl(user.Id, {
width: 225,
width: 28,
tag: user.PrimaryImageTag,
type: "Primary"
});
@ -801,6 +809,16 @@ var Dashboard = {
ApiClient.openWebSocket(webSocketUrl);
},
onWebSocketOpened: function () {
ApiClient.reportCapabilities({
PlayableMediaTypes: "Audio,Video",
SupportedCommands: Dashboard.getSupportedRemoteCommands().join(',')
});
},
onWebSocketMessageReceived: function (e, data) {
var msg = data;
@ -878,10 +896,6 @@ var Dashboard = {
}
});
}
else if (msg.MessageType === "Browse") {
Dashboard.onBrowseCommand(msg.Data);
}
else if (msg.MessageType === "GeneralCommand") {
var cmd = msg.Data;
@ -892,6 +906,9 @@ var Dashboard = {
else if (cmd.Name === 'GoToSettings') {
Dashboard.navigate('dashboard.html');
}
else if (cmd.Name === 'DisplayContent') {
Dashboard.onBrowseCommand(cmd.Arguments);
}
}
else if (msg.MessageType === "MessageCommand") {
@ -1237,6 +1254,27 @@ var Dashboard = {
}
$(select).html(html).selectmenu("refresh");
},
getSupportedRemoteCommands: function () {
// Full list
// https://github.com/MediaBrowser/MediaBrowser/blob/master/MediaBrowser.Model/Session/GeneralCommand.cs
return [
"GoHome",
"GoToSettings",
"VolumeUp",
"VolumeDown",
"Mute",
"Unmute",
"ToggleMute",
"SetVolume",
"ToggleFullscreen",
"SetAudioStreamIndex",
"SetSubtitleStreamIndex",
"DisplayContent"
];
}
};
@ -1252,7 +1290,7 @@ else if (!IsStorageEnabled()) {
var ApiClient = MediaBrowser.ApiClient.create("Dashboard", window.dashboardVersion);
$(ApiClient).on("websocketmessage", Dashboard.onWebSocketMessageReceived);
$(ApiClient).on("websocketopen", Dashboard.onWebSocketOpened).on("websocketmessage", Dashboard.onWebSocketMessageReceived);
$(function () {
@ -1277,7 +1315,6 @@ $(function () {
videoPlayerHtml += '<div id="video-basic-controls">';
videoPlayerHtml += '<a id="video-playlistButton" class="mediaButton playlistButton" href="playlist.videoPlayerHtml" data-role="button" data-icon="bullets" data-iconpos="notext" data-inline="true" title="Playlist">Playlist</a>';
videoPlayerHtml += '<button id="video-previousTrackButton" class="mediaButton previousTrackButton" title="Previous Track" type="button" onclick="MediaPlayer.previousTrack();" data-icon="previous-track" data-iconpos="notext" data-inline="true">Previous Track</button>';
videoPlayerHtml += '<button id="video-playButton" class="mediaButton" title="Play" type="button" onclick="MediaPlayer.unpause();" data-icon="play" data-iconpos="notext" data-inline="true">Play</button>';
videoPlayerHtml += '<button id="video-pauseButton" class="mediaButton" title="Pause" type="button" onclick="MediaPlayer.pause();" data-icon="pause" data-iconpos="notext" data-inline="true">Pause</button>';
@ -1286,7 +1323,8 @@ $(function () {
videoPlayerHtml += '<button id="video-nextTrackButton" class="mediaButton nextTrackButton" title="Next Track" type="button" onclick="MediaPlayer.nextTrack();" data-icon="next-track" data-iconpos="notext" data-inline="true">Next Track</button>';
videoPlayerHtml += '<div class="currentTime"></div>';
videoPlayerHtml += '<div class="nowPlayingMediaInfo"></div>';
videoPlayerHtml += '<div class="nowPlayingImage"></div>';
videoPlayerHtml += '<div class="nowPlayingText"></div>';
videoPlayerHtml += '<button id="video-muteButton" class="mediaButton muteButton" title="Mute" type="button" onclick="MediaPlayer.mute();" data-icon="audio" data-iconpos="notext" data-inline="true">Mute</button>';
videoPlayerHtml += '<button id="video-unmuteButton" class="mediaButton unmuteButton" title="Unmute" type="button" onclick="MediaPlayer.unMute();" data-icon="volume-off" data-iconpos="notext" data-inline="true">Unmute</button>';
@ -1310,7 +1348,7 @@ $(function () {
videoPlayerHtml += '<button onclick="MediaPlayer.showChaptersFlyout();" id="video-chaptersButton" class="mediaButton chaptersButton" title="Scenes" type="button" data-icon="video" data-iconpos="notext" data-inline="true">Scenes</button>';
videoPlayerHtml += '<div class="mediaFlyoutContainer"><div id="video-chaptersFlyout" style="display:none;" class="mediaPlayerFlyout chaptersFlyout"></div></div>';
videoPlayerHtml += '<button onclick="MediaPlayer.toggleFullscreen();" id="video-fullscreenButton" class="mediaButton fullscreenButton" title="Fullscreen" type="button" data-icon="action" data-iconpos="notext" data-inline="true">Fullscreen</button>';
videoPlayerHtml += '<button onclick="MediaPlayer.toggleFullscreen();" id="video-fullscreenButton" class="mediaButton fullscreenButton" title="Fullscreen" type="button" data-icon="expand" data-iconpos="notext" data-inline="true">Fullscreen</button>';
videoPlayerHtml += '</div>'; // video-advanced-controls
@ -1326,48 +1364,6 @@ $(function () {
mediaPlayerElem.trigger('create');
var footerHtml = '<div id="footer" data-theme="b" class="ui-bar-b">';
footerHtml += '<div id="nowPlayingBar" class="nowPlayingBar" style="display:none;">';
footerHtml += '<div class="barBackground ui-bar-b"></div>';
footerHtml += '<div style="display:inline-block;width:12px;"></div>';
footerHtml += '<a id="playlistButton" class="mediaButton playlistButton" href="playlist.html" data-role="button" data-icon="bullets" data-iconpos="notext" data-inline="true" title="Playlist">Playlist</a>';
footerHtml += '<button id="previousTrackButton" class="mediaButton previousTrackButton" title="Previous Track" type="button" onclick="MediaPlayer.previousTrack();" data-icon="previous-track" data-iconpos="notext" data-inline="true">Previous Track</button>';
footerHtml += '<button id="playButton" class="mediaButton" title="Play" type="button" onclick="MediaPlayer.unpause();" data-icon="play" data-iconpos="notext" data-inline="true">Play</button>';
footerHtml += '<button id="pauseButton" class="mediaButton" title="Pause" type="button" onclick="MediaPlayer.pause();" data-icon="pause" data-iconpos="notext" data-inline="true">Pause</button>';
footerHtml += '<div id="mediaElement"></div>';
footerHtml += '<button id="stopButton" class="mediaButton" title="Stop" type="button" onclick="MediaPlayer.stop();" data-icon="stop" data-iconpos="notext" data-inline="true">Stop</button>';
footerHtml += '<button id="nextTrackButton" class="mediaButton nextTrackButton" title="Next Track" type="button" onclick="MediaPlayer.nextTrack();" data-icon="next-track" data-iconpos="notext" data-inline="true">Next Track</button>';
footerHtml += '<div class="positionSliderContainer sliderContainer">';
footerHtml += '<input type="range" class="mediaSlider positionSlider slider" step=".001" min="0" max="100" value="0" style="display:none;" data-mini="true" data-theme="a" data-highlight="true" />';
footerHtml += '</div>';
footerHtml += '<div class="currentTime"></div>';
footerHtml += '<div class="nowPlayingMediaInfo"></div>';
footerHtml += '<button id="muteButton" class="mediaButton muteButton" title="Mute" type="button" onclick="MediaPlayer.mute();" data-icon="audio" data-iconpos="notext" data-inline="true">Mute</button>';
footerHtml += '<button id="unmuteButton" class="mediaButton unmuteButton" title="Unmute" type="button" onclick="MediaPlayer.unMute();" data-icon="volume-off" data-iconpos="notext" data-inline="true">Unmute</button>';
footerHtml += '<div class="volumeSliderContainer sliderContainer">';
footerHtml += '<input type="range" class="mediaSlider volumeSlider slider" step=".05" min="0" max="1" value="0" style="display:none;" data-mini="true" data-theme="a" data-highlight="true" />';
footerHtml += '</div>';
footerHtml += '<button onclick="MediaPlayer.showQualityFlyout();" id="qualityButton" class="mediaButton qualityButton" title="Quality" type="button" data-icon="gear" data-iconpos="notext" data-inline="true">Quality</button>';
footerHtml += '<div class="mediaFlyoutContainer"><div id="qualityFlyout" style="display:none;" class="mediaPlayerFlyout"></div></div>';
footerHtml += '<button onclick="MediaPlayer.showAudioTracksFlyout();" id="audioTracksButton" class="imageButton mediaButton audioTracksButton" title="Audio tracks" type="button" data-icon="audiocd" data-iconpos="notext" data-inline="true">Audio Tracks</button>';
footerHtml += '<div class="mediaFlyoutContainer"><div id="audioTracksFlyout" style="display:none;" class="mediaPlayerFlyout audioTracksFlyout"></div></div>';
footerHtml += '<button onclick="MediaPlayer.showSubtitleMenu();" id="subtitleButton" class="imageButton mediaButton subtitleButton" title="Subtitles" type="button" data-icon="subtitles" data-iconpos="notext" data-inline="true">Subtitles</button>';
footerHtml += '<div class="mediaFlyoutContainer"><div id="subtitleFlyout" style="display:none;" class="mediaPlayerFlyout subtitleFlyout"></div></div>';
footerHtml += '<button onclick="MediaPlayer.showChaptersFlyout();" id="chaptersButton" class="mediaButton chaptersButton" title="Scenes" type="button" data-icon="video" data-iconpos="notext" data-inline="true">Scenes</button>';
footerHtml += '<div class="mediaFlyoutContainer"><div id="chaptersFlyout" style="display:none;" class="mediaPlayerFlyout chaptersFlyout"></div></div>';
footerHtml += '<button onclick="MediaPlayer.toggleFullscreen();" id="fullscreenButton" class="mediaButton fullscreenButton" title="Fullscreen" type="button" data-icon="action" data-iconpos="notext" data-inline="true">Fullscreen</button>';
footerHtml += '</div>';
footerHtml += '<div id="footerNotifications"></div>';
footerHtml += '</div>';
@ -1427,5 +1423,4 @@ $(document).on('pagebeforeshow', ".page", function () {
if (!ApiClient.isWebSocketOpen()) {
Dashboard.refreshSystemInfoFromServer();
}
});
});

View file

@ -50,6 +50,7 @@
html += LibraryBrowser.getSongTableHtml(result.Items, {
showAlbum: true,
showArtist: true,
showAlbumArtist: true,
enableColumnSorting: true,
sortBy: query.SortBy,
sortOrder: query.SortOrder

View file

@ -1,29 +1,11 @@
var SupporterPage = {
(function () {
onPageShow: function () {
SupporterPage.load();
},
$(document).on('pageshow', "#supporterPage", function () {
onPageHide: function () {
var page = this;
$('#paypalReturnUrl', page).val(ApiClient.getUrl("supporterkey.html"));
},
});
load: function() {
Dashboard.showLoadingMsg();
var page = $.mobile.activePage;
ApiClient.getPluginSecurityInfo().done(function (info) {
$('#txtSupporterKey', page).val(info.SupporterKey);
if (info.IsMBSupporter) {
$('.supporterOnly', page).show();
} else {
$('.supporterOnly', page).hide();
}
$('#paypalReturnUrl', page).val(ApiClient.getUrl("supporterkey.html"));
Dashboard.hideLoadingMsg();
});
}
};
$(document).on('pageshow', "#supporterPage", SupporterPage.onPageShow)
.on('pagehide', "#supporterPage", SupporterPage.onPageHide);
})();

View file

@ -0,0 +1,82 @@
(function (document, $, localStorage) {
var currentOwnerId;
var currentThemeIds = [];
function playThemeSongs(items, ownerId) {
var player = getPlayer();
if (items.length && player.isDefaultPlayer && player.canAutoPlayAudio()) {
// Stop if a theme song from another ownerId
// Leave it alone if anything else (e.g user playing a movie)
if (!currentOwnerId && player.isPlaying()) {
return;
}
currentThemeIds = items.map(function (i) {
return i.Id;
});
currentOwnerId = ownerId;
player.play({
items: items
});
} else {
currentOwnerId = null;
}
}
function onPlayItem(item) {
// User played something manually
if (currentThemeIds.indexOf(item.Id) == -1) {
currentOwnerId = null;
}
}
function enabled(isEnabled) {
var userId = Dashboard.getCurrentUserId();
var key = userId + '-themesongs';
if (isEnabled == null) {
return localStorage.getItem(key) == '1';
}
var val = isEnabled ? '1' : '0';
localStorage.setItem(key, val);
}
function getPlayer() {
return MediaController.getCurrentPlayer();
}
$(document).on('thememediadownload', ".libraryPage", function (e, themeMediaResult) {
if (!enabled()) {
return;
}
var ownerId = themeMediaResult.ThemeSongsResult.OwnerId;
if (ownerId != currentOwnerId) {
playThemeSongs(themeMediaResult.ThemeSongsResult.Items, ownerId);
}
});
window.ThemeSongManager = {
enabled: function (isEnabled) {
return enabled(isEnabled);
}
};
})(document, jQuery, window.localStorage);

View file

@ -34,7 +34,8 @@
context: 'tv',
showTitle: true,
showItemCounts: true,
coverImage: true
coverImage: true,
lazy: true
});
html += LibraryBrowser.getPagingHtml(query, result.TotalRecordCount, false, [], false);

View file

@ -34,7 +34,8 @@
items: result.Items,
shape: "backdrop",
preferThumb: true,
context: 'tv'
context: 'tv',
lazy: true
});
$('.itemsContainer', page).removeClass('timelineItemsContainer');
@ -45,7 +46,8 @@
items: result.Items,
shape: "banner",
preferBanner: true,
context: 'tv'
context: 'tv',
lazy: true
});
$('.itemsContainer', page).removeClass('timelineItemsContainer');
}
@ -56,7 +58,8 @@
shape: "portrait",
context: 'tv',
showTitle: true,
centerText: true
centerText: true,
lazy: true
});
$('.itemsContainer', page).removeClass('timelineItemsContainer');
}
@ -67,7 +70,8 @@
shape: "portrait",
context: 'tv',
timeline: true,
showTitle: true
showTitle: true,
lazy: true
});
$('.itemsContainer', page).addClass('timelineItemsContainer');

View file

@ -17,7 +17,7 @@
if (user.PrimaryImageTag) {
var imageUrl = ApiClient.getUserImageUrl(user.Id, {
height: 450,
height: 200,
tag: user.PrimaryImageTag,
type: "Primary"
});

View file

@ -27,7 +27,7 @@
if (user.PrimaryImageTag) {
var url = ApiClient.getUserImageUrl(user.Id, {
width: 225,
width: 80,
tag: user.PrimaryImageTag,
type: "Primary"
});

View file

@ -1,13 +1,29 @@
(function ($, window, document) {
function populateLanguages(select, languages) {
var html = "";
html += "<option value=''></option>";
for (var i = 0, length = languages.length; i < length; i++) {
var culture = languages[i];
html += "<option value='" + culture.ThreeLetterISOLanguageName + "'>" + culture.DisplayName + "</option>";
}
$(select).html(html).selectmenu("refresh");
}
function loadUser(page, user, loggedInUser, allCulturesPromise) {
Dashboard.setPageTitle(user.Name);
allCulturesPromise.done(function (allCultures) {
Dashboard.populateLanguages($('#selectAudioLanguage', page), allCultures);
Dashboard.populateLanguages($('#selectSubtitleLanguage', page), allCultures);
populateLanguages($('#selectAudioLanguage', page), allCultures);
populateLanguages($('#selectSubtitleLanguage', page), allCultures);
$('#selectAudioLanguage', page).val(user.Configuration.AudioLanguagePreference || "").selectmenu("refresh");
$('#selectSubtitleLanguage', page).val(user.Configuration.SubtitleLanguagePreference || "").selectmenu("refresh");

View file

@ -16,23 +16,14 @@
<a href="supporterkey.html" data-role="button">${TabSupporterKey}</a>
<a href="about.html" data-role="button">${TabAbout}</a>
</div>
<h3>Support the Media Browser Team</h3>
<p>
Help ensure the continued development of this product by donating a minimum of $10 (greater amounts greatly appreciated). A portion of all donations will be contributed to other <a href="about.html">free tools</a> we depend on.
</p>
<h3>${HeaderSupportTheTeam}</h3>
<p>${HeaderSupportTheTeamHelp}</p>
<p style="display: none; padding: 1em; border-radius: 5px; font-weight: normal;" class="ui-bar-a supporterOnly">
<strong>Thank You</strong> for your past support of the Media Browser Team. Users like you make it possible for
Media Browser to exist and keep getting better and better. You can always support us again if you feel you are getting maximum
value from the product.
</p>
<br />
<form name="_xclick" action="https://www.paypal.com/cgi-bin/webscr"
method="post">
<label for="donateAmt">Amount (USD)</label>
<label for="donateAmt">${LabelSupportAmount}</label>
<select id="donateAmt" name="amount">
<option value="10">$10</option>
<option value="15" selected="selected">$15</option>
<option value="20">$20</option>
<option value="30">$30</option>
@ -46,10 +37,11 @@
<input type="hidden" name="item_number" value="MBSupporter">
<input type="hidden" name="notify_url" value="http://mb3admin.com/admin/service/services/ppipn.php">
<input type="hidden" name="return" id="paypalReturnUrl" value="#">
<a data-role="button" onclick="$(this).parents('form')[0].submit();">
<a data-role="button" data-icon="arrow-r" data-iconpos="right" onclick="$(this).parents('form')[0].submit();">
<img src="css/images/supporter/donatepaypal.png" /></a>
</form>
<p>Once complete, please return and <a href="supporterkey.html">enter your supporter key</a>, which you will receive by email.</p>
<p>${DonationNextStep}</p>
<p><a href="supporterkey.html">Enter supporter key</a></p>
</div>
</div>
</div>

View file

@ -0,0 +1,62 @@
/**
* jQuery Unveil
* A very lightweight jQuery plugin to lazy load images
* http://luis-almeida.github.com/unveil
*
* Licensed under the MIT license.
* Copyright 2013 Luís Almeida
* https://github.com/luis-almeida
*/
; (function ($) {
$.fn.unveil = function (threshold, callback) {
var $w = $(window),
th = threshold || 0,
retina = window.devicePixelRatio > 1,
attrib = retina ? "data-src-retina" : "data-src",
images = this,
loaded;
this.one("unveil", function () {
var elemType = $(this).get(0).tagName;
var source = this.getAttribute(attrib);
source = source || this.getAttribute("data-src");
if (source) {
if (elemType === "DIV") {
this.style.backgroundImage = "url('" + source + "')";
} else {
this.setAttribute("src", source);
}
if (typeof callback === "function") callback.call(this);
}
});
function unveil() {
var inview = images.filter(function () {
var $e = $(this);
if ($e.is(":hidden")) return;
var wt = $w.scrollTop(),
wb = wt + $w.height(),
et = $e.offset().top,
eb = et + $e.height();
return eb >= wt - th && et <= wb + th;
});
loaded = inview.trigger("unveil");
images = images.not(loaded);
}
$w.scroll(unveil);
$w.resize(unveil);
unveil();
return this;
};
})(window.jQuery || window.Zepto);

View file

@ -1728,6 +1728,16 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, wi
});
};
self.reportCapabilities = function (options) {
var url = self.getUrl("Sessions/Capabilities", options);
return self.ajax({
type: "POST",
url: url
});
};
self.updateItemImageIndex = function (itemId, itemType, itemName, imageType, imageIndex, newIndex) {
if (!imageType) {
@ -2198,6 +2208,28 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, wi
});
};
function normalizeImageOptions(options) {
var ratio = window.devicePixelRatio;
if (ratio) {
if (options.width) {
options.width = options.width * ratio;
}
if (options.height) {
options.height = options.height * ratio;
}
if (options.maxWidth) {
options.maxWidth = options.maxWidth * ratio;
}
if (options.maxHeight) {
options.maxHeight = options.maxHeight * ratio;
}
}
}
/**
* Constructs a url for a user image
* @param {String} userId
@ -2230,6 +2262,8 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, wi
delete options.type;
delete options.index;
normalizeImageOptions(options);
return self.getUrl(url, options);
};
@ -2265,215 +2299,7 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, wi
delete options.type;
delete options.index;
return self.getUrl(url, options);
};
/**
* Constructs a url for a year image
* @param {String} year
* @param {Object} options
* Options supports the following properties:
* width - download the image at a fixed width
* height - download the image at a fixed height
* maxWidth - download the image at a maxWidth
* maxHeight - download the image at a maxHeight
* quality - A scale of 0-100. This should almost always be omitted as the default will suffice.
* For best results do not specify both width and height together, as aspect ratio might be altered.
*/
self.getYearImageUrl = function (year, options) {
if (!year) {
throw new Error("null year");
}
options = options || {
};
var url = "Years/" + year + "/Images/" + options.type;
if (options.index != null) {
url += "/" + options.index;
}
// Don't put these on the query string
delete options.type;
delete options.index;
return self.getUrl(url, options);
};
/**
* Constructs a url for a genre image
* @param {String} name
* @param {Object} options
* Options supports the following properties:
* width - download the image at a fixed width
* height - download the image at a fixed height
* maxWidth - download the image at a maxWidth
* maxHeight - download the image at a maxHeight
* quality - A scale of 0-100. This should almost always be omitted as the default will suffice.
* For best results do not specify both width and height together, as aspect ratio might be altered.
*/
self.getGenreImageUrl = function (name, options) {
if (!name) {
throw new Error("null name");
}
options = options || {
};
var url = "Genres/" + self.encodeName(name) + "/Images/" + options.type;
if (options.index != null) {
url += "/" + options.index;
}
// Don't put these on the query string
delete options.type;
delete options.index;
return self.getUrl(url, options);
};
/**
* Constructs a url for a genre image
* @param {String} name
* @param {Object} options
* Options supports the following properties:
* width - download the image at a fixed width
* height - download the image at a fixed height
* maxWidth - download the image at a maxWidth
* maxHeight - download the image at a maxHeight
* quality - A scale of 0-100. This should almost always be omitted as the default will suffice.
* For best results do not specify both width and height together, as aspect ratio might be altered.
*/
self.getMusicGenreImageUrl = function (name, options) {
if (!name) {
throw new Error("null name");
}
options = options || {
};
var url = "MusicGenres/" + self.encodeName(name) + "/Images/" + options.type;
if (options.index != null) {
url += "/" + options.index;
}
// Don't put these on the query string
delete options.type;
delete options.index;
return self.getUrl(url, options);
};
/**
* Constructs a url for a genre image
* @param {String} name
* @param {Object} options
* Options supports the following properties:
* width - download the image at a fixed width
* height - download the image at a fixed height
* maxWidth - download the image at a maxWidth
* maxHeight - download the image at a maxHeight
* quality - A scale of 0-100. This should almost always be omitted as the default will suffice.
* For best results do not specify both width and height together, as aspect ratio might be altered.
*/
self.getGameGenreImageUrl = function (name, options) {
if (!name) {
throw new Error("null name");
}
options = options || {
};
var url = "GameGenres/" + self.encodeName(name) + "/Images/" + options.type;
if (options.index != null) {
url += "/" + options.index;
}
// Don't put these on the query string
delete options.type;
delete options.index;
return self.getUrl(url, options);
};
/**
* Constructs a url for a artist image
* @param {String} name
* @param {Object} options
* Options supports the following properties:
* width - download the image at a fixed width
* height - download the image at a fixed height
* maxWidth - download the image at a maxWidth
* maxHeight - download the image at a maxHeight
* quality - A scale of 0-100. This should almost always be omitted as the default will suffice.
* For best results do not specify both width and height together, as aspect ratio might be altered.
*/
self.getArtistImageUrl = function (name, options) {
if (!name) {
throw new Error("null name");
}
options = options || {
};
var url = "Artists/" + self.encodeName(name) + "/Images/" + options.type;
if (options.index != null) {
url += "/" + options.index;
}
// Don't put these on the query string
delete options.type;
delete options.index;
return self.getUrl(url, options);
};
/**
* Constructs a url for a studio image
* @param {String} name
* @param {Object} options
* Options supports the following properties:
* width - download the image at a fixed width
* height - download the image at a fixed height
* maxWidth - download the image at a maxWidth
* maxHeight - download the image at a maxHeight
* quality - A scale of 0-100. This should almost always be omitted as the default will suffice.
* For best results do not specify both width and height together, as aspect ratio might be altered.
*/
self.getStudioImageUrl = function (name, options) {
if (!name) {
throw new Error("null name");
}
options = options || {
};
var url = "Studios/" + self.encodeName(name) + "/Images/" + options.type;
if (options.index != null) {
url += "/" + options.index;
}
// Don't put these on the query string
delete options.type;
delete options.index;
normalizeImageOptions(options);
return self.getUrl(url, options);
};
@ -2498,9 +2324,7 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, wi
throw new Error("itemId cannot be empty");
}
options = options || {
};
options = options || {};
var url = "Items/" + itemId + "/Images/" + options.type;
@ -3183,10 +3007,7 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, wi
});
};
/**
* Gets theme songs for an item
*/
self.getThemeSongs = function (userId, itemId) {
self.getThemeMedia = function (userId, itemId, inherit) {
if (!itemId) {
throw new Error("null itemId");
@ -3198,28 +3019,9 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, wi
options.userId = userId;
}
var url = self.getUrl("Items/" + itemId + "/ThemeSongs", options);
options.InheritFromParent = inherit || false;
return self.ajax({
type: "GET",
url: url,
dataType: "json"
});
};
self.getThemeVideos = function (userId, itemId) {
if (!itemId) {
throw new Error("null itemId");
}
var options = {};
if (userId) {
options.userId = userId;
}
var url = self.getUrl("Items/" + itemId + "/ThemeVideos", options);
var url = self.getUrl("Items/" + itemId + "/ThemeMedia", options);
return self.ajax({
type: "GET",
@ -3944,24 +3746,6 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, wi
});
};
self.sendBrowseCommand = function (sessionId, options) {
if (!sessionId) {
throw new Error("null sessionId");
}
if (!options) {
throw new Error("null options");
}
var url = self.getUrl("Sessions/" + sessionId + "/Viewing", options);
return self.ajax({
type: "POST",
url: url
});
};
self.sendPlayCommand = function (sessionId, options) {
if (!sessionId) {
@ -3980,7 +3764,7 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, wi
});
};
self.sendSystemCommand = function (sessionId, command) {
self.sendCommand = function (sessionId, command, options) {
if (!sessionId) {
throw new Error("null sessionId");
@ -3990,12 +3774,22 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, wi
throw new Error("null command");
}
var url = self.getUrl("Sessions/" + sessionId + "/System/" + command);
var url = self.getUrl("Sessions/" + sessionId + "/Command");
return self.ajax({
var ajaxOptions = {
type: "POST",
url: url
});
};
options = {
Arguments: options || {},
Name: command
};
ajaxOptions.data = JSON.stringify(options);
ajaxOptions.contentType = "application/json";
return self.ajax(ajaxOptions);
};
self.sendMessageCommand = function (sessionId, options) {